-- MSUF_Options_Colors.lua
-- Options panel for color settings (pure UX / UI).
-- All runtime Get/Set/Reset logic lives in MSUF_ColorsCore.lua
-- which loads first and exports via ns._colorsAPI.

local addonName, ns = ...
ns = ns or {}

------------------------------------------------------
-- Import core API (aliased to the same local names
-- the original monolithic file used, so zero changes
-- are needed in the panel builder body below).
------------------------------------------------------
local _API = ns._colorsAPI or {}

local PushVisualUpdates               = _API.PushVisualUpdates

local GetGlobalFontColor              = _API.GetGlobalFontColor
local SetGlobalFontColor              = _API.SetGlobalFontColor

local GetCastbarTextColor             = _API.GetCastbarTextColor
local SetCastbarTextColor             = _API.SetCastbarTextColor

local GetCastbarBorderColor           = _API.GetCastbarBorderColor
local SetCastbarBorderColor           = _API.SetCastbarBorderColor

-- NOTE: Castbar background + all Reset* functions are pulled from ns._colorsAPI
-- inside the panel builder to stay within Lua 5.1's 60-upvalue ceiling.

local GetInterruptibleCastColor       = _API.GetInterruptibleCastColor
local SetInterruptibleCastColor       = _API.SetInterruptibleCastColor
local GetNonInterruptibleCastColor    = _API.GetNonInterruptibleCastColor
local SetNonInterruptibleCastColor    = _API.SetNonInterruptibleCastColor
local GetInterruptFeedbackCastColor   = _API.GetInterruptFeedbackCastColor
local SetInterruptFeedbackCastColor   = _API.SetInterruptFeedbackCastColor

local GetPlayerCastbarOverrideEnabled = _API.GetPlayerCastbarOverrideEnabled
local SetPlayerCastbarOverrideEnabled = _API.SetPlayerCastbarOverrideEnabled
local GetPlayerCastbarOverrideMode    = _API.GetPlayerCastbarOverrideMode
local SetPlayerCastbarOverrideMode    = _API.SetPlayerCastbarOverrideMode
local GetPlayerCastbarOverrideColor   = _API.GetPlayerCastbarOverrideColor
local SetPlayerCastbarOverrideColor   = _API.SetPlayerCastbarOverrideColor

local CLASS_TOKENS                    = _API.CLASS_TOKENS
local GetClassColor                   = _API.GetClassColor
local SetClassColor                   = _API.SetClassColor

local GetClassBarBgColor              = _API.GetClassBarBgColor
local SetClassBarBgColor              = _API.SetClassBarBgColor

local GetBarBgMatchHP                 = _API.GetBarBgMatchHP
local SetBarBgMatchHP                 = _API.SetBarBgMatchHP

local GetNPCColor                     = _API.GetNPCColor
local SetNPCColor                     = _API.SetNPCColor

local GetPetFrameColor                = _API.GetPetFrameColor
local SetPetFrameColor                = _API.SetPetFrameColor

local GetAbsorbOverlayColor           = _API.GetAbsorbOverlayColor
local SetAbsorbOverlayColor           = _API.SetAbsorbOverlayColor
local GetHealAbsorbOverlayColor       = _API.GetHealAbsorbOverlayColor
local SetHealAbsorbOverlayColor       = _API.SetHealAbsorbOverlayColor

local GetPowerBarBackgroundColor      = _API.GetPowerBarBackgroundColor
local SetPowerBarBackgroundColor      = _API.SetPowerBarBackgroundColor

local GetAggroBorderColor             = _API.GetAggroBorderColor
local SetAggroBorderColor             = _API.SetAggroBorderColor

local GetPowerBarBackgroundMatchHP    = _API.GetPowerBarBackgroundMatchHP
local SetPowerBarBackgroundMatchHP    = _API.SetPowerBarBackgroundMatchHP

_API = nil  -- not needed after alias init; avoid accidental upvalue capture

------------------------------------------------------
-- Local shortcuts (UI framework)
------------------------------------------------------
local CreateFrame                  = CreateFrame
local Settings                     = Settings
local ColorPickerFrame             = ColorPickerFrame
local InterfaceOptions_AddCategory = InterfaceOptions_AddCategory

local UIDropDownMenu_CreateInfo      = UIDropDownMenu_CreateInfo
local UIDropDownMenu_SetWidth       = UIDropDownMenu_SetWidth
local UIDropDownMenu_Initialize     = UIDropDownMenu_Initialize
local UIDropDownMenu_SetSelectedValue = UIDropDownMenu_SetSelectedValue
local UIDropDownMenu_AddButton      = UIDropDownMenu_AddButton

local EnsureDB                     = _G.EnsureDB
local RAID_CLASS_COLORS            = RAID_CLASS_COLORS
local C_Timer                      = C_Timer

local function MSUF_ExpandDropdownClickArea(dropdown)
    if not dropdown or dropdown._msufClickAreaExpanded then return end

    local btn = dropdown.Button
    if not btn and dropdown.GetName then
        local nm = dropdown:GetName()
        if nm then btn = _G[nm .. "Button"] end
    end
    if not btn or not btn.SetHitRectInsets then return end

    btn:SetHitRectInsets(-260, 0, -8, -8)
    dropdown._msufClickAreaExpanded = true
end

local function MSUF_ConfirmColorReset(label, doReset)
    if type(doReset) ~= "function" then return end

    local KEY = "MSUF_CONFIRM_COLOR_RESET"
    _G.MSUF__ColorResetConfirm = _G.MSUF__ColorResetConfirm or {}
    local st = _G.MSUF__ColorResetConfirm
    st.fn = doReset

    if not StaticPopupDialogs[KEY] then
        StaticPopupDialogs[KEY] = {
            text = "",
            button1 = OKAY,
            button2 = CANCEL,
            OnAccept = function()
                local state = _G.MSUF__ColorResetConfirm
                local fn = state and state.fn
                if fn then
                    state.fn = nil
                    fn()
                end
            end,
            timeout = 0,
            whileDead = 1,
            hideOnEscape = 1,
            preferredIndex = 3,
        }
    end

    StaticPopupDialogs[KEY].text = "Reset " .. tostring(label) .. " color settings?\n\nThis cannot be undone."
    StaticPopup_Show(KEY)
end

local function MSUF_ShowBarModeReloadPopup(label)
    if InCombatLockdown and InCombatLockdown() then
        if type(MSUF_Print) == "function" then
            MSUF_Print("Reload recommended (cannot show popup in combat).")
        else
            print("|cffffaa00MSUF:|r Reload recommended (cannot show popup in combat).")
        end
        return
    end

    local KEY = "MSUF_RELOAD_BAR_MODE"
    local reason = tostring(label or "these changes")

    if not StaticPopupDialogs[KEY] then
        StaticPopupDialogs[KEY] = {
            text = "MSUF recommends reloading the UI to ensure the selected bar mode applies everywhere.\n\nApply: %s\n\nReload now?",
            button1 = RELOADUI,
            button2 = LATER or CANCEL,
            OnAccept = function()
                if type(ReloadUI) == "function" then ReloadUI() end
            end,
            timeout = 0,
            whileDead = 1,
            hideOnEscape = 1,
            preferredIndex = 3,
        }
    end

    StaticPopup_Show(KEY, reason)
end

-- Helper: ColorPicker wrapper
------------------------------------------------------
local function OpenColorPicker(initialR, initialG, initialB, callback)
    if not ColorPickerFrame or type(callback) ~= "function" then return end

    -- Snapshot the color as it was BEFORE opening the picker.
    -- We use this for proper Cancel behavior (revert live swatch changes).
    local startR = tonumber(initialR) or 1
    local startG = tonumber(initialG) or 1
    local startB = tonumber(initialB) or 1

    if ColorPickerFrame.SetupColorPickerAndShow then
        -- modern API
        local info = {
            r          = startR,
            g          = startG,
            b          = startB,
            opacity    = 1,
            hasOpacity = false,

            -- Called when the user changes the color (live preview).
            swatchFunc = function()
                local r, g, b = ColorPickerFrame:GetColorRGB()
                callback(r, g, b)
            end,

            -- Called when the user presses Cancel.
            cancelFunc = function(previousValues)
                if type(previousValues) == "table" then
                    callback(previousValues.r or startR, previousValues.g or startG, previousValues.b or startB)
                else
                    callback(startR, startG, startB)
                end
            end,
        }

        -- Some builds use previousValues for Cancel; harmless if ignored.
        info.previousValues = { r = startR, g = startG, b = startB, opacity = 1 }

        ColorPickerFrame:SetupColorPickerAndShow(info)
    else
        -- fallback
        local function OnColorChanged()
            local r, g, b = ColorPickerFrame:GetColorRGB()
            callback(r, g, b)
        end

        ColorPickerFrame.func        = OnColorChanged
        ColorPickerFrame.cancelFunc  = function(previousValues)
            if type(previousValues) == "table" then
                callback(previousValues.r or startR, previousValues.g or startG, previousValues.b or startB)
            else
                callback(startR, startG, startB)
            end
        end
        ColorPickerFrame.previousValues = { r = startR, g = startG, b = startB }

        ColorPickerFrame.hasOpacity  = false
        ColorPickerFrame:SetColorRGB(startR, startG, startB)
        ColorPickerFrame:Show()
    end
end

-- Public: register Colors options panel (with scrolling)
------------------------------------------------------
function ns.MSUF_RegisterColorsOptions_Full(parentCategory)
    --------------------------------------------------
    -- Root panel & scroll container
    --------------------------------------------------
    local panel = (_G.MSUF_ColorsPanel) or CreateFrame("Frame", "MSUF_ColorsPanel", UIParent)
    panel.name = "Colors"

    if panel.__MSUF_ColorsBuilt then
        return panel
    end

    -- Pulled inside the function body (not file-scope) to stay under the 60-upvalue ceiling.
    local _api = ns._colorsAPI or {}
    local GetCastbarBackgroundColor   = _api.GetCastbarBackgroundColor
    local SetCastbarBackgroundColor   = _api.SetCastbarBackgroundColor
    local ResetCastbarBackgroundColor = _api.ResetCastbarBackgroundColor
    local ResetGlobalFontToPalette    = _api.ResetGlobalFontToPalette
    local ResetCastbarTextColorToGlobal = _api.ResetCastbarTextColorToGlobal
    local ResetCastbarBorderColor     = _api.ResetCastbarBorderColor
    local ResetAllClassColors         = _api.ResetAllClassColors
    local ResetClassBarBgColor        = _api.ResetClassBarBgColor
    local ResetAllNPCColors           = _api.ResetAllNPCColors
    local GetNPCColorMode             = _api.GetNPCColorMode
    local SetNPCColorMode             = _api.SetNPCColorMode
    local GetNPCTypeColorBar          = _api.GetNPCTypeColorBar
    local SetNPCTypeColorBar          = _api.SetNPCTypeColorBar
    local GetNPCTypeColorText         = _api.GetNPCTypeColorText
    local SetNPCTypeColorText         = _api.SetNPCTypeColorText
    local ResetNPCTypeColors          = _api.ResetNPCTypeColors
    local NPC_TYPE_UNITS              = _api.NPC_TYPE_UNITS
    local GetNPCTypePerUnit           = _api.GetNPCTypePerUnit
    local SetNPCTypePerUnit           = _api.SetNPCTypePerUnit

    local scrollFrame = CreateFrame("ScrollFrame", "MSUF_ColorsScrollFrame", panel, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", panel, "TOPLEFT", 0, 0)
    scrollFrame:SetPoint("BOTTOMRIGHT", panel, "BOTTOMRIGHT", -30, 0)

    local content = CreateFrame("Frame", "MSUF_ColorsScrollChild", scrollFrame)
    content:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
    content:SetWidth(640)
    content:SetHeight(600)

    scrollFrame:SetScrollChild(content)

    -- Func table to avoid 200-local limit (store helper funcs + persistent UI refs as fields, not locals)
    local F = panel.__MSUF_ColorsFuncs
    if not F then
        F = {}
        panel.__MSUF_ColorsFuncs = F
    end

    local S = panel.__MSUF_ColorsState
    if not S then
        S = {
            classSwatches = {}, -- token -> texture
            classLabels = {},   -- token -> FontString
            barAppearanceRefreshing = false,
        }
        panel.__MSUF_ColorsState = S
    else
        S.classSwatches = S.classSwatches or {}
        S.classLabels = S.classLabels or {}
        if S.barAppearanceRefreshing == nil then
            S.barAppearanceRefreshing = false
        end
    end

    --------------------------------------------------
    -- Helper: section divider (like Gameplay tab)
    --------------------------------------------------
    F.CreateHeaderDividerAbove = function(header)
        local line = content:CreateTexture(nil, "ARTWORK")
        line:SetColorTexture(1, 1, 1, 0.15)
        line:SetHeight(1)
        line:SetPoint("BOTTOMLEFT", header, "TOPLEFT", 0, 8)
        line:SetPoint("RIGHT", content, "RIGHT", -16, 0)
        return line
    end

    --------------------------------------------------
    -- Collapsible section helper (accordion UX)
    --------------------------------------------------
    local SECTION_W = 700
    local SECTION_COLLAPSED_H = 28
    local TEX_W8 = "Interface\\Buttons\\WHITE8x8"
    local math_pi = math.pi

    -- Section tracking for accordion + auto-open
    S._allSections = S._allSections or {}
    local function CollapseAllExcept(keepBox)
        for i = 1, #S._allSections do
            local b = S._allSections[i]
            if b and b ~= keepBox and not b._msufCollapsed then
                b._msufCollapsed = true
                if b._msufApplyCollapseState then b._msufApplyCollapseState() end
            end
        end
    end

    F.MakeCollapsibleSection = function(parent, expandedH, titleText, defaultOpen)
        local box = CreateFrame("Frame", nil, parent, "BackdropTemplate")
        box:SetSize(SECTION_W, defaultOpen and expandedH or SECTION_COLLAPSED_H)
        box:SetBackdrop({
            bgFile = TEX_W8, edgeFile = TEX_W8, edgeSize = 1,
            insets = { left = 1, right = 1, top = 1, bottom = 1 },
        })
        box:SetBackdropColor(0, 0, 0, 0.25)
        box:SetBackdropBorderColor(0.35, 0.35, 0.35, 0.9)
        box._msufExpandedH = expandedH
        box._msufCollapsedH = SECTION_COLLAPSED_H
        box._msufCollapsed = not defaultOpen

        local hdr = CreateFrame("Button", nil, box)
        hdr:SetHeight(24)
        hdr:SetPoint("TOPLEFT", box, "TOPLEFT", 0, 0)
        hdr:SetPoint("TOPRIGHT", box, "TOPRIGHT", 0, 0)

        local chevron = hdr:CreateTexture(nil, "OVERLAY")
        chevron:SetSize(12, 12)
        chevron:SetPoint("LEFT", hdr, "LEFT", 12, 0)
        chevron:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
        MSUF_ApplyCollapseVisual(chevron, nil, defaultOpen)

        local title = hdr:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        title:SetPoint("LEFT", chevron, "RIGHT", 6, 0)
        title:SetText(titleText)

        local hint = hdr:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
        hint:SetPoint("RIGHT", hdr, "RIGHT", -12, 0)
        hint:SetText(defaultOpen and "" or "click to expand")
        hint:SetTextColor(0.45, 0.52, 0.65)

        local divider = box:CreateTexture(nil, "ARTWORK")
        divider:SetPoint("TOPLEFT", box, "TOPLEFT", 8, -28)
        divider:SetPoint("TOPRIGHT", box, "TOPRIGHT", -8, -28)
        divider:SetHeight(1)
        divider:SetColorTexture(1, 1, 1, 0.08)

        local body = CreateFrame("Frame", nil, box)
        body:SetPoint("TOPLEFT", box, "TOPLEFT", 0, -30)
        body:SetPoint("BOTTOMRIGHT", box, "BOTTOMRIGHT", 0, 0)
        body:SetShown(defaultOpen)
        box._msufBody = body

        local function ApplyState()
            local open = not box._msufCollapsed
            body:SetShown(open)
            box:SetHeight(open and box._msufExpandedH or box._msufCollapsedH)
            MSUF_ApplyCollapseVisual(chevron, hint, open)
            if F.UpdateContentHeight then F.UpdateContentHeight() end
        end

        hdr:SetScript("OnClick", function()
            if box._msufCollapsed then
                CollapseAllExcept(box)
                box._msufCollapsed = false
            else
                box._msufCollapsed = true
            end
            ApplyState()
        end)
        do
            local hl = hdr:CreateTexture(nil, "HIGHLIGHT")
            hl:SetAllPoints()
            hl:SetColorTexture(1, 1, 1, 0.03)
        end

        box._msufApplyCollapseState = ApplyState
        S._allSections[#S._allSections + 1] = box
        return box, body
    end

--------------------------------------------------
-- Helper: toggle greyout (like main menu)
-- When a feature toggle is OFF, it should look disabled (greyed),
-- but remain clickable.
--------------------------------------------------
F.ApplyToggleGreyout = function(checkBtn, isOn)
    if not checkBtn then return end
    local on = isOn
    if on == nil and checkBtn.GetChecked then
        on = (checkBtn:GetChecked() == true)
    end
    local a = on and 1 or 0.35
    if checkBtn.SetAlpha then checkBtn:SetAlpha(a) end
    if checkBtn.text and checkBtn.text.SetAlpha then
        checkBtn.text:SetAlpha(a)
    end
end

    --------------------------------------------------
-- Contrast helper for class labels
--------------------------------------------------
F.SetLabelContrast = function(label, r, g, b)
    if not label then return end
    -- Intentionally keep labels readable and consistent:
    -- Always white text with a black shadow (avoid automatic black text on bright colors).
    label:SetTextColor(1, 1, 1)
    label:SetShadowColor(0, 0, 0, 1)
    label:SetShadowOffset(1, -1)
end

    --------------------------------------------------
    -- Color swatch row factory (label + button + texture + OnClick → picker)
    --------------------------------------------------
    F.MkRow = function(parent, labelText, globalName, getter, setter, stateKey, anchorTo, xLabel, yLabel, xSwatch, ySwatch, swatchW, swatchH, panelKey)
        swatchW = swatchW or 32; swatchH = swatchH or 16
        local lbl = parent:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
        lbl:SetPoint("TOPLEFT", anchorTo, "BOTTOMLEFT", xLabel, yLabel)
        lbl:SetJustifyH("LEFT"); lbl:SetText(labelText)
        local btn = CreateFrame("Button", globalName, parent)
        btn:SetSize(swatchW, swatchH)
        btn:SetPoint("TOPLEFT", anchorTo, "BOTTOMLEFT", xSwatch, ySwatch)
        local tex = btn:CreateTexture(nil, "ARTWORK"); tex:SetAllPoints()
        local r, g, b = getter(); tex:SetColorTexture(r, g, b)
        btn:SetScript("OnClick", function()
            local cr, cg, cb = getter()
            OpenColorPicker(cr, cg, cb, function(nr, ng, nb)
                setter(nr, ng, nb); tex:SetColorTexture(nr, ng, nb)
            end)
        end)
        if stateKey then S[stateKey] = tex end
        if panelKey then panel[panelKey] = tex end
        return lbl, btn, tex
    end

    -- Simpler row: anchored relative to a header with row index
    F.MkGridRow = function(parent, labelText, globalName, getter, setter, stateKey, header, labelX, swatchX, swatchW, rowY, panelKey)
        local lbl = parent:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
        lbl:SetPoint("TOPLEFT", header, "BOTTOMLEFT", labelX, rowY)
        lbl:SetJustifyH("LEFT"); lbl:SetText(labelText)
        local btn = CreateFrame("Button", globalName, parent)
        btn:SetSize(swatchW or 120, 16)
        btn:SetPoint("TOPLEFT", header, "BOTTOMLEFT", swatchX, rowY)
        local tex = btn:CreateTexture(nil, "ARTWORK"); tex:SetAllPoints()
        local r, g, b = getter(); tex:SetColorTexture(r, g, b)
        btn:SetScript("OnClick", function()
            local cr, cg, cb = getter()
            OpenColorPicker(cr, cg, cb, function(nr, ng, nb)
                setter(nr, ng, nb); tex:SetColorTexture(nr, ng, nb)
            end)
        end)
        if stateKey then S[stateKey] = tex end
        if panelKey then panel[panelKey] = tex end
        return lbl, btn, tex
    end

    --------------------------------------------------
    -- Title + description
    --------------------------------------------------
    local title = content:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 16, -16)
    title:SetText("Midnight Simple Unit Frames - Colors")

    local subText = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    subText:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
    subText:SetWidth(600)
    subText:SetJustifyH("LEFT")
    subText:SetText("Configure global colors for Player, Target, Focus, Boss and Pet frames.\nGroup Frames (Party/Raid) have their own color controls in each Group Frames section.")

    --------------------------------------------------
    -- Section 1: Global Font Color
    --------------------------------------------------
    S.sec1Box, S.sec1Body = F.MakeCollapsibleSection(content, 100, "Global Font Color", false)
    S.sec1Box:SetPoint("TOPLEFT", subText, "BOTTOMLEFT", 0, -16)
    do local content = S.sec1Body

    local fontLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    fontLabel:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
    fontLabel:SetText("Global font color")

    local fontSwatch = CreateFrame("Button", "MSUF_Colors_FontSwatchButton", content)
    fontSwatch:SetSize(32, 16)
    fontSwatch:SetPoint("TOPLEFT", fontLabel, "BOTTOMLEFT", 0, -8)

    S.fontSwatchTex = fontSwatch:CreateTexture(nil, "ARTWORK")
    S.fontSwatchTex:SetAllPoints()

    fontSwatch:SetScript("OnClick", function()
        local r, g, b = GetGlobalFontColor()
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            SetGlobalFontColor(nr, ng, nb)
            S.fontSwatchTex:SetColorTexture(nr, ng, nb)
        end)
    end)

    local fontResetBtn = CreateFrame("Button", "MSUF_Colors_FontResetButton", content, "UIPanelButtonTemplate")
    fontResetBtn:SetSize(140, 22)
    fontResetBtn:SetPoint("LEFT", fontSwatch, "RIGHT", 12, 0)
    fontResetBtn:SetText("Use font palette")
    fontResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("font palette", function()
                    ResetGlobalFontToPalette()
                    local r, g, b = GetGlobalFontColor()
                    S.fontSwatchTex:SetColorTexture(r, g, b)
        end)
    end)

    end -- section 1

    --------------------------------------------------
    -- Section 2: Class Bar Colors
    --------------------------------------------------
    S.sec2Box, S.sec2Body = F.MakeCollapsibleSection(content, 270, "Class Bar Colors", false)
    S.sec2Box:SetPoint("TOPLEFT", S.sec1Box, "BOTTOMLEFT", 0, -6)
    do local content = S.sec2Body

    local classSub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    classSub:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
    classSub:SetWidth(600)
    classSub:SetJustifyH("LEFT")
    classSub:SetText("Choose an override bar color per class.")

    local startY    = -36
    local rowHeight = 22
    local colWidth  = 110   -- Platz pro Spalte
    local barOffset = 30    -- Abstand innerhalb der Spalte bis zum Balken

    local rowSizes   = { 5, 5, 3 }   -- 5 / 5 / 3 = 13 Klassen
    local rowCount   = #rowSizes
    local classIndex = 1

    for rowIndex, rowSize in ipairs(rowSizes) do
        for colIndex = 1, rowSize do
            local token = CLASS_TOKENS[classIndex]
            if not token then break end
            classIndex = classIndex + 1

            local lower = token:lower()
            local className
            if lower == "deathknight" then
                className = "DK"
            elseif lower == "demonhunter" then
                className = "DH"
            else
                className = lower:sub(1, 1):upper() .. lower:sub(2)
            end

            local c = RAID_CLASS_COLORS and RAID_CLASS_COLORS[token]

            local xOffset = (colIndex - 1) * colWidth
            local yOffset = startY - (rowIndex - 1) * rowHeight

            -- Bar an fester Position je Spalte
            local rowSwatch = CreateFrame("Button", nil, content)
            rowSwatch:SetSize(80, 16)
            rowSwatch:SetPoint("TOPLEFT", classSub, "BOTTOMLEFT", xOffset + barOffset, yOffset)

            local rowTex = rowSwatch:CreateTexture(nil, "ARTWORK")
            rowTex:SetAllPoints()
            if c then
                rowTex:SetColorTexture(c.r, c.g, c.b)
            else
                rowTex:SetColorTexture(1, 1, 1)
            end

            -- Klassename direkt auf die Bar
            local label = rowSwatch:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
            label:SetPoint("CENTER", rowSwatch, "CENTER", 0, 0)
            label:SetJustifyH("CENTER")
            label:SetText(className)

            local r, g, b = GetClassColor(token)
            F.SetLabelContrast(label, r, g, b)

            S.classSwatches[token] = rowTex
            S.classLabels[token]   = label

            rowSwatch:SetScript("OnClick", function()
                local cr, cg, cb = GetClassColor(token)
                OpenColorPicker(cr, cg, cb, function(nr, ng, nb)
                    SetClassColor(token, nr, ng, nb)
                    rowTex:SetColorTexture(nr, ng, nb)
                    F.SetLabelContrast(label, nr, ng, nb)
                end)
            end)
        end
    end

    local resetOffsetY = startY - rowCount * rowHeight - 16

    local resetClassBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
    resetClassBtn:SetSize(180, 22)
    resetClassBtn:SetPoint("TOPLEFT", classSub, "BOTTOMLEFT", 0, resetOffsetY)
    resetClassBtn:SetText("Reset all class colors")
    resetClassBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("class", function()
                    ResetAllClassColors()
                    for _, token in ipairs(CLASS_TOKENS) do
                        local tex   = S.classSwatches[token]
                        local label = S.classLabels[token]
                        if tex then
                            local r, g, b = GetClassColor(token)
                            tex:SetColorTexture(r, g, b)
                            F.SetLabelContrast(label, r, g, b)
                        end
                    end
        end)
    end)

    end -- section 2

    --------------------------------------------------
    -- Section 3: Bar Background Tint
    --------------------------------------------------
    S.sec3Box, S.sec3Body = F.MakeCollapsibleSection(content, 170, "Bar Background Tint", false)
    S.sec3Box:SetPoint("TOPLEFT", S.sec2Box, "BOTTOMLEFT", 0, -6)
    do local content = S.sec3Body

    local classBgSub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    classBgSub:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
    classBgSub:SetWidth(600)
    classBgSub:SetJustifyH("LEFT")
    classBgSub:SetText("Tint applied to the bar background in *all* bar modes. (Dark Mode uses this tint too.)")

    local classBgSwatch = CreateFrame("Button", "MSUF_Colors_ClassBarBgSwatch", content)
    classBgSwatch:SetSize(80, 16)
    classBgSwatch:SetPoint("TOPLEFT", classBgSub, "BOTTOMLEFT", 0, -8)

    S.classBgSwatchTex = classBgSwatch:CreateTexture(nil, "ARTWORK")
    S.classBgSwatchTex:SetAllPoints()

    classBgSwatch:SetScript("OnClick", function()
        local r, g, b = GetClassBarBgColor()
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            SetClassBarBgColor(nr, ng, nb)
            S.classBgSwatchTex:SetColorTexture(nr, ng, nb)
        end)
    end)

    local classBgResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
    classBgResetBtn:SetSize(140, 22)
    classBgResetBtn:SetPoint("TOPLEFT", classBgSwatch, "BOTTOMLEFT", 0, -8)
    classBgResetBtn:SetText("Reset to black")
    classBgResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("class bar background", function()
                    ResetClassBarBgColor()
                    local r, g, b = GetClassBarBgColor()
                    S.classBgSwatchTex:SetColorTexture(r, g, b)
        end)
    end)

    -- Optional toggle: match background tint to the current HP bar color
    -- (so users don't need to pick a separate tint color)
    S.classBgMatchCheck = CreateFrame("CheckButton", "MSUF_Colors_BarBgMatchHP", content, "UICheckButtonTemplate")
    S.classBgMatchCheck:SetPoint("LEFT", classBgSwatch, "RIGHT", 14, 0)
    if not S.classBgMatchCheck.text then
        S.classBgMatchCheck.text = S.classBgMatchCheck:CreateFontString(nil, "ARTWORK", "GameFontNormal")
        S.classBgMatchCheck.text:SetPoint("LEFT", S.classBgMatchCheck, "RIGHT", 2, 0)
    end
    S.classBgMatchCheck.text:SetText("Match HP")

    local function UpdateClassBgMatchState()
        local match = GetBarBgMatchHP()
        S.classBgMatchCheck:SetChecked(match)
        if classBgSwatch and classBgSwatch.EnableMouse then
            classBgSwatch:EnableMouse(not match)
        end
        if classBgSwatch and classBgSwatch.SetAlpha then
            classBgSwatch:SetAlpha(match and 0.5 or 1)
        end
        if classBgResetBtn and classBgResetBtn.SetEnabled then
            classBgResetBtn:SetEnabled(not match)
        end
    end

    S.classBgMatchCheck:SetScript("OnClick", function(btn)
        SetBarBgMatchHP(btn:GetChecked())
        UpdateClassBgMatchState()
    end)

    -- Initial state
    UpdateClassBgMatchState()

    -- Toggle: use tint color directly in Dark Mode (bypass brightness dimming).
    -- Allows fully custom background colors (including white) in Dark Mode.
    -- NOTE: All references stored on F to avoid adding locals (Lua 5.1 200-local limit).
    F._darkBgCustomCheck = CreateFrame("CheckButton", "MSUF_Colors_DarkBgCustomColor", content, "UICheckButtonTemplate")
    F._darkBgCustomCheck:SetPoint("TOPLEFT", classBgResetBtn, "BOTTOMLEFT", -4, -4)
    if not F._darkBgCustomCheck.text then
        F._darkBgCustomCheck.text = F._darkBgCustomCheck:CreateFontString(nil, "ARTWORK", "GameFontNormal")
        F._darkBgCustomCheck.text:SetPoint("LEFT", F._darkBgCustomCheck, "RIGHT", 2, 0)
    end
    F._darkBgCustomCheck.text:SetText("Custom color in Dark Mode")

    F.UpdateDarkBgCustomControls = function()
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        local g = MSUF_DB.general
        local mode = g.barMode
        if mode ~= "dark" and mode ~= "class" and mode ~= "unified" and mode ~= "gradient" then
            mode = (g.useClassColors and "class") or "dark"
        end
        local isDark = (mode == "dark")
        local a = isDark and 1 or 0.35
        F._darkBgCustomCheck:SetChecked(g.darkBgCustomColor and true or false)
        if F._darkBgCustomCheck.Enable and F._darkBgCustomCheck.Disable then
            if isDark then F._darkBgCustomCheck:Enable() else F._darkBgCustomCheck:Disable() end
        end
        F._darkBgCustomCheck:SetAlpha(a)
        if F._darkBgCustomCheck.text then F._darkBgCustomCheck.text:SetAlpha(a) end
    end

    F._darkBgCustomCheck:SetScript("OnClick", function(btn)
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        MSUF_DB.general.darkBgCustomColor = btn:GetChecked() and true or false
        PushVisualUpdates()
        F.UpdateDarkBgCustomControls()
    end)

    F.UpdateDarkBgCustomControls()

    end -- section 3

    --------------------------------------------------
    -- Section 4: Unitframe Global Coloring
    --------------------------------------------------
    S.sec4Box, S.sec4Body = F.MakeCollapsibleSection(content, 250, "Unitframe Global Coloring", false)
    S.sec4Box:SetPoint("TOPLEFT", S.sec3Box, "BOTTOMLEFT", 0, -6)
    do local content = S.sec4Body

    local barModeLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    barModeLabel:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
    barModeLabel:SetText("Bar mode")

    local barModeOptions = {
        { key = "dark",     label = "Dark Mode (dark black bars)" },
        { key = "class",    label = "Class Color Mode (color HP bars)" },
        { key = "unified",  label = "Unified Color Mode (one color for all frames)" },
        { key = "gradient", label = "Color Gradient" },
    }

    S.barModeDrop = (_G.MSUF_CreateStyledDropdown and _G.MSUF_CreateStyledDropdown("MSUF_Colors_BarModeDropdown", content) or CreateFrame("Frame", "MSUF_Colors_BarModeDropdown", content, "UIDropDownMenuTemplate"))
    S.barModeDrop:SetPoint("TOPLEFT", barModeLabel, "BOTTOMLEFT", -16, -4)
    UIDropDownMenu_SetWidth(S.barModeDrop, 240)
    MSUF_ExpandDropdownClickArea(S.barModeDrop)

    F.BarModeDropdown_Initialize = function(self, level)
        EnsureDB()
        local g = (MSUF_DB and MSUF_DB.general) or {}
        local current = g.barMode
        if current ~= "dark" and current ~= "class" and current ~= "unified" and current ~= "gradient" then
            current = (g.useClassColors and "class") or "dark"
        end

        for _, opt in ipairs(barModeOptions) do
            local info = UIDropDownMenu_CreateInfo()
            info.text  = opt.label
            info.value = opt.key
            info.func  = function(btn)
                if S.barAppearanceRefreshing then return end
                EnsureDB()
                if not MSUF_DB.general then MSUF_DB.general = {} end
                local mode = btn.value
                MSUF_DB.general.barMode = mode

                -- Keep legacy booleans in sync
                if mode == "dark" then
                    MSUF_DB.general.darkMode       = true
                    MSUF_DB.general.useClassColors = false
                elseif mode == "class" then
                    MSUF_DB.general.darkMode       = false
                    MSUF_DB.general.useClassColors = true
                else -- unified or gradient: neither legacy flag applies
                    MSUF_DB.general.darkMode       = false
                    MSUF_DB.general.useClassColors = false
                end

                UIDropDownMenu_SetSelectedValue(S.barModeDrop, mode)
                UIDropDownMenu_SetText(S.barModeDrop, opt.label)

                if F.UpdateDarkBarControls then F.UpdateDarkBarControls() end
                if F.UpdateDarkBgCustomControls then F.UpdateDarkBgCustomControls() end
                if F.UpdateUnifiedBarControls then F.UpdateUnifiedBarControls() end
                PushVisualUpdates()
                MSUF_ShowBarModeReloadPopup(opt.label)
            end
            info.checked = (opt.key == current)
            UIDropDownMenu_AddButton(info, level)
        end
    end

    UIDropDownMenu_Initialize(S.barModeDrop, F.BarModeDropdown_Initialize)

    -- Unified bar color (only used when Bar mode == "unified")
    local unifiedLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    unifiedLabel:SetPoint("TOPLEFT", S.barModeDrop, "BOTTOMLEFT", 16, -18)
    unifiedLabel:SetText("Unified bar color")

    local unifiedSwatch = CreateFrame("Button", "MSUF_Colors_UnifiedBarSwatch", content)
    unifiedSwatch:SetSize(240, 16)
    unifiedSwatch:SetPoint("TOPLEFT", unifiedLabel, "BOTTOMLEFT", 0, -8)

    local unifiedTex = unifiedSwatch:CreateTexture(nil, "ARTWORK")
    unifiedTex:SetAllPoints()

    local unifiedResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
    unifiedResetBtn:SetSize(140, 22)
    unifiedResetBtn:SetPoint("TOPLEFT", unifiedSwatch, "BOTTOMLEFT", 0, -8)
    unifiedResetBtn:SetText("Reset to default")

    local function MSUF_GetUnifiedBarColor()
        EnsureDB()
        local g = (MSUF_DB and MSUF_DB.general) or {}
        local r, gg, b = g.unifiedBarR, g.unifiedBarG, g.unifiedBarB
        if type(r) ~= "number" or type(gg) ~= "number" or type(b) ~= "number" then
            -- Reasonable default (slightly desaturated cyan)
            r, gg, b = 0.10, 0.60, 0.90
        end
        if r < 0 then r = 0 elseif r > 1 then r = 1 end
        if gg < 0 then gg = 0 elseif gg > 1 then gg = 1 end
        if b < 0 then b = 0 elseif b > 1 then b = 1 end
        return r, gg, b
    end

    local function MSUF_SetUnifiedBarColor(r, gg, b)
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        MSUF_DB.general.unifiedBarR = r
        MSUF_DB.general.unifiedBarG = gg
        MSUF_DB.general.unifiedBarB = b
    end

    local function MSUF_ResetUnifiedBarColor()
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        MSUF_DB.general.unifiedBarR = 0.10
        MSUF_DB.general.unifiedBarG = 0.60
        MSUF_DB.general.unifiedBarB = 0.90
    end

    unifiedSwatch:SetScript("OnClick", function()
        local r, gg, b = MSUF_GetUnifiedBarColor()
        OpenColorPicker(r, gg, b, function(nr, ng, nb)
            MSUF_SetUnifiedBarColor(nr, ng, nb)
            unifiedTex:SetColorTexture(nr, ng, nb)
            PushVisualUpdates()
        end)
    end)

    unifiedResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("bar", function()
                    MSUF_ResetUnifiedBarColor()
                    local r, gg, b = MSUF_GetUnifiedBarColor()
                    unifiedTex:SetColorTexture(r, gg, b)
                    PushVisualUpdates()
        end)
    end)

    local function UpdateUnifiedBarControls()
        EnsureDB()
        local g = (MSUF_DB and MSUF_DB.general) or {}
        local mode = g.barMode
        if mode ~= "dark" and mode ~= "class" and mode ~= "unified" and mode ~= "gradient" then
            mode = (g.useClassColors and "class") or "dark"
        end
        local enabled = (mode == "unified")
        local a = enabled and 1 or 0.35

        unifiedLabel:SetAlpha(a)
        unifiedSwatch:SetAlpha(a)
        unifiedResetBtn:SetAlpha(a)
        unifiedSwatch:EnableMouse(enabled and true or false)
        unifiedResetBtn:SetEnabled(enabled and true or false)
    end

    -- Init swatch + state
    do
        local r, gg, b = MSUF_GetUnifiedBarColor()
        unifiedTex:SetColorTexture(r, gg, b)
        UpdateUnifiedBarControls()
        -- Expose updater so dropdown selection can refresh both sets
        F.UpdateUnifiedBarControls = UpdateUnifiedBarControls
    end
local darkToneLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
darkToneLabel:SetPoint("TOPLEFT", unifiedResetBtn, "BOTTOMLEFT", 0, -18)
darkToneLabel:SetText("Dark mode bar color")

    S.darkToneLabelFS = darkToneLabel

-- Continuous gray "picker" bar (ColorPicker-style, but HORIZONTAL)
-- NOTE: We intentionally implement this as a plain Frame (NOT a Slider).
-- Some Midnight/Beta builds / skin passes can reskin Slider widgets into the vertical "eye" slider.
-- A plain Frame with our own drag logic is stable and guarantees the requested horizontal behavior.

-- Hide any legacy widget that might still exist from older builds (defensive; no errors if nil)
do
    local legacy = _G["MSUF_Colors_DarkToneSlider"]
    if legacy and legacy.Hide and legacy ~= S.darkToneSlider then
        legacy:Hide()
    end
end

S.darkToneSlider = CreateFrame("Frame", "MSUF_Colors_DarkToneSlider", content)
S.darkToneSlider:SetSize(240, 14)
S.darkToneSlider:SetPoint("TOPLEFT", darkToneLabel, "BOTTOMLEFT", 0, -10)
S.darkToneSlider:EnableMouse(true)

local darkToneBG = S.darkToneSlider:CreateTexture(nil, "BACKGROUND")
darkToneBG:SetAllPoints()
darkToneBG:SetColorTexture(1, 1, 1, 1)

-- black (left) -> white (right)  (so moving toward white makes the bar LIGHTER)
do
    local ok = false
    if darkToneBG.SetGradientAlpha then
        ok = pcall(function()
            darkToneBG:SetGradientAlpha("HORIZONTAL", 0, 0, 0, 1,  1, 1, 1, 1)
        end)
    elseif darkToneBG.SetGradient and CreateColor then
        ok = pcall(function()
            darkToneBG:SetGradient("HORIZONTAL", CreateColor(0, 0, 0, 1), CreateColor(1, 1, 1, 1))
        end)
    end
    if not ok then
        -- fallback: readable neutral background (no crash)
        darkToneBG:SetColorTexture(0.65, 0.65, 0.65, 1)
    end
end

-- Border (subtle)
if S.darkToneSlider.SetBackdrop then
    S.darkToneSlider:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        edgeSize = 1,
        insets = { left = 0, right = 0, top = 0, bottom = 0 },
    })
    S.darkToneSlider:SetBackdropColor(0, 0, 0, 0)
    S.darkToneSlider:SetBackdropBorderColor(0, 0, 0, 0.55)
end

local knob = S.darkToneSlider:CreateTexture(nil, "OVERLAY")
knob:SetTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
knob:SetSize(16, 16)

F.ClampPct = function(v)
    v = tonumber(v) or 0
    if v < 0 then v = 0 end
    if v > 100 then v = 100 end
    return math.floor(v + 0.5)
end

F.PositionKnob = function(pct)
    if not knob then return end
    local w = S.darkToneSlider:GetWidth() or 1
    local x = (pct / 100) * w
    knob:ClearAllPoints()
    knob:SetPoint("CENTER", S.darkToneSlider, "LEFT", x, 0)
end

-- Provide a minimal "Slider-like" API for existing refresh/disable logic
function S.darkToneSlider:SetValue(pct)
    pct = F.ClampPct(pct)
    F.PositionKnob(pct)
end
function S.darkToneSlider:SetEnabled(enabled)
    self:EnableMouse(enabled and true or false)
end

S.darkToneValueText = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
S.darkToneValueText:SetPoint("LEFT", S.darkToneSlider, "RIGHT", 10, 0)
S.darkToneValueText:SetText("0%  (#000000)")

F.UpdateDarkToneValueText = function(pct)
    local v = (pct or 0) / 100
    local c = math.floor(v * 255 + 0.5)
    if c < 0 then c = 0 end
    if c > 255 then c = 255 end
    if S.darkToneValueText then
        S.darkToneValueText:SetText(string.format("%d%%  (#%02X%02X%02X)", pct or 0, c, c, c))
    end
end

local _lastAppliedPct = -1
F.ApplyPct = function(pct, fromUser)
    pct = F.ClampPct(pct)

    -- Always keep the knob + label in sync, even if we early-return.
    F.PositionKnob(pct)
    if F.UpdateDarkToneValueText then F.UpdateDarkToneValueText(pct) end

    if pct == _lastAppliedPct then return end
    _lastAppliedPct = pct

    if fromUser then
        if S.barAppearanceRefreshing then return end
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        -- 0 = black, 1 = white
        MSUF_DB.general.darkBarGray = pct / 100
        MSUF_DB.general.darkBarTone = nil
        PushVisualUpdates()
    end
end

F.GetPctFromCursor = function()
    local cx = (GetCursorPosition())
    local scale = S.darkToneSlider:GetEffectiveScale() or 1
    cx = cx / scale
    local left = S.darkToneSlider:GetLeft() or 0
    local w = S.darkToneSlider:GetWidth() or 1
    return ((cx - left) / w) * 100
end

F.StopDrag = function(self)
    self.__msufDragging = nil
    self:SetScript("OnUpdate", nil)
end

S.darkToneSlider:SetScript("OnMouseDown", function(self, button)
    if button ~= "LeftButton" then return end
    self.__msufDragging = true
    F.ApplyPct(F.GetPctFromCursor(), true)
    self:SetScript("OnUpdate", function()
        if not self.__msufDragging then return end
        F.ApplyPct(F.GetPctFromCursor(), true)
    end)
end)
S.darkToneSlider:SetScript("OnMouseUp", F.StopDrag)
S.darkToneSlider:SetScript("OnHide", F.StopDrag)

-- Enable/disable dark-mode-only controls when bar mode is not "dark"
F.UpdateDarkBarControls = function()
    EnsureDB()
    local g = (MSUF_DB and MSUF_DB.general) or {}
    local mode = g.barMode
    if mode ~= "dark" and mode ~= "class" and mode ~= "unified" and mode ~= "gradient" then
        mode = (g.useClassColors and "class") or "dark"
    end
    local enabled = (mode == "dark")

    local a = enabled and 1 or 0.35

    if S.darkToneLabelFS then S.darkToneLabelFS:SetAlpha(a) end
    if S.darkToneSlider then
        if S.darkToneSlider.SetEnabled then S.darkToneSlider:SetEnabled(enabled) end
        S.darkToneSlider:SetAlpha(a)
    end
    if S.darkToneValueText then S.darkToneValueText:SetAlpha(a) end
end

if F.UpdateDarkBarControls then
    F.UpdateDarkBarControls()
end

    end -- section 4

    --------------------------------------------------
    -- Section 5: Unitframe & Bar Colors (two-column)
    --------------------------------------------------
    S.sec5Box, S.sec5Body = F.MakeCollapsibleSection(content, 220, "Unitframe Colors", false)
    S.sec5Box:SetPoint("TOPLEFT", S.sec4Box, "BOTTOMLEFT", 0, -6)
    do local content = S.sec5Body

    local leftHeaderX   = 0
    local rightHeaderX  = 420

    local rowH          = 22
    local startY        = -8

    -- Left block: Unitframe Colors
    local unitHeader = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    unitHeader:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
    unitHeader:SetText("Unitframe Colors")

    local unitLabelX    = 0
    local unitBarX      = 220
    local unitBarW      = 120

    -- Data-driven NPC + Pet color rows
    local UF_COLOR_ROWS = {
        { label = "Friendly NPC Color", key = "friendly", name = "NPCFriendlySwatch", state = "npcFriendlyTex", get = function() return GetNPCColor("friendly") end, set = function(r,g,b) SetNPCColor("friendly",r,g,b) end },
        { label = "Neutral NPC Color",  key = "neutral",  name = "NPCNeutralSwatch",  state = "npcNeutralTex",  get = function() return GetNPCColor("neutral") end,  set = function(r,g,b) SetNPCColor("neutral",r,g,b) end },
        { label = "Enemy NPC Color",    key = "enemy",    name = "NPCEnemySwatch",    state = "npcEnemyTex",    get = function() return GetNPCColor("enemy") end,    set = function(r,g,b) SetNPCColor("enemy",r,g,b) end },
        { label = "Dead NPC Color",     key = "dead",     name = "NPCDeadSwatch",     state = "npcDeadTex",     get = function() return GetNPCColor("dead") end,     set = function(r,g,b) SetNPCColor("dead",r,g,b) end },
        { label = "Pet Frame Color",    key = "pet",      name = "PetFrameSwatch",     state = "petFrameTex",    get = GetPetFrameColor, set = SetPetFrameColor },
    }
    for i, def in ipairs(UF_COLOR_ROWS) do
        F.MkGridRow(content, def.label, "MSUF_Colors_"..def.name, def.get, def.set, def.state, unitHeader, unitLabelX, unitBarX, unitBarW, startY - (i-1) * rowH)
    end

    local unitResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
    unitResetBtn:SetSize(180, 22)
    unitResetBtn:SetPoint("TOPLEFT", unitHeader, "BOTTOMLEFT", unitLabelX, startY - 5 * rowH - 4)
    unitResetBtn:SetText("Reset Unitframe Colors")
    unitResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("unitframe", function()
            if EnsureDB and MSUF_DB then
                EnsureDB(); MSUF_DB.npcColors = nil; PushVisualUpdates()
            end
            for _, def in ipairs(UF_COLOR_ROWS) do
                local tex = S[def.state]
                if tex then local r, g, b = def.get(); tex:SetColorTexture(r, g, b) end
            end
        end)
    end)

    end -- section 5 (Unitframe Colors)

    --------------------------------------------------
    -- Section 5t: NPC Type Colors
    --------------------------------------------------
    S.sec5tBox, S.sec5tBody = F.MakeCollapsibleSection(content, 380, "NPC Type Colors", false)
    S.sec5tBox:SetPoint("TOPLEFT", S.sec5Box, "BOTTOMLEFT", 0, -6)
    do local content = S.sec5tBody

    local rowH     = 22
    local startY   = -8
    local labelX   = 0
    local swatchX  = 220
    local swatchW  = 120

    -- Master enable toggle
    local enableCB = CreateFrame("CheckButton", "MSUF_Colors_NPCTypeEnableCB", content, "UICheckButtonTemplate")
    enableCB:SetPoint("TOPLEFT", content, "TOPLEFT", 8, -4)
    local enableText = enableCB:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    enableText:SetPoint("LEFT", enableCB, "RIGHT", 2, 0)
    enableText:SetText("Enable NPC Type Colors (Boss / Caster / Melee ...)")
    enableCB:SetChecked(GetNPCColorMode() == "type")

    -- Sub-toggle: Color HP bar
    local barCB = CreateFrame("CheckButton", "MSUF_Colors_NPCTypeColorBarCB", content, "UICheckButtonTemplate")
    barCB:SetPoint("TOPLEFT", enableCB, "BOTTOMLEFT", 16, 2)
    local barText = barCB:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    barText:SetPoint("LEFT", barCB, "RIGHT", 2, 0)
    barText:SetText("Color HP bar (Class Color mode only)")
    barCB:SetChecked(GetNPCTypeColorBar())
    barCB:SetScript("OnClick", function(btn) SetNPCTypeColorBar(btn:GetChecked()) end)

    -- Sub-toggle: Color name text
    local textCB = CreateFrame("CheckButton", "MSUF_Colors_NPCTypeColorTextCB", content, "UICheckButtonTemplate")
    textCB:SetPoint("TOPLEFT", barCB, "BOTTOMLEFT", 0, 2)
    local textTxt = textCB:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    textTxt:SetPoint("LEFT", textCB, "RIGHT", 2, 0)
    textTxt:SetText("Color name text")
    textCB:SetChecked(GetNPCTypeColorText())
    textCB:SetScript("OnClick", function(btn) SetNPCTypeColorText(btn:GetChecked()) end)

    -- Apply-to label
    local applyLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    applyLabel:SetPoint("TOPLEFT", textCB, "BOTTOMLEFT", 0, -4)
    applyLabel:SetText("Apply to:")

    -- Per-unit checkboxes (2-column layout)
    local perUnitCBs = {}
    for i, info in ipairs(NPC_TYPE_UNITS) do
        local cb = CreateFrame("CheckButton", "MSUF_Colors_NPCTypeUnit_" .. info.key, content, "UICheckButtonTemplate")
        local col = ((i - 1) % 2)   -- 0 or 1
        local row = math.floor((i - 1) / 2) -- 0, 1, ...
        cb:SetPoint("TOPLEFT", applyLabel, "BOTTOMLEFT", 16 + col * 180, -2 - row * 22)
        local txt = cb:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
        txt:SetPoint("LEFT", cb, "RIGHT", 2, 0)
        txt:SetText(info.label)
        cb:SetChecked(GetNPCTypePerUnit(info.key))
        cb:SetScript("OnClick", function(btn) SetNPCTypePerUnit(info.key, btn:GetChecked()) end)
        perUnitCBs[#perUnitCBs + 1] = cb
    end

    -- Info label
    local infoText = content:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
    infoText:SetPoint("TOPLEFT", applyLabel, "BOTTOMLEFT", 0, -48)
    infoText:SetWidth(520)
    infoText:SetJustifyH("LEFT")
    infoText:SetText("HP bar coloring requires Class Color bar mode. Active in 5-man dungeons only. Name text works in all bar modes.")

    -- Anchor for swatch rows
    local header = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    header:SetPoint("TOPLEFT", infoText, "BOTTOMLEFT", -4, -8)
    header:SetText("")
    header:SetHeight(1)

    local NPC_TYPE_SWATCHES = {
        { key = "npcBoss",     label = "Boss",     row = 0 },
        { key = "npcMiniboss", label = "Miniboss / Lieutenant", row = 1 },
        { key = "npcCaster",   label = "Caster",   row = 2 },
        { key = "npcMelee",    label = "Melee",    row = 3 },
        { key = "npcRegular",  label = "Regular",  row = 4 },
    }

    for _, info in ipairs(NPC_TYPE_SWATCHES) do
        local lbl = content:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
        lbl:SetPoint("TOPLEFT", header, "BOTTOMLEFT", labelX, startY - info.row * rowH)
        lbl:SetJustifyH("LEFT")
        lbl:SetText(info.label)

        local sw = CreateFrame("Button", "MSUF_Colors_NPCType_" .. info.key, content)
        sw:SetSize(swatchW, 16)
        sw:SetPoint("TOPLEFT", header, "BOTTOMLEFT", swatchX, startY - info.row * rowH)

        local tex = sw:CreateTexture(nil, "ARTWORK")
        tex:SetAllPoints()
        local cr, cg, cb = GetNPCColor(info.key)
        tex:SetColorTexture(cr, cg, cb)

        S["npcType_" .. info.key .. "_tex"] = tex

        sw:SetScript("OnClick", function()
            local r, g, b = GetNPCColor(info.key)
            OpenColorPicker(r, g, b, function(nr, ng, nb)
                SetNPCColor(info.key, nr, ng, nb)
                tex:SetColorTexture(nr, ng, nb)
            end)
        end)
    end

    -- Grey out swatches + sub-toggles when master is disabled
    local function UpdateNPCTypeEnabled()
        local enabled = enableCB:GetChecked()
        for _, info in ipairs(NPC_TYPE_SWATCHES) do
            local sw = _G["MSUF_Colors_NPCType_" .. info.key]
            if sw then
                sw:EnableMouse(enabled)
                sw:SetAlpha(enabled and 1 or 0.35)
            end
        end
        barCB:EnableMouse(enabled);   barCB:SetAlpha(enabled and 1 or 0.5)
        textCB:EnableMouse(enabled);  textCB:SetAlpha(enabled and 1 or 0.5)
        for _, cb in ipairs(perUnitCBs) do
            cb:EnableMouse(enabled); cb:SetAlpha(enabled and 1 or 0.5)
        end
    end

    enableCB:SetScript("OnClick", function(btn)
        SetNPCColorMode(btn:GetChecked() and "type" or "reaction")
        UpdateNPCTypeEnabled()
    end)
    UpdateNPCTypeEnabled()

    -- Reset button
    local resetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
    resetBtn:SetSize(180, 22)
    resetBtn:SetPoint("TOPLEFT", header, "BOTTOMLEFT", labelX, startY - #NPC_TYPE_SWATCHES * rowH - 4)
    resetBtn:SetText("Reset NPC Type Colors")
    resetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("NPC type colors", function()
            ResetNPCTypeColors()
            for _, info in ipairs(NPC_TYPE_SWATCHES) do
                local t = S["npcType_" .. info.key .. "_tex"]
                if t then
                    local r, g, b = GetNPCColor(info.key)
                    t:SetColorTexture(r, g, b)
                end
            end
        end)
    end)

    end -- section 5t (NPC Type Colors)

    --------------------------------------------------
    -- Section 5b: Bar Colors
    --------------------------------------------------
    S.sec5bBox, S.sec5bBody = F.MakeCollapsibleSection(content, 220, "Bar Colors", false)
    S.sec5bBox:SetPoint("TOPLEFT", S.sec5tBox, "BOTTOMLEFT", 0, -6)
    do local content = S.sec5bBody

    local barLabelX     = 0
    local barSwatchX    = 210
    local barSwatchW    = 120

    local rowH          = 22
    local startY        = -8

    -- Invisible anchor for bar color rows
    local barHeader = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    barHeader:SetPoint("TOPLEFT", content, "TOPLEFT", 12, 0)
    barHeader:SetText("")
    barHeader:SetHeight(1)

    -- Generic DB color getter/setter factory for general.xxxR/G/B keys
    local function MkDBColorGetter(keyR, keyG, keyB, defR, defG, defB)
        return function()
            if EnsureDB and MSUF_DB then
                EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
                local g = MSUF_DB.general
                local r, gg, b = g[keyR], g[keyG], g[keyB]
                if type(r) == "number" and type(gg) == "number" and type(b) == "number" then return r, gg, b end
            end
            return defR, defG, defB
        end
    end
    local function MkDBColorSetter(keyR, keyG, keyB)
        return function(r, g, b)
            if not EnsureDB or not MSUF_DB then return end
            EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
            MSUF_DB.general[keyR] = r; MSUF_DB.general[keyG] = g; MSUF_DB.general[keyB] = b
            PushVisualUpdates()
        end
    end

    local GetPurgeBorderColor = MkDBColorGetter("purgeBorderColorR","purgeBorderColorG","purgeBorderColorB", 1.00, 0.85, 0.00)
    local SetPurgeBorderColor = MkDBColorSetter("purgeBorderColorR","purgeBorderColorG","purgeBorderColorB")

    -- Data-driven bar color rows
    local BAR_COLOR_ROWS = {
        { label = "Absorb Bar Color",           name = "AbsorbOverlaySwatch",    get = GetAbsorbOverlayColor,       set = SetAbsorbOverlayColor,       pkey = "__MSUF_ExtraColorAbsorbTex" },
        { label = "Heal-Absorb Bar Color",      name = "HealAbsorbOverlaySwatch",get = GetHealAbsorbOverlayColor,   set = SetHealAbsorbOverlayColor,   pkey = "__MSUF_ExtraColorHealAbsorbTex" },
        { label = "Power Bar Background Color", name = "PowerBarBackgroundSwatch",get = GetPowerBarBackgroundColor,  set = SetPowerBarBackgroundColor,  pkey = "__MSUF_ExtraColorPowerBgTex" },
        { label = "Aggro Border Color",         name = "AggroBorderSwatch",      get = GetAggroBorderColor,         set = SetAggroBorderColor,         pkey = "__MSUF_ExtraColorAggroBorderTex" },
        { label = "Purge Border Color",         name = "PurgeBorderSwatch",      get = GetPurgeBorderColor,         set = SetPurgeBorderColor,         pkey = "__MSUF_ExtraColorPurgeBorderTex" },
    }
    for i, def in ipairs(BAR_COLOR_ROWS) do
        local _, btn = F.MkGridRow(content, def.label, "MSUF_Colors_"..def.name, def.get, def.set, nil, barHeader, barLabelX, barSwatchX, barSwatchW, startY - (i-1) * rowH, def.pkey)
        if def.pkey == "__MSUF_ExtraColorPowerBgTex" then panel.__MSUF_ExtraColorPowerBgSwatch = btn end
    end

    -- PowerBg MatchHP checkbox (after the grid rows)
    local powerBgSwatch = panel.__MSUF_ExtraColorPowerBgSwatch
    panel.__MSUF_ExtraColorPowerBgMatchCheck = panel.__MSUF_ExtraColorPowerBgMatchCheck or CreateFrame("CheckButton", "MSUF_Colors_PowerBarBgMatchHP", content, "UICheckButtonTemplate")
    panel.__MSUF_ExtraColorPowerBgMatchCheck:ClearAllPoints()
    panel.__MSUF_ExtraColorPowerBgMatchCheck:SetPoint("LEFT", powerBgSwatch, "RIGHT", 14, 0)
    if not panel.__MSUF_ExtraColorPowerBgMatchCheck.text then
        panel.__MSUF_ExtraColorPowerBgMatchCheck.text = panel.__MSUF_ExtraColorPowerBgMatchCheck:CreateFontString(nil, "ARTWORK", "GameFontNormal")
        panel.__MSUF_ExtraColorPowerBgMatchCheck.text:SetPoint("LEFT", panel.__MSUF_ExtraColorPowerBgMatchCheck, "RIGHT", 2, 0)
    end
    panel.__MSUF_ExtraColorPowerBgMatchCheck.text:SetText("Match HP")
    panel.__MSUF_ExtraColorPowerBgMatchCheck:SetChecked(GetPowerBarBackgroundMatchHP())
    panel.__MSUF_ExtraColorPowerBgMatchCheck:SetScript("OnClick", function(btn)
        SetPowerBarBackgroundMatchHP(btn:GetChecked())
        if powerBgSwatch then powerBgSwatch:EnableMouse(not btn:GetChecked()); powerBgSwatch:SetAlpha(btn:GetChecked() and 0.35 or 1) end
    end)
    do local m = GetPowerBarBackgroundMatchHP()
        if powerBgSwatch then powerBgSwatch:EnableMouse(not m); powerBgSwatch:SetAlpha(m and 0.35 or 1) end
    end

    -- Reset bar colors only
    local npcResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
    npcResetBtn:SetSize(160, 22)
    npcResetBtn:SetPoint("TOPLEFT", barHeader, "BOTTOMLEFT", barLabelX, startY - #BAR_COLOR_ROWS * rowH - 4)
    npcResetBtn:SetText("Reset Bar Colors")
    npcResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("bar colors", function()
            if EnsureDB and MSUF_DB then
                EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
                local gen = MSUF_DB.general
                for _, keys in ipairs({
                    {"absorbBarColorR","absorbBarColorG","absorbBarColorB"},
                    {"healAbsorbBarColorR","healAbsorbBarColorG","healAbsorbBarColorB"},
                    {"powerBarBgColorR","powerBarBgColorG","powerBarBgColorB"},
                    {"aggroBorderColorR","aggroBorderColorG","aggroBorderColorB"},
                    {"purgeBorderColorR","purgeBorderColorG","purgeBorderColorB"},
                }) do gen[keys[1]], gen[keys[2]], gen[keys[3]] = nil, nil, nil end
                gen.powerBarBgMatchHPColor = nil
                MSUF_DB.bars = MSUF_DB.bars or {}; MSUF_DB.bars.powerBarBgMatchBarColor = nil
                PushVisualUpdates()
            end
            for _, def in ipairs(BAR_COLOR_ROWS) do
                local tex = panel[def.pkey]; if tex then local r, g, b = def.get(); tex:SetColorTexture(r, g, b) end
            end
            if panel.__MSUF_ExtraColorPowerBgMatchCheck then panel.__MSUF_ExtraColorPowerBgMatchCheck:SetChecked(false) end
            if powerBgSwatch then powerBgSwatch:EnableMouse(true); powerBgSwatch:SetAlpha(1) end
        end)
    end)

    S.lastControl = npcResetBtn

    end -- section 5b (Bar Colors)

    --------------------------------------------------
    -- Section 5d: Dispel Colors
    --------------------------------------------------
    S.sec5dBox, S.sec5dBody = F.MakeCollapsibleSection(content, 300, "Dispel", false)
    S.sec5dBox:SetPoint("TOPLEFT", S.sec5bBox, "BOTTOMLEFT", 0, -6)
    do local content = S.sec5dBody

    local dispelHint = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    dispelHint:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
    dispelHint:SetWidth(420)
    dispelHint:SetJustifyH("LEFT")
    dispelHint:SetText("Dispel color shared by Highlight Border and Group Frame Dispel Overlay.")
    dispelHint:SetTextColor(0.55, 0.60, 0.70)

    -- Color mode dropdown (moved from Bars > Highlight Borders)
    local dispelModeLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    dispelModeLabel:SetPoint("TOPLEFT", dispelHint, "BOTTOMLEFT", 0, -10)
    dispelModeLabel:SetText("Color mode")

    local dispelModeDrop = (_G.MSUF_CreateStyledDropdown and _G.MSUF_CreateStyledDropdown("MSUF_Colors_DispelModeDropdown", content) or CreateFrame("Frame", "MSUF_Colors_DispelModeDropdown", content, "UIDropDownMenuTemplate"))
    dispelModeDrop:SetPoint("TOPLEFT", dispelModeLabel, "BOTTOMLEFT", -16, -2)
    UIDropDownMenu_SetWidth(dispelModeDrop, 180)
    MSUF_ExpandDropdownClickArea(dispelModeDrop)

    local function GetDispelColorMode()
        if EnsureDB and MSUF_DB then
            EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
            return MSUF_DB.general.hlDispelColorMode or "SINGLE"
        end
        return "SINGLE"
    end

    local _DISPEL_MODE_ITEMS = {
        { key = "SINGLE", label = "Single color" },
        { key = "TYPE",   label = "Per debuff type" },
    }

    UIDropDownMenu_Initialize(dispelModeDrop, function(self, level)
        local current = GetDispelColorMode()
        for _, opt in ipairs(_DISPEL_MODE_ITEMS) do
            local info = UIDropDownMenu_CreateInfo()
            info.text = opt.label; info.value = opt.key
            info.checked = (current == opt.key)
            info.func = function()
                if EnsureDB and MSUF_DB then
                    EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
                    MSUF_DB.general.hlDispelColorMode = opt.key
                    PushVisualUpdates()
                    UIDropDownMenu_SetSelectedValue(dispelModeDrop, opt.key)
                    UIDropDownMenu_SetText(dispelModeDrop, opt.label)
                    if _G.MSUF_RefreshDispelTypeColorVisibility then _G.MSUF_RefreshDispelTypeColorVisibility() end
                    if _G.MSUF_PrioRows_Reinit then _G.MSUF_PrioRows_Reinit() end
                    if _G.MSUF_DispelBorderTestMode and type(_G.MSUF_SetDispelBorderTestMode) == "function" then
                        _G.MSUF_SetDispelBorderTestMode(true, "shared")
                    end
                end
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)
    do
        local m = GetDispelColorMode()
        UIDropDownMenu_SetSelectedValue(dispelModeDrop, m)
        for _, opt in ipairs(_DISPEL_MODE_ITEMS) do
            if opt.key == m then UIDropDownMenu_SetText(dispelModeDrop, opt.label); break end
        end
    end

    -- Single color swatch (all dispel types share this color)
    local singleLabel = content:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    singleLabel:SetPoint("TOPLEFT", dispelModeDrop, "BOTTOMLEFT", 20, -6)
    singleLabel:SetJustifyH("LEFT"); singleLabel:SetText("Dispel Color (all types)")

    local singleSwatch = CreateFrame("Button", "MSUF_Colors_DispelSingleSwatch", content)
    singleSwatch:SetSize(120, 16)
    singleSwatch:SetPoint("LEFT", singleLabel, "LEFT", 210, 0)
    local singleTex = singleSwatch:CreateTexture(nil, "ARTWORK"); singleTex:SetAllPoints()
    local function GetSingleDispelColor()
        if EnsureDB and MSUF_DB then
            EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
            local g = MSUF_DB.general
            local r, gg, b = g.dispelBorderColorR, g.dispelBorderColorG, g.dispelBorderColorB
            if type(r) == "number" and type(gg) == "number" and type(b) == "number" then return r, gg, b end
        end
        return 0.25, 0.75, 1.00
    end
    do local r, g, b = GetSingleDispelColor(); singleTex:SetColorTexture(r, g, b) end
    singleSwatch:SetScript("OnClick", function()
        local cr, cg, cb = GetSingleDispelColor()
        OpenColorPicker(cr, cg, cb, function(nr, ng, nb)
            if EnsureDB and MSUF_DB then
                EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
                MSUF_DB.general.dispelBorderColorR = nr
                MSUF_DB.general.dispelBorderColorG = ng
                MSUF_DB.general.dispelBorderColorB = nb
                PushVisualUpdates()
            end
            singleTex:SetColorTexture(nr, ng, nb)
        end)
    end)

    -- Per-type color swatches (Magic, Curse, Disease, Poison, Bleed)
    local DISPEL_TYPE_DEFS = {
        { key = "Magic",   label = "Magic",   defR = 0.20, defG = 0.60, defB = 1.00 },
        { key = "Curse",   label = "Curse",   defR = 0.60, defG = 0.00, defB = 1.00 },
        { key = "Disease", label = "Disease", defR = 0.60, defG = 0.40, defB = 0.00 },
        { key = "Poison",  label = "Poison",  defR = 0.00, defG = 0.60, defB = 0.00 },
        { key = "Bleed",   label = "Bleed",   defR = 0.80, defG = 0.10, defB = 0.10 },
    }
    local typeSwatches = {}
    local prevAnchor = singleLabel
    for i, def in ipairs(DISPEL_TYPE_DEFS) do
        local keyR = "dispelType" .. def.key .. "R"
        local keyG = "dispelType" .. def.key .. "G"
        local keyB = "dispelType" .. def.key .. "B"
        local lbl = content:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
        lbl:SetPoint("TOPLEFT", prevAnchor, "BOTTOMLEFT", 0, -6)
        lbl:SetJustifyH("LEFT"); lbl:SetText(def.label)
        local btn = CreateFrame("Button", "MSUF_Colors_DispelType" .. def.key .. "Swatch", content)
        btn:SetSize(120, 16)
        btn:SetPoint("LEFT", lbl, "LEFT", 210, 0)
        local tex = btn:CreateTexture(nil, "ARTWORK"); tex:SetAllPoints()
        local function getter()
            if EnsureDB and MSUF_DB then
                EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
                local g = MSUF_DB.general
                local r, gg, b = g[keyR], g[keyG], g[keyB]
                if type(r) == "number" and type(gg) == "number" and type(b) == "number" then return r, gg, b end
            end
            return def.defR, def.defG, def.defB
        end
        do local r, g, b = getter(); tex:SetColorTexture(r, g, b) end
        btn:SetScript("OnClick", function()
            local cr, cg, cb = getter()
            OpenColorPicker(cr, cg, cb, function(nr, ng, nb)
                if EnsureDB and MSUF_DB then
                    EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
                    MSUF_DB.general[keyR] = nr; MSUF_DB.general[keyG] = ng; MSUF_DB.general[keyB] = nb
                    PushVisualUpdates()
                end
                tex:SetColorTexture(nr, ng, nb)
            end)
        end)
        typeSwatches[i] = { btn = btn, tex = tex, lbl = lbl, getter = getter }
        prevAnchor = lbl
    end

    -- Visibility: dim unused mode swatches
    local function UpdateDispelVisibility()
        local isSingle = (GetDispelColorMode() ~= "TYPE")
        singleLabel:SetAlpha(isSingle and 1 or 0.35)
        singleSwatch:SetAlpha(isSingle and 1 or 0.35)
        singleSwatch:EnableMouse(isSingle)
        for _, info in ipairs(typeSwatches) do
            info.lbl:SetAlpha(isSingle and 0.35 or 1)
            info.btn:SetAlpha(isSingle and 0.35 or 1)
            info.btn:EnableMouse(not isSingle)
        end
    end
    _G.MSUF_RefreshDispelTypeColorVisibility = UpdateDispelVisibility
    UpdateDispelVisibility()

    -- Reset
    local dispelResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
    dispelResetBtn:SetSize(180, 22)
    dispelResetBtn:SetPoint("TOPLEFT", prevAnchor, "BOTTOMLEFT", 0, -12)
    dispelResetBtn:SetText("Reset Dispel Colors")
    dispelResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("dispel colors", function()
            if EnsureDB and MSUF_DB then
                EnsureDB(); MSUF_DB.general = MSUF_DB.general or {}
                local gen = MSUF_DB.general
                gen.dispelBorderColorR = nil; gen.dispelBorderColorG = nil; gen.dispelBorderColorB = nil
                gen.hlDispelColorMode = nil
                for _, def in ipairs(DISPEL_TYPE_DEFS) do
                    gen["dispelType" .. def.key .. "R"] = nil
                    gen["dispelType" .. def.key .. "G"] = nil
                    gen["dispelType" .. def.key .. "B"] = nil
                end
                PushVisualUpdates()
            end
            do local r, g, b = GetSingleDispelColor(); singleTex:SetColorTexture(r, g, b) end
            for _, info in ipairs(typeSwatches) do
                local r, g, b = info.getter(); info.tex:SetColorTexture(r, g, b)
            end
            UIDropDownMenu_SetSelectedValue(dispelModeDrop, "SINGLE")
            UIDropDownMenu_SetText(dispelModeDrop, "Single color")
            UpdateDispelVisibility()
            if _G.MSUF_PrioRows_Reinit then _G.MSUF_PrioRows_Reinit() end
        end)
    end)

    end -- section 5d (Dispel Colors)

    --------------------------------------------------
    -- Section 6: Castbar Colors
    --------------------------------------------------
    S.sec6Box, S.sec6Body = F.MakeCollapsibleSection(content, 460, "Castbar Colors", false)
    S.sec6Box:SetPoint("TOPLEFT", S.sec5dBox, "BOTTOMLEFT", 0, -6)
    do local content = S.sec6Body

    local castbarSub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    castbarSub:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
    castbarSub:SetWidth(600)
    castbarSub:SetJustifyH("LEFT")
    castbarSub:SetText("Configure colors for interruptible, non-interruptible and interrupt feedback castbars.")

    --------------------------------------------------
    -- Castbar dropdowns
    --------------------------------------------------
    -- Interruptible cast color (custom Color Picker)
    local interruptibleColorLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    interruptibleColorLabel:SetPoint("TOPLEFT", castbarSub, "BOTTOMLEFT", 0, -12)
    interruptibleColorLabel:SetText("Interruptible cast color")

    local interruptibleSwatch = CreateFrame("Button", "MSUF_Colors_InterruptibleCastColorSwatch", content)
    interruptibleSwatch:SetSize(32, 16)
    interruptibleSwatch:SetPoint("TOPLEFT", interruptibleColorLabel, "BOTTOMLEFT", 0, -8)

    S.interruptibleTex = interruptibleSwatch:CreateTexture(nil, "ARTWORK")
    S.interruptibleTex:SetAllPoints()

    interruptibleSwatch:SetScript("OnClick", function()
        local r, g, b = GetInterruptibleCastColor()
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            SetInterruptibleCastColor(nr, ng, nb)
            S.interruptibleTex:SetColorTexture(nr, ng, nb)
        end)
    end)

    do
        local r, g, b = GetInterruptibleCastColor()
        S.interruptibleTex:SetColorTexture(r, g, b)
    end

    local nonInterruptibleColorLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    nonInterruptibleColorLabel:SetPoint("TOPLEFT", interruptibleColorLabel, "BOTTOMLEFT", 0, -32)
    nonInterruptibleColorLabel:SetText("Non-interruptible cast color")

    local nonInterruptibleSwatch = CreateFrame("Button", "MSUF_Colors_NonInterruptibleCastColorSwatch", content)
    nonInterruptibleSwatch:SetSize(32, 16)
    nonInterruptibleSwatch:SetPoint("TOPLEFT", nonInterruptibleColorLabel, "BOTTOMLEFT", 0, -8)

    S.nonInterruptibleTex = nonInterruptibleSwatch:CreateTexture(nil, "ARTWORK")
    S.nonInterruptibleTex:SetAllPoints()

    nonInterruptibleSwatch:SetScript("OnClick", function()
        local r, g, b = GetNonInterruptibleCastColor()
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            SetNonInterruptibleCastColor(nr, ng, nb)
            S.nonInterruptibleTex:SetColorTexture(nr, ng, nb)
        end)
    end)

    do
        local r, g, b = GetNonInterruptibleCastColor()
        S.nonInterruptibleTex:SetColorTexture(r, g, b)
    end

-- Interrupt color (all castbars)
    local interruptFeedbackColorLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    interruptFeedbackColorLabel:SetPoint("TOPLEFT", nonInterruptibleColorLabel, "BOTTOMLEFT", 0, -32)
    interruptFeedbackColorLabel:SetText("Interrupt color (all castbars)")

    local interruptFeedbackSwatch = CreateFrame("Button", "MSUF_Colors_InterruptFeedbackColorSwatch", content)
    interruptFeedbackSwatch:SetSize(32, 16)
    interruptFeedbackSwatch:SetPoint("TOPLEFT", interruptFeedbackColorLabel, "BOTTOMLEFT", 0, -8)

    S.interruptFeedbackTex = interruptFeedbackSwatch:CreateTexture(nil, "ARTWORK")
    S.interruptFeedbackTex:SetAllPoints()

    interruptFeedbackSwatch:SetScript("OnClick", function()
        local r, g, b = GetInterruptFeedbackCastColor()
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            SetInterruptFeedbackCastColor(nr, ng, nb)
            S.interruptFeedbackTex:SetColorTexture(nr, ng, nb)
        end)
    end)

    do
        local r, g, b = GetInterruptFeedbackCastColor()
        S.interruptFeedbackTex:SetColorTexture(r, g, b)
    end

    -- Castbar text color (custom RGB; right-click to reset to Global font color)
    local castbarTextColorLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    castbarTextColorLabel:SetPoint("TOPLEFT", castbarSub, "BOTTOMLEFT", 360, -12)
    castbarTextColorLabel:SetText("Castbar text color")

    local castbarTextSwatch = CreateFrame("Button", "MSUF_Colors_CastbarTextColorSwatch", content)
    castbarTextSwatch:SetSize(32, 16)
    castbarTextSwatch:SetPoint("TOPLEFT", castbarTextColorLabel, "BOTTOMLEFT", 0, -8)

    local castbarTextTex = castbarTextSwatch:CreateTexture(nil, "ARTWORK")
    castbarTextTex:SetAllPoints()

    castbarTextSwatch:RegisterForClicks("LeftButtonUp", "RightButtonUp")
    castbarTextSwatch:SetScript("OnClick", function(_, btn)
        if btn == "RightButton" then
            ResetCastbarTextColorToGlobal()
            local rr, gg, bb = GetCastbarTextColor()
            castbarTextTex:SetColorTexture(rr, gg, bb)
            return
        end

        local r, g, b = GetCastbarTextColor()
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            SetCastbarTextColor(nr, ng, nb)
            castbarTextTex:SetColorTexture(nr, ng, nb)
        end)
    end)

    do
        local r, g, b = GetCastbarTextColor()
        castbarTextTex:SetColorTexture(r, g, b)
    end

-- Castbar border color (Outline; right-click to reset)
local castbarBorderColorLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
castbarBorderColorLabel:SetPoint("TOPLEFT", castbarTextSwatch, "BOTTOMLEFT", 0, -18)
castbarBorderColorLabel:SetText("Castbar border color")

local castbarBorderSwatch = CreateFrame("Button", "MSUF_Colors_CastbarBorderColorSwatch", content)
castbarBorderSwatch:SetSize(32, 16)
castbarBorderSwatch:SetPoint("TOPLEFT", castbarBorderColorLabel, "BOTTOMLEFT", 0, -8)

local castbarBorderTex = castbarBorderSwatch:CreateTexture(nil, "ARTWORK")
castbarBorderTex:SetAllPoints()

castbarBorderSwatch:RegisterForClicks("LeftButtonUp", "RightButtonUp")
castbarBorderSwatch:SetScript("OnClick", function(_, btn)
    if btn == "RightButton" then
        ResetCastbarBorderColor()
        local rr, gg, bb = GetCastbarBorderColor()
        castbarBorderTex:SetColorTexture(rr, gg, bb)
        return
    end

    local r, g, b = GetCastbarBorderColor()
    OpenColorPicker(r, g, b, function(nr, ng, nb)
        SetCastbarBorderColor(nr, ng, nb, 1)
        castbarBorderTex:SetColorTexture(nr, ng, nb)
    end)
end)

do
    local r, g, b = GetCastbarBorderColor()
    castbarBorderTex:SetColorTexture(r, g, b)
end

-- Castbar background color (right-click to reset)
local castbarBgColorLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
castbarBgColorLabel:SetPoint("TOPLEFT", castbarBorderSwatch, "BOTTOMLEFT", 0, -18)
castbarBgColorLabel:SetText("Castbar background color")

local castbarBgSwatch = CreateFrame("Button", "MSUF_Colors_CastbarBgColorSwatch", content)
castbarBgSwatch:SetSize(32, 16)
castbarBgSwatch:SetPoint("TOPLEFT", castbarBgColorLabel, "BOTTOMLEFT", 0, -8)

local castbarBgTex = castbarBgSwatch:CreateTexture(nil, "ARTWORK")
castbarBgTex:SetAllPoints()
S.castbarBgTex = castbarBgTex

castbarBgSwatch:RegisterForClicks("LeftButtonUp", "RightButtonUp")
castbarBgSwatch:SetScript("OnClick", function(_, btn)
    if btn == "RightButton" then
        ResetCastbarBackgroundColor()
        local rr, gg, bb = GetCastbarBackgroundColor()
        castbarBgTex:SetColorTexture(rr, gg, bb)
        return
    end

    local r, g, b = GetCastbarBackgroundColor()
    OpenColorPicker(r, g, b, function(nr, ng, nb)
        SetCastbarBackgroundColor(nr, ng, nb, 1)
        castbarBgTex:SetColorTexture(nr, ng, nb)
    end)
end)

do
    local r, g, b = GetCastbarBackgroundColor()
    castbarBgTex:SetColorTexture(r, g, b)
end

    --------------------------------------------------
    -- Player castbar override (normal casts/channels)
    --------------------------------------------------
    local playerOverrideHeader = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    playerOverrideHeader:SetPoint("TOPLEFT", interruptFeedbackSwatch, "BOTTOMLEFT", 0, -26)
    playerOverrideHeader:SetText("Player castbar override")

    local playerOverrideSub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    playerOverrideSub:SetPoint("TOPLEFT", playerOverrideHeader, "BOTTOMLEFT", 0, -4)
    playerOverrideSub:SetWidth(600)
    playerOverrideSub:SetJustifyH("LEFT")
    playerOverrideSub:SetText("Optional: forces the Player castbar to use Class or Custom color during normal casts. Interrupt feedback still uses 'Interrupt color (all castbars)'.")

    local playerOverrideEnable = CreateFrame("CheckButton", nil, content, "UICheckButtonTemplate")
    playerOverrideEnable:SetPoint("TOPLEFT", playerOverrideSub, "BOTTOMLEFT", 0, -10)
    playerOverrideEnable.text:SetText("Enable Player override")

    local modeLabel = content:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    modeLabel:SetPoint("TOPLEFT", playerOverrideEnable, "BOTTOMLEFT", 0, -10)
    modeLabel:SetText("Mode:")

    local classModeCheck = CreateFrame("CheckButton", nil, content, "UICheckButtonTemplate")
    classModeCheck:SetPoint("LEFT", modeLabel, "RIGHT", 12, 0)
    classModeCheck.text:SetText("Class color")

    local customModeCheck = CreateFrame("CheckButton", nil, content, "UICheckButtonTemplate")
    customModeCheck:SetPoint("LEFT", classModeCheck, "RIGHT", 70, 0)
    customModeCheck.text:SetText("Custom color")

    local customColorLabel = content:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    customColorLabel:SetPoint("LEFT", customModeCheck.text, "RIGHT", 18, 0)
    customColorLabel:SetText("Color:")

    local playerOverrideSwatch = CreateFrame("Button", "MSUF_Colors_PlayerCastbarOverrideSwatch", content)
    playerOverrideSwatch:SetSize(32, 16)
    playerOverrideSwatch:SetPoint("LEFT", customColorLabel, "RIGHT", 8, -1)

    local playerOverrideTex = playerOverrideSwatch:CreateTexture(nil, "ARTWORK")
    playerOverrideTex:SetAllPoints()

    F.UpdatePlayerOverrideControls = function()
        local enabled = GetPlayerCastbarOverrideEnabled()
        local mode = GetPlayerCastbarOverrideMode()

        playerOverrideEnable:SetChecked(enabled)
        F.ApplyToggleGreyout(playerOverrideEnable, enabled)

        classModeCheck:SetChecked(mode == "CLASS")
        customModeCheck:SetChecked(mode == "CUSTOM")

        -- Grey-out OFF state (like main menu): unchecked choice looks disabled but is still clickable.
        if enabled then
            F.ApplyToggleGreyout(classModeCheck, mode == "CLASS")
            F.ApplyToggleGreyout(customModeCheck, mode == "CUSTOM")
        else
            F.ApplyToggleGreyout(classModeCheck, false)
            F.ApplyToggleGreyout(customModeCheck, false)
        end

        if modeLabel then modeLabel:SetAlpha(enabled and 1 or 0.35) end

        classModeCheck:SetEnabled(enabled)
        customModeCheck:SetEnabled(enabled)

        local showCustom = enabled and (mode == "CUSTOM")
        customColorLabel:SetAlpha(showCustom and 1 or 0.35)
        playerOverrideSwatch:SetAlpha(showCustom and 1 or 0.35)
        playerOverrideSwatch:EnableMouse(showCustom)

        local r, g, b = GetPlayerCastbarOverrideColor()
        playerOverrideTex:SetColorTexture(r, g, b)
    end

    playerOverrideEnable:SetScript("OnClick", function(self)
        SetPlayerCastbarOverrideEnabled(self:GetChecked() == true)
        F.UpdatePlayerOverrideControls()
    end)

    classModeCheck:SetScript("OnClick", function()
        if not GetPlayerCastbarOverrideEnabled() then return end
        SetPlayerCastbarOverrideMode("CLASS")
        F.UpdatePlayerOverrideControls()
    end)

    customModeCheck:SetScript("OnClick", function()
        if not GetPlayerCastbarOverrideEnabled() then return end
        SetPlayerCastbarOverrideMode("CUSTOM")
        F.UpdatePlayerOverrideControls()
    end)

    playerOverrideSwatch:SetScript("OnClick", function()
        if not (GetPlayerCastbarOverrideEnabled() and GetPlayerCastbarOverrideMode() == "CUSTOM") then return end
        local r, g, b = GetPlayerCastbarOverrideColor()
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            SetPlayerCastbarOverrideColor(nr, ng, nb)
            playerOverrideTex:SetColorTexture(nr, ng, nb)
        end)
    end)

    F.UpdatePlayerOverrideControls()

    local playerOverrideAnchor = playerOverrideSwatch

    -- Reset button for castbar colors
    local resetCastbarColorsBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
    resetCastbarColorsBtn:SetSize(160, 22)
    resetCastbarColorsBtn:SetPoint("TOPLEFT", modeLabel, "BOTTOMLEFT", 0, -10)
    resetCastbarColorsBtn:SetText("Reset castbar colors")

    resetCastbarColorsBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("castbar", function()
                    EnsureDB()
                    local g = MSUF_DB and MSUF_DB.general
                    if not g then return end

                    -- Interruptible defaults
                    g.castbarInterruptibleR = nil
                    g.castbarInterruptibleG = nil
                    g.castbarInterruptibleB = nil
                    g.castbarInterruptibleColor = "turquoise"

                    -- Non-interruptible defaults
                    g.castbarNonInterruptibleR = nil
                    g.castbarNonInterruptibleG = nil
                    g.castbarNonInterruptibleB = nil
                    g.castbarNonInterruptibleColor = "red"

                    -- Interrupt feedback defaults
                    g.castbarInterruptR = nil
                    g.castbarInterruptG = nil
                    g.castbarInterruptB = nil
                    g.castbarInterruptColor = "red"

                    -- Player override defaults
                    g.playerCastbarOverrideEnabled = false
                    g.playerCastbarOverrideMode = "CLASS"
                    g.playerCastbarOverrideR = 1
                    g.playerCastbarOverrideG = 1
                    g.playerCastbarOverrideB = 1

                    -- Castbar background defaults
                    g.castbarBgR = nil
                    g.castbarBgG = nil
                    g.castbarBgB = nil
                    g.castbarBgA = nil

                    -- Update swatches in the Colors panel
                    if S.interruptibleTex then
                        local r1, g1, b1 = GetInterruptibleCastColor()
                        S.interruptibleTex:SetColorTexture(r1, g1, b1)
                    end
                    if S.nonInterruptibleTex then
                        local r2, g2, b2 = GetNonInterruptibleCastColor()
                        S.nonInterruptibleTex:SetColorTexture(r2, g2, b2)
                    end
                    if S.interruptFeedbackTex then
                        local r3, g3, b3 = GetInterruptFeedbackCastColor()
                        S.interruptFeedbackTex:SetColorTexture(r3, g3, b3)
                    end
                    if S.castbarBgTex then
                        local rb, gb, bb = GetCastbarBackgroundColor()
                        S.castbarBgTex:SetColorTexture(rb, gb, bb)
                    end

                    if F.UpdatePlayerOverrideControls then
                        F.UpdatePlayerOverrideControls()
                    end

                    -- Update override swatch + toggles
                    if playerOverrideTex then
                        local r4, g4, b4 = GetPlayerCastbarOverrideColor()
                        playerOverrideTex:SetColorTexture(r4, g4, b4)
                    end
                    if F.UpdatePlayerOverrideControls then
                        F.UpdatePlayerOverrideControls()
                    end

                    -- Push visuals to active castbars if the helper exists
                    if ns.MSUF_UpdateCastbarVisuals then
                        ns.MSUF_UpdateCastbarVisuals()
                    end

                    if PushVisualUpdates then
                        PushVisualUpdates()
                    end
        end)
    end)

    S.lastControl = resetCastbarColorsBtn

    --------------------------------------------------
    -- Kick Ready Indicator Colors
    --------------------------------------------------
    local kickReadyDivider = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    kickReadyDivider:SetPoint("TOPLEFT", resetCastbarColorsBtn, "BOTTOMLEFT", 0, -16)
    kickReadyDivider:SetText("Interrupt Ready Indicator")

    local kickReadyLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    kickReadyLabel:SetPoint("TOPLEFT", kickReadyDivider, "BOTTOMLEFT", 0, -10)
    kickReadyLabel:SetText("Ready color (kick available)")

    local kickReadySwatch = CreateFrame("Button", "MSUF_Colors_KickReadySwatch", content)
    kickReadySwatch:SetSize(32, 16)
    kickReadySwatch:SetPoint("TOPLEFT", kickReadyLabel, "BOTTOMLEFT", 0, -4)
    local kickReadyTex = kickReadySwatch:CreateTexture(nil, "ARTWORK")
    kickReadyTex:SetAllPoints()

    local function GetKickColor(key, dr, dg, db)
        EnsureDB()
        local g = MSUF_DB and MSUF_DB.general
        local c = g and g[key]
        if c then return tonumber(c["1"]) or dr, tonumber(c["2"]) or dg, tonumber(c["3"]) or db end
        return dr, dg, db
    end

    kickReadySwatch:SetScript("OnClick", function()
        local r, g, b = GetKickColor("kickReadyColor", 0, 1, 0)
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            EnsureDB()
            MSUF_DB.general.kickReadyColor = { ["1"] = nr, ["2"] = ng, ["3"] = nb }
            kickReadyTex:SetColorTexture(nr, ng, nb)
            if PushVisualUpdates then PushVisualUpdates() end
        end)
    end)
    do local r, g, b = GetKickColor("kickReadyColor", 0, 1, 0); kickReadyTex:SetColorTexture(r, g, b) end

    local kickNotReadyLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    kickNotReadyLabel:SetPoint("TOPLEFT", kickReadyLabel, "BOTTOMLEFT", 0, -28)
    kickNotReadyLabel:SetText("Not ready color (kick on cooldown)")

    local kickNotReadySwatch = CreateFrame("Button", "MSUF_Colors_KickNotReadySwatch", content)
    kickNotReadySwatch:SetSize(32, 16)
    kickNotReadySwatch:SetPoint("TOPLEFT", kickNotReadyLabel, "BOTTOMLEFT", 0, -4)
    local kickNotReadyTex = kickNotReadySwatch:CreateTexture(nil, "ARTWORK")
    kickNotReadyTex:SetAllPoints()

    kickNotReadySwatch:SetScript("OnClick", function()
        local r, g, b = GetKickColor("kickNotReadyColor", 1, 0, 0)
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            EnsureDB()
            MSUF_DB.general.kickNotReadyColor = { ["1"] = nr, ["2"] = ng, ["3"] = nb }
            kickNotReadyTex:SetColorTexture(nr, ng, nb)
            if PushVisualUpdates then PushVisualUpdates() end
        end)
    end)
    do local r, g, b = GetKickColor("kickNotReadyColor", 1, 0, 0); kickNotReadyTex:SetColorTexture(r, g, b) end

    end -- section 6

    --------------------------------------------------
    -- Section 7: Mouseover Highlight
    --------------------------------------------------
    S.sec7Box, S.sec7Body = F.MakeCollapsibleSection(content, 280, "Mouseover Highlight", false)
    S.sec7Box:SetPoint("TOPLEFT", S.sec6Box, "BOTTOMLEFT", 0, -6)
    do local content = S.sec7Body

    local mouseoverSub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    mouseoverSub:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
    mouseoverSub:SetWidth(600)
    mouseoverSub:SetJustifyH("LEFT")
    mouseoverSub:SetText("Configure the mouseover highlight border that appears when you hover MSUF unitframes.")

    -- Enable/disable mouseover highlight
    S.highlightEnableCheck = CreateFrame("CheckButton", "MSUF_Colors_HighlightEnableCheck", content, "UICheckButtonTemplate")
    S.highlightEnableCheck:SetPoint("TOPLEFT", mouseoverSub, "BOTTOMLEFT", 0, -12)

    if not S.highlightEnableCheck.text then
        S.highlightEnableCheck.text = S.highlightEnableCheck:CreateFontString(nil, "ARTWORK", "GameFontNormal")
        S.highlightEnableCheck.text:SetPoint("LEFT", S.highlightEnableCheck, "RIGHT", 2, 0)
    end
    S.highlightEnableCheck.text:SetText("Enable mouseover highlight")

    local highlightColorLabel
    local highlightColorSwatch

    F.UpdateHighlightControls = function()
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        local enabled = (MSUF_DB.general.highlightEnabled ~= false)

        if S.highlightEnableCheck then
            S.highlightEnableCheck:SetChecked(enabled)
            F.ApplyToggleGreyout(S.highlightEnableCheck, enabled)
        end

        local a = enabled and 1 or 0.35
        if highlightColorLabel then highlightColorLabel:SetAlpha(a) end
        if highlightColorSwatch then
            highlightColorSwatch:SetAlpha(a)
            highlightColorSwatch:EnableMouse(enabled)
        end
        if S.highlightColorTex then S.highlightColorTex:SetAlpha(a) end
        if type(_G.MSUF_GF_RefreshIndicatorControlStates) == "function" then
            _G.MSUF_GF_RefreshIndicatorControlStates()
        end
    end

    S.highlightEnableCheck:SetScript("OnClick", function(self)
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        MSUF_DB.general.highlightEnabled = self:GetChecked() and true or false
        if F.UpdateHighlightControls then F.UpdateHighlightControls() end
        if UpdateAllHighlightColors then
            UpdateAllHighlightColors()
        end
        if ns and ns.MSUF_FixMouseoverHighlightBindings then
            ns.MSUF_FixMouseoverHighlightBindings()
        end
    end)

    -- Mouseover highlight color (Colorpicker)
    highlightColorLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    highlightColorLabel:SetPoint("TOPLEFT", S.highlightEnableCheck, "BOTTOMLEFT", 0, -12)
    highlightColorLabel:SetText("Mouseover highlight color")

    highlightColorSwatch = CreateFrame("Button", "MSUF_Colors_HighlightColorSwatch", content)
    highlightColorSwatch:SetSize(32, 16)
    highlightColorSwatch:SetPoint("TOPLEFT", highlightColorLabel, "BOTTOMLEFT", 0, -8)

    S.highlightColorTex = highlightColorSwatch:CreateTexture(nil, "ARTWORK")
    S.highlightColorTex:SetAllPoints()

    F.GetHighlightColor = function()
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        local g = MSUF_DB.general

        if type(g.highlightColor) == "table" and g.highlightColor[1] and g.highlightColor[2] and g.highlightColor[3] then
            return g.highlightColor[1], g.highlightColor[2], g.highlightColor[3]
        end

        local key = (type(g.highlightColor) == "string" and g.highlightColor:lower()) or "white"
        local colors = MSUF_FONT_COLORS

        if colors and colors[key] then
            local c = colors[key]
            return c[1], c[2], c[3]
        end

        if colors and colors.white then
            local c = colors.white
            return c[1], c[2], c[3]
        end

        return 1, 1, 1
    end

    F.SetHighlightColor = function(r, g, b)
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        local gdb = MSUF_DB.general

        gdb.highlightColor = { r, g, b }

        if S.highlightColorTex then
            S.highlightColorTex:SetColorTexture(r, g, b)
        end

        if UpdateAllHighlightColors then
            UpdateAllHighlightColors()
        end
        if ns and ns.MSUF_FixMouseoverHighlightBindings then
            ns.MSUF_FixMouseoverHighlightBindings()
        end
    end

    highlightColorSwatch:SetScript("OnClick", function()
        local r, g, b = F.GetHighlightColor()
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            F.SetHighlightColor(nr, ng, nb)
        end)
    end)

    do
        local r, g, b = F.GetHighlightColor()
        S.highlightColorTex:SetColorTexture(r, g, b)
    end

    if F.UpdateHighlightControls then F.UpdateHighlightControls() end

    -- Mouseover highlight is now the lowest control for dynamic height
    S.lastControl = highlightColorSwatch

    -- Boss Target Highlight color (separate from mouseover highlight)
    local bthDivider = content:CreateTexture(nil, "ARTWORK")
    bthDivider:SetHeight(1)
    bthDivider:SetPoint("TOPLEFT", highlightColorSwatch, "BOTTOMLEFT", 0, -14)
    bthDivider:SetPoint("RIGHT", content, "RIGHT", -12, 0)
    bthDivider:SetColorTexture(0.25, 0.25, 0.25, 0.6)

    local bthLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    bthLabel:SetPoint("TOPLEFT", bthDivider, "BOTTOMLEFT", 0, -10)
    bthLabel:SetText("Boss target highlight color")

    local bthSwatch = CreateFrame("Button", "MSUF_Colors_BossTargetHLSwatch", content)
    bthSwatch:SetSize(32, 16)
    bthSwatch:SetPoint("TOPLEFT", bthLabel, "BOTTOMLEFT", 0, -8)

    S.bthColorTex = bthSwatch:CreateTexture(nil, "ARTWORK")
    S.bthColorTex:SetAllPoints()

    F.GetBossTargetHLColor = function()
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        local c = MSUF_DB.general.bossTargetHighlightColor
        if c and c[1] and c[2] and c[3] then
            return c[1], c[2], c[3]
        end
        return 1, 0.82, 0
    end

    F.SetBossTargetHLColor = function(r, g, b)
        EnsureDB()
        MSUF_DB.general = MSUF_DB.general or {}
        MSUF_DB.general.bossTargetHighlightColor = { r, g, b }
        if S.bthColorTex then S.bthColorTex:SetColorTexture(r, g, b) end
        if _G.MSUF_UFCore_RefreshSettingsCache then _G.MSUF_UFCore_RefreshSettingsCache("BTH_COLOR") end
        if _G.MSUF_UpdateBossTargetHighlight then _G.MSUF_UpdateBossTargetHighlight(true) end
    end

    bthSwatch:SetScript("OnClick", function()
        local r, g, b = F.GetBossTargetHLColor()
        OpenColorPicker(r, g, b, function(nr, ng, nb)
            F.SetBossTargetHLColor(nr, ng, nb)
        end)
    end)

    do
        local r, g, b = F.GetBossTargetHLColor()
        S.bthColorTex:SetColorTexture(r, g, b)
    end

    S.lastControl = bthSwatch

    end -- section 7

--------------------------------------------------
-- Section 8: Gameplay
--------------------------------------------------
S.sec8Box, S.sec8Body = F.MakeCollapsibleSection(content, 395, "Gameplay", false)
S.sec8Box:SetPoint("TOPLEFT", S.sec7Box, "BOTTOMLEFT", 0, -6)
do local content = S.sec8Body

local gameplaySub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
gameplaySub:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
gameplaySub:SetWidth(600)
gameplaySub:SetJustifyH("LEFT")
gameplaySub:SetText("Configure colors used by Gameplay overlays (Combat Timer, Combat Enter/Leave text, Crosshair range).")

local combatTimerLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
combatTimerLabel:SetPoint("TOPLEFT", gameplaySub, "BOTTOMLEFT", 0, -12)
combatTimerLabel:SetText("Combat timer text color")

-- Shown when the corresponding Gameplay option is disabled
local combatTimerOffText = content:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
combatTimerOffText:SetPoint("LEFT", combatTimerLabel, "RIGHT", 10, 0)
combatTimerOffText:SetText("Turned Off in Gameplay")
combatTimerOffText:Hide()

local combatTimerSwatch = CreateFrame("Button", "MSUF_Colors_CombatTimerColorSwatch", content)
combatTimerSwatch:SetSize(32, 16)
combatTimerSwatch:SetPoint("TOPLEFT", combatTimerLabel, "BOTTOMLEFT", 0, -8)
local combatTimerTex = combatTimerSwatch:CreateTexture(nil, "ARTWORK")
combatTimerTex:SetAllPoints()

local combatEnterLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
combatEnterLabel:SetPoint("TOPLEFT", combatTimerSwatch, "BOTTOMLEFT", 0, -12)
combatEnterLabel:SetText("Combat Enter text color")

-- Shown when Combat Enter/Leave text is disabled in Gameplay
local combatStateOffText = content:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
combatStateOffText:SetPoint("LEFT", combatEnterLabel, "RIGHT", 10, 0)
combatStateOffText:SetText("Turned Off in Gameplay")
combatStateOffText:Hide()

local combatEnterSwatch = CreateFrame("Button", "MSUF_Colors_CombatEnterColorSwatch", content)
combatEnterSwatch:SetSize(32, 16)
combatEnterSwatch:SetPoint("TOPLEFT", combatEnterLabel, "BOTTOMLEFT", 0, -8)
local combatEnterTex = combatEnterSwatch:CreateTexture(nil, "ARTWORK")
combatEnterTex:SetAllPoints()

local combatLeaveLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
combatLeaveLabel:SetPoint("TOPLEFT", combatEnterSwatch, "BOTTOMLEFT", 0, -12)
combatLeaveLabel:SetText("Combat Leave text color")

local combatLeaveSwatch = CreateFrame("Button", "MSUF_Colors_CombatLeaveColorSwatch", content)
combatLeaveSwatch:SetSize(32, 16)
combatLeaveSwatch:SetPoint("TOPLEFT", combatLeaveLabel, "BOTTOMLEFT", 0, -8)
local combatLeaveTex = combatLeaveSwatch:CreateTexture(nil, "ARTWORK")
combatLeaveTex:SetAllPoints()

local combatColorSyncCheck = CreateFrame("CheckButton", "MSUF_Colors_CombatStateColorSyncCheck", content, "UICheckButtonTemplate")
combatColorSyncCheck:SetPoint("LEFT", combatLeaveLabel, "RIGHT", 16, 0)

if not combatColorSyncCheck.text then
    combatColorSyncCheck.text = combatColorSyncCheck:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    combatColorSyncCheck.text:SetPoint("LEFT", combatColorSyncCheck, "RIGHT", 2, 0)
end
combatColorSyncCheck.text:SetText("Sync")

-- Forward refs so UpdateGameplay* can grey/disable Reset buttons
local combatTimerResetBtn
local combatStateResetBtn
local crosshairResetBtn

F.EnsureGameplayDB = function()
    EnsureDB()
    MSUF_DB.gameplay = MSUF_DB.gameplay or {}
    local g = MSUF_DB.gameplay
    if type(g.combatTimerColor) ~= "table" then
        -- Default matches legacy (white timer text).
        g.combatTimerColor = { 1, 1, 1 }
    end
    if type(g.combatStateEnterColor) ~= "table" then
        g.combatStateEnterColor = { 1, 1, 1 }
    end
    if type(g.combatStateLeaveColor) ~= "table" then
        g.combatStateLeaveColor = { 0.7, 0.7, 0.7 }
    end
    if g.combatStateColorSync == nil then
        g.combatStateColorSync = false
    end
    -- Crosshair range colors (Gameplay crosshair)
    if type(g.crosshairInRangeColor) ~= "table" then
        g.crosshairInRangeColor = { 0, 1, 0 } -- default green
    end
    if type(g.crosshairOutRangeColor) ~= "table" then
        g.crosshairOutRangeColor = { 1, 0, 0 } -- default red
    end
    return g
end

-- Read Gameplay toggles from SavedVariables (Gameplay module defaults are FALSE).
F.IsGameplayToggleEnabled = function(key)
    EnsureDB()
    local gdb = (MSUF_DB and MSUF_DB.gameplay) or {}
    return (gdb[key] == true)
end

F.SetFSAlpha = function(fs, enabled)
    if fs and fs.SetAlpha then
        fs:SetAlpha(enabled and 1 or 0.35)
    end
end

F.SetSwatchEnabled = function(btn, enabled)
    if not btn then return end
    if btn.EnableMouse then btn:EnableMouse(enabled and true or false) end
    if btn.SetAlpha then btn:SetAlpha(enabled and 1 or 0.35) end
end

F.SetButtonEnabled = function(btn, enabled)
    if not btn then return end
    if btn.Enable and btn.Disable then
        if enabled then btn:Enable() else btn:Disable() end
    elseif btn.SetEnabled then
        btn:SetEnabled(enabled and true or false)
    end
    if btn.SetAlpha then btn:SetAlpha(enabled and 1 or 0.35) end
end

F.GetCombatTimerColor = function()
    local g = F.EnsureGameplayDB()
    local t = g.combatTimerColor
    return (t and t[1]) or 1, (t and t[2]) or 1, (t and t[3]) or 1
end

F.GetCombatStateEnterColor = function()
    local g = F.EnsureGameplayDB()
    local t = g.combatStateEnterColor
    return (t and t[1]) or 1, (t and t[2]) or 1, (t and t[3]) or 1
end

F.GetCombatStateLeaveColor = function()
    local g = F.EnsureGameplayDB()
    local t = g.combatStateLeaveColor
    return (t and t[1]) or 0.7, (t and t[2]) or 0.7, (t and t[3]) or 0.7
end

F.GetCrosshairInRangeColor = function()
    local g = F.EnsureGameplayDB()
    local t = g.crosshairInRangeColor
    return (t and t[1]) or 0, (t and t[2]) or 1, (t and t[3]) or 0
end

F.GetCrosshairOutRangeColor = function()
    local g = F.EnsureGameplayDB()
    local t = g.crosshairOutRangeColor
    return (t and t[1]) or 1, (t and t[2]) or 0, (t and t[3]) or 0
end

F.UpdateGameplayCombatColorControls = function()
    local g = F.EnsureGameplayDB()

    -- Feature toggles live in the Gameplay menu; if a feature is OFF there,
    -- the corresponding color controls are greyed out here to avoid confusion.
    local timerOn = F.IsGameplayToggleEnabled("enableCombatTimer")
    local stateOn = F.IsGameplayToggleEnabled("enableCombatStateText")

    if combatTimerOffText then combatTimerOffText:SetShown(not timerOn) end
    if combatStateOffText then combatStateOffText:SetShown(not stateOn) end

    -- Combat Timer swatch
    F.SetFSAlpha(combatTimerLabel, timerOn)
    F.SetSwatchEnabled(combatTimerSwatch, timerOn)
    F.SetButtonEnabled(combatTimerResetBtn, timerOn)

    local tr, tg, tb = F.GetCombatTimerColor()
    if combatTimerTex then
        combatTimerTex:SetColorTexture(tr, tg, tb)
        combatTimerTex:SetAlpha(timerOn and 1 or 0.35)
    end

    -- Combat Enter/Leave swatches
    F.SetFSAlpha(combatEnterLabel, stateOn)
    F.SetSwatchEnabled(combatEnterSwatch, stateOn)
    F.SetButtonEnabled(combatStateResetBtn, stateOn)

    local er, eg, eb = F.GetCombatStateEnterColor()
    local lr, lg, lb = F.GetCombatStateLeaveColor()

    if g.combatStateColorSync then
        lr, lg, lb = er, eg, eb
    end

    if combatEnterTex then
        combatEnterTex:SetColorTexture(er, eg, eb)
        combatEnterTex:SetAlpha(stateOn and 1 or 0.35)
    end

    if combatColorSyncCheck then
        combatColorSyncCheck:SetChecked(g.combatStateColorSync and true or false)
        if stateOn and combatColorSyncCheck.Enable then
            combatColorSyncCheck:Enable()
        elseif combatColorSyncCheck.Disable then
            combatColorSyncCheck:Disable()
        end
        F.ApplyToggleGreyout(combatColorSyncCheck, stateOn)
    end

    -- Leave color is disabled when Sync is enabled (and also when the feature itself is off).
    local leaveEnabled = stateOn and (not g.combatStateColorSync)
    local a = leaveEnabled and 1 or 0.35

    if combatLeaveLabel then combatLeaveLabel:SetAlpha(a) end
    if combatLeaveSwatch then
        combatLeaveSwatch:SetAlpha(a)
        combatLeaveSwatch:EnableMouse(leaveEnabled)
    end
    if combatLeaveTex then
        combatLeaveTex:SetColorTexture(lr, lg, lb)
        combatLeaveTex:SetAlpha(a)
    end
end

F.SetCombatTimerColor = function(r, gCol, bCol)
    local g = F.EnsureGameplayDB()
    g.combatTimerColor = { r, gCol, bCol }
    F.UpdateGameplayCombatColorControls()
    if PushVisualUpdates then PushVisualUpdates() end
    if ns and ns.MSUF_RequestGameplayApply then
        ns.MSUF_RequestGameplayApply()
    end
end

F.SetCombatStateEnterColor = function(r, gCol, bCol)
    local g = F.EnsureGameplayDB()
    g.combatStateEnterColor = { r, gCol, bCol }
    if g.combatStateColorSync then
        g.combatStateLeaveColor = { r, gCol, bCol }
    end
    F.UpdateGameplayCombatColorControls()
    if PushVisualUpdates then PushVisualUpdates() end
    if ns and ns.MSUF_RequestGameplayApply then
        ns.MSUF_RequestGameplayApply()
    end
end

F.SetCombatStateLeaveColor = function(r, gCol, bCol)
    local g = F.EnsureGameplayDB()
    if g.combatStateColorSync then return end
    g.combatStateLeaveColor = { r, gCol, bCol }
    F.UpdateGameplayCombatColorControls()
    if PushVisualUpdates then PushVisualUpdates() end
    if ns and ns.MSUF_RequestGameplayApply then
        ns.MSUF_RequestGameplayApply()
    end
end

-- Reset buttons (Gameplay colors)
F.ResetGameplayCombatTimerColor = function()
    local g = F.EnsureGameplayDB()
    g.combatTimerColor = { 1, 1, 1 }
    F.UpdateGameplayCombatColorControls()
    if PushVisualUpdates then PushVisualUpdates() end
    if ns and ns.MSUF_RequestGameplayApply then
        ns.MSUF_RequestGameplayApply()
    end
end

F.ResetGameplayCombatStateColors = function()
    local g = F.EnsureGameplayDB()
    g.combatStateEnterColor = { 1, 1, 1 }
    if g.combatStateColorSync then
        g.combatStateLeaveColor = { 1, 1, 1 }
    else
        g.combatStateLeaveColor = { 0.7, 0.7, 0.7 }
    end
    F.UpdateGameplayCombatColorControls()
    if PushVisualUpdates then PushVisualUpdates() end
    if ns and ns.MSUF_RequestGameplayApply then
        ns.MSUF_RequestGameplayApply()
    end
end

combatTimerResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
combatTimerResetBtn:SetSize(110, 22)
combatTimerResetBtn:SetPoint("LEFT", combatTimerSwatch, "RIGHT", 12, 0)
combatTimerResetBtn:SetText("Reset")
combatTimerResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("combat timer colors", function()
                F.ResetGameplayCombatTimerColor()
        end)
    end)

combatStateResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
combatStateResetBtn:SetSize(110, 22)
combatStateResetBtn:SetPoint("LEFT", combatEnterSwatch, "RIGHT", 12, 0)
combatStateResetBtn:SetText("Reset")
combatStateResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("combat state colors", function()
                F.ResetGameplayCombatStateColors()
        end)
    end)

combatTimerSwatch:SetScript("OnClick", function()
    local r, gCol, bCol = F.GetCombatTimerColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetCombatTimerColor(nr, ng, nb)
    end)
end)

combatEnterSwatch:SetScript("OnClick", function()
    local r, gCol, bCol = F.GetCombatStateEnterColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetCombatStateEnterColor(nr, ng, nb)
    end)
end)

combatLeaveSwatch:SetScript("OnClick", function()
    local g = F.EnsureGameplayDB()
    if g.combatStateColorSync then return end
    local r, gCol, bCol = F.GetCombatStateLeaveColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetCombatStateLeaveColor(nr, ng, nb)
    end)
end)

combatColorSyncCheck:SetScript("OnClick", function(self)
    local g = F.EnsureGameplayDB()
    g.combatStateColorSync = self:GetChecked() and true or false
    if g.combatStateColorSync then
        local r, gCol, bCol = F.GetCombatStateEnterColor()
        g.combatStateLeaveColor = { r, gCol, bCol }
    end
    F.UpdateGameplayCombatColorControls()
    if PushVisualUpdates then PushVisualUpdates() end
    if ns and ns.MSUF_RequestGameplayApply then
        ns.MSUF_RequestGameplayApply()
    end
end)

-- Crosshair range colors (Gameplay)
local crosshairInLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
crosshairInLabel:SetPoint("TOPLEFT", combatLeaveSwatch, "BOTTOMLEFT", 0, -18)
crosshairInLabel:SetText("Crosshair in-range color")

-- Shown when Crosshair melee-range coloring is disabled in Gameplay
local crosshairOffText = content:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
crosshairOffText:SetPoint("LEFT", crosshairInLabel, "RIGHT", 10, 0)
crosshairOffText:SetText("Turned Off in Gameplay")
crosshairOffText:Hide()

local crosshairInSwatch = CreateFrame("Button", "MSUF_Colors_CrosshairInRangeColorSwatch", content)
crosshairInSwatch:SetSize(32, 16)
crosshairInSwatch:SetPoint("TOPLEFT", crosshairInLabel, "BOTTOMLEFT", 0, -8)
local crosshairInTex = crosshairInSwatch:CreateTexture(nil, "ARTWORK")
crosshairInTex:SetAllPoints()

local crosshairOutLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
crosshairOutLabel:SetPoint("TOPLEFT", crosshairInSwatch, "BOTTOMLEFT", 0, -12)
crosshairOutLabel:SetText("Crosshair out-of-range color")

local crosshairOutSwatch = CreateFrame("Button", "MSUF_Colors_CrosshairOutRangeColorSwatch", content)
crosshairOutSwatch:SetSize(32, 16)
crosshairOutSwatch:SetPoint("TOPLEFT", crosshairOutLabel, "BOTTOMLEFT", 0, -8)
local crosshairOutTex = crosshairOutSwatch:CreateTexture(nil, "ARTWORK")
crosshairOutTex:SetAllPoints()

F.UpdateGameplayCrosshairColorControls = function()

    -- Crosshair range colors only matter when:
    --  1) Crosshair is enabled
    --  2) Melee-range coloring is enabled
    local crosshairOn = F.IsGameplayToggleEnabled("enableCombatCrosshair") and F.IsGameplayToggleEnabled("enableCombatCrosshairMeleeRangeColor")

    if crosshairOffText then crosshairOffText:SetShown(not crosshairOn) end

    F.SetFSAlpha(crosshairInLabel, crosshairOn)
    F.SetFSAlpha(crosshairOutLabel, crosshairOn)
    F.SetSwatchEnabled(crosshairInSwatch, crosshairOn)
    F.SetSwatchEnabled(crosshairOutSwatch, crosshairOn)
    F.SetButtonEnabled(crosshairResetBtn, crosshairOn)

    local ir, ig, ib = F.GetCrosshairInRangeColor()
    local or_, og, ob = F.GetCrosshairOutRangeColor()

    if crosshairInTex then
        crosshairInTex:SetColorTexture(ir, ig, ib)
        crosshairInTex:SetAlpha(crosshairOn and 1 or 0.35)
    end
    if crosshairOutTex then
        crosshairOutTex:SetColorTexture(or_, og, ob)
        crosshairOutTex:SetAlpha(crosshairOn and 1 or 0.35)
    end
end

F.SetCrosshairInRangeColor = function(r, gCol, bCol)
    local g = F.EnsureGameplayDB()
    g.crosshairInRangeColor = { r, gCol, bCol }
    F.UpdateGameplayCrosshairColorControls()
    if PushVisualUpdates then PushVisualUpdates() end
    if ns and ns.MSUF_RequestGameplayApply then
        ns.MSUF_RequestGameplayApply()
    end
end

F.SetCrosshairOutRangeColor = function(r, gCol, bCol)
    local g = F.EnsureGameplayDB()
    g.crosshairOutRangeColor = { r, gCol, bCol }
    F.UpdateGameplayCrosshairColorControls()
    if PushVisualUpdates then PushVisualUpdates() end
    if ns and ns.MSUF_RequestGameplayApply then
        ns.MSUF_RequestGameplayApply()
    end
end

-- Reset buttons (Crosshair range colors)
F.ResetGameplayCrosshairColors = function()
    local g = F.EnsureGameplayDB()
    g.crosshairInRangeColor = { 0, 1, 0 }
    g.crosshairOutRangeColor = { 1, 0, 0 }
    F.UpdateGameplayCrosshairColorControls()
    if PushVisualUpdates then PushVisualUpdates() end
    if ns and ns.MSUF_RequestGameplayApply then
        ns.MSUF_RequestGameplayApply()
    end
end

crosshairResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
crosshairResetBtn:SetSize(110, 22)
crosshairResetBtn:SetPoint("LEFT", crosshairInSwatch, "RIGHT", 12, 0)
crosshairResetBtn:SetText("Reset")
crosshairResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("crosshair range colors", function()
                F.ResetGameplayCrosshairColors()
        end)
    end)

crosshairInSwatch:SetScript("OnClick", function()
    local r, gCol, bCol = F.GetCrosshairInRangeColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetCrosshairInRangeColor(nr, ng, nb)
    end)
end)

crosshairOutSwatch:SetScript("OnClick", function()
    local r, gCol, bCol = F.GetCrosshairOutRangeColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetCrosshairOutRangeColor(nr, ng, nb)
    end)
end)

-- Initialize swatches + enable states
F.UpdateGameplayCombatColorControls()
F.UpdateGameplayCrosshairColorControls()

-- Gameplay section is now the lowest control for dynamic height
S.lastControl = crosshairOutSwatch

end -- section 8

--------------------------------------------------
-- Section 9: Power Bar Colors
--------------------------------------------------
S.sec9Box, S.sec9Body = F.MakeCollapsibleSection(content, 100, "Power Bar Colors", false)
S.sec9Box:SetPoint("TOPLEFT", S.sec8Box, "BOTTOMLEFT", 0, -6)
do local content = S.sec9Body

local powerSub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
powerSub:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
powerSub:SetWidth(600)
powerSub:SetJustifyH("LEFT")
powerSub:SetText("Configure custom colors for power resources used by MSUF power bars.")

local powerTypeDrop = (_G.MSUF_CreateStyledDropdown and _G.MSUF_CreateStyledDropdown("MSUF_Colors_PowerTypeDropdown", content) or CreateFrame("Frame", "MSUF_Colors_PowerTypeDropdown", content, "UIDropDownMenuTemplate"))
powerTypeDrop:SetPoint("TOPLEFT", powerSub, "BOTTOMLEFT", -16, -8)
UIDropDownMenu_SetWidth(powerTypeDrop, 220)
MSUF_ExpandDropdownClickArea(powerTypeDrop)

local powerColorSwatch = CreateFrame("Button", "MSUF_Colors_PowerColorSwatch", content)
powerColorSwatch:SetSize(32, 16)
powerColorSwatch:SetPoint("LEFT", powerTypeDrop, "RIGHT", 18, 2)
local powerColorTex = powerColorSwatch:CreateTexture(nil, "ARTWORK")
powerColorTex:SetAllPoints()

local powerColorResetBtn = CreateFrame("Button", "MSUF_Colors_PowerColorResetBtn", content, "UIPanelButtonTemplate")
powerColorResetBtn:SetText("Reset")
powerColorResetBtn:SetSize(70, 18)
powerColorResetBtn:SetPoint("LEFT", powerColorSwatch, "RIGHT", 10, 0)

-- Common power tokens (keep simple, but cover modern classes)
local POWER_TOKEN_OPTIONS = {
    { token = "MANA",        label = "Mana" },
    { token = "RAGE",        label = "Rage" },
    { token = "ENERGY",      label = "Energy" },
    { token = "FOCUS",       label = "Focus" },
    { token = "RUNIC_POWER", label = "Runic Power" },
    { token = "INSANITY",    label = "Insanity" },
    { token = "FURY",        label = "Fury" },
    { token = "PAIN",        label = "Pain" },
    { token = "ESSENCE",     label = "Essence" },
}

F.EnsurePowerColorsDB = function()
    EnsureDB()
    MSUF_DB.general = MSUF_DB.general or {}
    local g = MSUF_DB.general
    if type(g.powerColorOverrides) ~= "table" then
        g.powerColorOverrides = {}
    end
    return g
end

F.GetDefaultPowerColorForToken = function(token)
    local col = (PowerBarColor and token and PowerBarColor[token]) or nil
    if type(col) == "table" then
        local r = col.r or col[1]
        local g = col.g or col[2]
        local b = col.b or col[3]
        if type(r) == "number" and type(g) == "number" and type(b) == "number" then
            return r, g, b
        end
    end
    return 0.8, 0.8, 0.8
end

F.GetEffectivePowerColorForToken = function(token)
    local g = (MSUF_DB and MSUF_DB.general) or nil
    local ov = g and g.powerColorOverrides
    local t = (type(ov) == "table" and token) and ov[token] or nil
    if type(t) == "table" then
        local r = t[1] or t.r
        local gg = t[2] or t.g
        local b = t[3] or t.b
        if type(r) == "number" and type(gg) == "number" and type(b) == "number" then
            return r, gg, b, true
        end
    end
    local dr, dg, db = F.GetDefaultPowerColorForToken(token)
    return dr, dg, db, false
end

F.UpdatePowerColorControls = function()
    local token = powerTypeDrop._msufSelectedToken or "MANA"
    local r, gCol, bCol, hasOverride = F.GetEffectivePowerColorForToken(token)
    if powerColorTex then
        powerColorTex:SetColorTexture(r, gCol, bCol)
    end
    if powerColorResetBtn then
        powerColorResetBtn:SetEnabled(hasOverride)
        powerColorResetBtn:SetAlpha(hasOverride and 1 or 0.35)
    end
end

F.PowerTypeDropdown_Initialize = function(self, level)
    local selected = powerTypeDrop._msufSelectedToken or "MANA"
    for _, opt in ipairs(POWER_TOKEN_OPTIONS) do
        local info = UIDropDownMenu_CreateInfo()
        info.text  = opt.label
        info.value = opt.token
        info.func  = function()
            powerTypeDrop._msufSelectedToken = opt.token
            UIDropDownMenu_SetSelectedValue(powerTypeDrop, opt.token)
            UIDropDownMenu_SetText(powerTypeDrop, opt.label)
            F.UpdatePowerColorControls()
        end
        info.checked = (opt.token == selected)
        UIDropDownMenu_AddButton(info, level)
    end
end

UIDropDownMenu_Initialize(powerTypeDrop, F.PowerTypeDropdown_Initialize)
powerTypeDrop._msufSelectedToken = powerTypeDrop._msufSelectedToken or "MANA"
UIDropDownMenu_SetSelectedValue(powerTypeDrop, powerTypeDrop._msufSelectedToken)
-- Set initial text
do
    local txtLabel = "Mana"
    for _, opt in ipairs(POWER_TOKEN_OPTIONS) do
        if opt.token == powerTypeDrop._msufSelectedToken then
            txtLabel = opt.label
            break
        end
    end
    UIDropDownMenu_SetText(powerTypeDrop, txtLabel)
end

powerColorSwatch:SetScript("OnClick", function()
    local token = powerTypeDrop._msufSelectedToken or "MANA"
    local r, gCol, bCol = F.GetEffectivePowerColorForToken(token)
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        local g = F.EnsurePowerColorsDB()
        g.powerColorOverrides[token] = { nr, ng, nb }
        F.UpdatePowerColorControls()
        PushVisualUpdates()
    end)
end)

powerColorResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("power colors", function()
                local token = powerTypeDrop._msufSelectedToken or "MANA"
                F.EnsurePowerColorsDB()
                if MSUF_DB and MSUF_DB.general and type(MSUF_DB.general.powerColorOverrides) == "table" then
                    MSUF_DB.general.powerColorOverrides[token] = nil
                end
                F.UpdatePowerColorControls()
                PushVisualUpdates()
        end)
    end)

F.UpdatePowerColorControls()

-- Power colors is now the lowest control for dynamic height
S.lastControl = powerColorResetBtn

end -- section 9

--------------------------------------------------
-- Section 10: Class Power Colors
--------------------------------------------------
S.sec10Box, S.sec10Body = F.MakeCollapsibleSection(content, 292, "Class Power Colors", false)
S.sec10Box:SetPoint("TOPLEFT", S.sec9Box, "BOTTOMLEFT", 0, -6)
do local content = S.sec10Body

local cpColSub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
cpColSub:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
cpColSub:SetWidth(600)
cpColSub:SetJustifyH("LEFT")
cpColSub:SetText("Configure colors for secondary resource bars: Combo Points, Holy Power, Soul Shards, Chi, Runes, Arcane Charges, Essence, Soul Fragments (DH), Maelstrom (Enh/Ele), Stagger (BrM), Insanity (Shadow), Whirlwind (Fury), Tip of the Spear (SV), Ebon Might (Aug), Eclipse + Prediction (Balance).")

local cpColTypeDrop = (_G.MSUF_CreateStyledDropdown and _G.MSUF_CreateStyledDropdown("MSUF_Colors_ClassPowerTypeDropdown", content) or CreateFrame("Frame", "MSUF_Colors_ClassPowerTypeDropdown", content, "UIDropDownMenuTemplate"))
cpColTypeDrop:SetPoint("TOPLEFT", cpColSub, "BOTTOMLEFT", -16, -8)
UIDropDownMenu_SetWidth(cpColTypeDrop, 260)
MSUF_ExpandDropdownClickArea(cpColTypeDrop)

local cpColSwatch = CreateFrame("Button", "MSUF_Colors_ClassPowerColorSwatch", content)
cpColSwatch:SetSize(32, 16)
cpColSwatch:SetPoint("LEFT", cpColTypeDrop, "RIGHT", 18, 2)
local cpColTex = cpColSwatch:CreateTexture(nil, "ARTWORK")
cpColTex:SetAllPoints()

local cpColResetBtn = CreateFrame("Button", "MSUF_Colors_ClassPowerColorResetBtn", content, "UIPanelButtonTemplate")
cpColResetBtn:SetText("Reset")
cpColResetBtn:SetSize(70, 18)
cpColResetBtn:SetPoint("LEFT", cpColSwatch, "RIGHT", 10, 0)

local cpColBgLabel = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
cpColBgLabel:SetPoint("TOPLEFT", cpColTypeDrop, "BOTTOMLEFT", 16, -24)
cpColBgLabel:SetText("Background")

local cpColBgSwatch = CreateFrame("Button", "MSUF_Colors_ClassPowerBgColorSwatch", content)
cpColBgSwatch:SetSize(32, 16)
cpColBgSwatch:SetPoint("LEFT", cpColBgLabel, "RIGHT", 10, 0)
local cpColBgTex = cpColBgSwatch:CreateTexture(nil, "ARTWORK")
cpColBgTex:SetAllPoints()

local cpColBgResetBtn = CreateFrame("Button", "MSUF_Colors_ClassPowerBgColorResetBtn", content, "UIPanelButtonTemplate")
cpColBgResetBtn:SetText("Reset")
cpColBgResetBtn:SetSize(70, 18)
cpColBgResetBtn:SetPoint("LEFT", cpColBgSwatch, "RIGHT", 10, 0)

local cpSlotPanel = CreateFrame("Frame", nil, content)
cpSlotPanel:SetPoint("TOPLEFT", cpColBgLabel, "BOTTOMLEFT", 0, -24)
cpSlotPanel:SetSize(620, 72)

local cpSlotLabel = cpSlotPanel:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
cpSlotLabel:SetPoint("TOPLEFT", cpSlotPanel, "TOPLEFT", 0, 0)
cpSlotLabel:SetText("Combo point slot colors")

local cpSlotModeDrop = (_G.MSUF_CreateStyledDropdown and _G.MSUF_CreateStyledDropdown("MSUF_Colors_CPComboPointModeDropdown", cpSlotPanel) or CreateFrame("Frame", "MSUF_Colors_CPComboPointModeDropdown", cpSlotPanel, "UIDropDownMenuTemplate"))
cpSlotModeDrop:SetPoint("LEFT", cpSlotLabel, "RIGHT", 12, 1)
UIDropDownMenu_SetWidth(cpSlotModeDrop, 140)
MSUF_ExpandDropdownClickArea(cpSlotModeDrop)

local cpSlotResetBtn = CreateFrame("Button", "MSUF_Colors_CPComboPointSlotsResetBtn", cpSlotPanel, "UIPanelButtonTemplate")
cpSlotResetBtn:SetText("Reset slots")
cpSlotResetBtn:SetSize(92, 18)
cpSlotResetBtn:SetPoint("LEFT", cpSlotModeDrop, "RIGHT", 12, 2)

local cpSlotSwatches = {}

-- Class power token options (secondary resources)
local CP_TOKEN_OPTIONS = {
    -- ── Standard segmented ──
    { token = "COMBO_POINTS",   label = "Combo Points" },
    { token = "HOLY_POWER",     label = "Holy Power" },
    { token = "SOUL_SHARDS",    label = "Soul Shards" },
    { token = "CHI",            label = "Chi" },
    { token = "ARCANE_CHARGES", label = "Arcane Charges" },
    { token = "RUNES",          label = "Runes" },
    { token = "ESSENCE",        label = "Essence" },
    { token = "CHARGED",        label = "Empowered (Charged)" },
    -- ── New: aura-based class powers ──
    { token = "SOUL_FRAGMENTS",      label = "Soul Fragments (DH)" },
    { token = "SOUL_FRAGMENTS_META", label = "Soul Fragments \124cFF9933EE(Void Meta)\124r" },
    { token = "MAELSTROM",           label = "Maelstrom Weapon (Enh)" },
    { token = "MAELSTROM_ABOVE_5",  label = "Maelstrom Weapon \124cFFFF8000(5+ Spender Ready)\124r" },
    -- ── Balance Druid: Astral Power + Eclipse ──
    { token = "ASTRAL_POWER",   label = "Astral Power (Balance)" },
    { token = "AP_PREDICTION",  label = "Astral Power \124cFF7799CC(Prediction Overlay)\124r" },
    { token = "ECLIPSE_SOLAR",  label = "Eclipse \124cFFD18F3F(Solar)\124r" },
    { token = "ECLIPSE_LUNAR",  label = "Eclipse \124cFF697ED1(Lunar)\124r" },
    { token = "ECLIPSE_CA",     label = "Eclipse \124cFF4DFF6D(Celestial Alignment)\124r" },
    -- ── Stagger (Brewmaster Monk) ──
    { token = "STAGGER_GREEN",  label = "Stagger \124cFF85FF85(Light)\124r" },
    { token = "STAGGER_YELLOW", label = "Stagger \124cFFFFFAB8(Moderate)\124r" },
    { token = "STAGGER_RED",    label = "Stagger \124cFFFF6B6B(Heavy)\124r" },
    -- ── DH Vengeance ──
    { token = "SOUL_FRAGMENTS_VENG", label = "Soul Fragments \124cFF570B76(Vengeance)\124r" },
    -- ── Continuous bars ──
    { token = "INSANITY",       label = "Insanity (Shadow)" },
    { token = "MAELSTROM_POWER", label = "Maelstrom Power (Ele)" },
    -- ── Spell Trackers ──
    { token = "WHIRLWIND",      label = "Whirlwind (Fury)" },
    { token = "TIP_OF_THE_SPEAR", label = "Tip of the Spear (SV)" },
    { token = "ICICLES",        label = "Icicles (Frost Mage)" },
    -- ── Timer Bar ──
    { token = "EBON_MIGHT",     label = "Ebon Might (Aug)" },
    -- ── Text ──
    { token = "RESOURCE_TEXT",  label = "Resource Text" },
}

local CP_SLOT_TOKENS = {
    "COMBO_POINTS_1", "COMBO_POINTS_2", "COMBO_POINTS_3", "COMBO_POINTS_4",
    "COMBO_POINTS_5", "COMBO_POINTS_6", "COMBO_POINTS_7",
}
local CP_SLOT_DEFAULTS = {
    COMBO_POINTS_1 = { 0.00, 0.95, 1.00 },
    COMBO_POINTS_2 = { 0.00, 0.95, 1.00 },
    COMBO_POINTS_3 = { 1.00, 1.00, 0.00 },
    COMBO_POINTS_4 = { 1.00, 1.00, 0.00 },
    COMBO_POINTS_5 = { 1.00, 1.00, 0.00 },
    COMBO_POINTS_6 = { 1.00, 0.05, 0.05 },
    COMBO_POINTS_7 = { 1.00, 0.05, 0.05 },
}
local CP_SLOT_MODE_LABELS = {
    default = "Resource color",
    ramp = "Combo ramp",
    custom = "Custom slots",
}

F.EnsureClassPowerColorsDB = function()
    EnsureDB()
    MSUF_DB.bars = MSUF_DB.bars or {}
    if MSUF_DB.bars.classPowerComboPointColorMode == nil then
        MSUF_DB.bars.classPowerComboPointColorMode = "default"
    end
    MSUF_DB.general = MSUF_DB.general or {}
    local g = MSUF_DB.general
    if type(g.classPowerColorOverrides) ~= "table" then
        g.classPowerColorOverrides = {}
    end
    if type(g.classPowerBgColorOverrides) ~= "table" then
        g.classPowerBgColorOverrides = {}
    end
    return g
end

F.GetDefaultClassPowerColor = function(token)
    -- Charged/empowered has a built-in default (not in PowerBarColor)
    if token == "CHARGED" then
        return 0.60, 0.20, 0.80  -- MidnightRogueBars purple
    end
    local slotDefault = CP_SLOT_DEFAULTS[token]
    if slotDefault then
        return slotDefault[1], slotDefault[2], slotDefault[3]
    end
    -- Resource text: default = global font color from MSUF settings
    if token == "RESOURCE_TEXT" then
        if type(_G.MSUF_GetGlobalFontSettings) == "function" then
            local _, _, fr, fg, fb = _G.MSUF_GetGlobalFontSettings()
            if type(fr) == "number" then return fr, fg, fb end
        end
        return 1, 1, 1
    end
    -- DH Devourer: Soul Fragments (normal green)
    if token == "SOUL_FRAGMENTS" then
        return 0.00, 0.80, 0.00
    end
    -- DH Devourer: Void Metamorphosis purple
    if token == "SOUL_FRAGMENTS_META" then
        return 0.60, 0.20, 0.93
    end
    -- Enhancement Shaman: Maelstrom Weapon (use Maelstrom power bar color)
    if token == "MAELSTROM" then
        local col = PowerBarColor and PowerBarColor["MAELSTROM"]
        if type(col) == "table" then
            local r = col.r or col[1]
            local g = col.g or col[2]
            local b = col.b or col[3]
            if type(r) == "number" then return r, g, b end
        end
        return 0.00, 0.50, 1.00  -- blue fallback
    end
    -- Enhancement Shaman: Maelstrom Weapon 5+ stacks (spender empowered threshold)
    if token == "MAELSTROM_ABOVE_5" then return 1.00, 0.50, 0.00 end
    -- Balance Druid: Astral Power (Blizzard LunarPower blue)
    if token == "ASTRAL_POWER" then
        local col = PowerBarColor and PowerBarColor["LUNAR_POWER"]
        if type(col) == "table" then
            local r = col.r or col[1]
            local g = col.g or col[2]
            local b = col.b or col[3]
            if type(r) == "number" then return r, g, b end
        end
        return 0.30, 0.52, 0.90  -- MCR default
    end
    -- Balance Druid: Prediction overlay (inherits Astral Power default)
    if token == "AP_PREDICTION" then
        local col = PowerBarColor and PowerBarColor["LUNAR_POWER"]
        if type(col) == "table" then
            local r = col.r or col[1]
            local g = col.g or col[2]
            local b = col.b or col[3]
            if type(r) == "number" then return r, g, b end
        end
        return 0.30, 0.52, 0.90  -- same as Astral Power
    end
    -- Balance Druid: Eclipse colors (MCR/Shrom defaults)
    if token == "ECLIPSE_SOLAR" then return 0.82, 0.56, 0.25 end
    if token == "ECLIPSE_LUNAR" then return 0.41, 0.49, 0.82 end
    if token == "ECLIPSE_CA"    then return 0.30, 1.00, 0.43 end
    -- Stagger: Brewmaster Monk (oUF threshold colors)
    if token == "STAGGER_GREEN" then
        return 0.52, 1.00, 0.52
    end
    if token == "STAGGER_YELLOW" then
        return 1.00, 0.98, 0.72
    end
    if token == "STAGGER_RED" then
        return 1.00, 0.42, 0.42
    end
    -- DH Vengeance: Soul Fragments (MCR default — dark purple)
    if token == "SOUL_FRAGMENTS_VENG" then return 0.34, 0.06, 0.46 end
    -- Shadow Priest: Insanity (Blizzard PowerBarColor or MCR default)
    if token == "INSANITY" then
        local col = PowerBarColor and PowerBarColor["INSANITY"]
        if type(col) == "table" then
            local r = col.r or col[1]
            local g = col.g or col[2]
            local b = col.b or col[3]
            if type(r) == "number" then return r, g, b end
        end
        return 0.44, 0.00, 0.74  -- MCR default purple
    end
    -- Ele Shaman: Maelstrom Power (Blizzard PowerBarColor or MCR default)
    if token == "MAELSTROM_POWER" then
        local col = PowerBarColor and PowerBarColor["MAELSTROM"]
        if type(col) == "table" then
            local r = col.r or col[1]
            local g = col.g or col[2]
            local b = col.b or col[3]
            if type(r) == "number" then return r, g, b end
        end
        return 0.00, 0.50, 1.00  -- MCR default blue
    end
    -- Warrior Fury: Whirlwind (MCR default — green)
    if token == "WHIRLWIND" then return 0.20, 0.80, 0.20 end
    -- Hunter SV: Tip of the Spear (MCR default — lime-green)
    if token == "TIP_OF_THE_SPEAR" then return 0.60, 0.80, 0.20 end
    -- Mage Frost: Icicles (MCR default — ice blue)
    if token == "ICICLES" then return 0.50, 0.80, 1.00 end
    -- Evoker Aug: Ebon Might (MCR default — teal)
    if token == "EBON_MIGHT" then return 0.40, 0.80, 0.60 end
    -- Look up in PowerBarColor
    local col = (PowerBarColor and token and PowerBarColor[token]) or nil
    if type(col) == "table" then
        local r = col.r or col[1]
        local g = col.g or col[2]
        local b = col.b or col[3]
        if type(r) == "number" and type(g) == "number" and type(b) == "number" then
            return r, g, b
        end
    end
    return 0.8, 0.8, 0.8
end

F.GetEffectiveClassPowerColor = function(token)
    local g = (MSUF_DB and MSUF_DB.general) or nil
    local ov = g and g.classPowerColorOverrides
    local t = (type(ov) == "table" and token) and ov[token] or nil
    if type(t) == "table" then
        local r = t[1] or t.r
        local gg = t[2] or t.g
        local b = t[3] or t.b
        if type(r) == "number" and type(gg) == "number" and type(b) == "number" then
            return r, gg, b, true
        end
    end
    local dr, dg, db = F.GetDefaultClassPowerColor(token)
    return dr, dg, db, false
end

F.GetEffectiveClassPowerBgColor = function(token)
    local g = (MSUF_DB and MSUF_DB.general) or nil
    local ov = g and g.classPowerBgColorOverrides
    local t = (type(ov) == "table" and token) and ov[token] or nil
    if type(t) == "table" then
        local r = t[1] or t.r
        local gg = t[2] or t.g
        local b = t[3] or t.b
        if type(r) == "number" and type(gg) == "number" and type(b) == "number" then
            return r, gg, b, true
        end
    end
    return 0, 0, 0, false
end

local function GetComboPointColorMode()
    local b = MSUF_DB and MSUF_DB.bars
    local mode = b and b.classPowerComboPointColorMode or "default"
    if mode ~= "ramp" and mode ~= "custom" then mode = "default" end
    return mode
end

local function RefreshComboPointModeDropdown()
    local mode = GetComboPointColorMode()
    UIDropDownMenu_SetSelectedValue(cpSlotModeDrop, mode)
    UIDropDownMenu_SetText(cpSlotModeDrop, CP_SLOT_MODE_LABELS[mode] or CP_SLOT_MODE_LABELS.default)
end

local function RefreshComboPointSlotSwatches()
    local anyOverride = false
    local mode = GetComboPointColorMode()
    for i = 1, #CP_SLOT_TOKENS do
        local token = CP_SLOT_TOKENS[i]
        local sw = cpSlotSwatches[i]
        local r, gCol, bCol, hasOverride
        if mode == "custom" then
            r, gCol, bCol, hasOverride = F.GetEffectiveClassPowerColor(token)
        else
            r, gCol, bCol = F.GetDefaultClassPowerColor(token)
            local _r, _g, _b, slotOverride = F.GetEffectiveClassPowerColor(token)
            hasOverride = slotOverride
        end
        if sw and sw.tex then sw.tex:SetColorTexture(r, gCol, bCol) end
        if sw and sw.SetAlpha then sw:SetAlpha(mode == "default" and 0.65 or 1) end
        anyOverride = anyOverride or hasOverride
    end
    if cpSlotResetBtn then
        cpSlotResetBtn:SetEnabled(anyOverride)
        cpSlotResetBtn:SetAlpha(anyOverride and 1 or 0.35)
    end
end

local function ApplyComboPointColorMode(mode)
    if mode ~= "ramp" and mode ~= "custom" then mode = "default" end
    F.EnsureClassPowerColorsDB()
    MSUF_DB.bars.classPowerComboPointColorMode = mode
    RefreshComboPointModeDropdown()
    if F.UpdateClassPowerColorControls then
        F.UpdateClassPowerColorControls()
    end
    if _G.MSUF_ClassPower_InvalidateColors then
        _G.MSUF_ClassPower_InvalidateColors()
    end
    PushVisualUpdates()
end

for i = 1, #CP_SLOT_TOKENS do
    local idx = i
    local sw = CreateFrame("Button", "MSUF_Colors_CPComboPointSlot" .. i .. "Swatch", cpSlotPanel)
    sw:SetSize(32, 18)
    if i == 1 then
        sw:SetPoint("TOPLEFT", cpSlotLabel, "BOTTOMLEFT", 0, -16)
    else
        sw:SetPoint("LEFT", cpSlotSwatches[i - 1], "RIGHT", 8, 0)
    end
    local tex = sw:CreateTexture(nil, "ARTWORK")
    tex:SetAllPoints()
    sw.tex = tex
    local num = sw:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    num:SetPoint("CENTER", sw, "CENTER", 0, 0)
    num:SetText(tostring(idx))
    num:SetTextColor(1, 1, 1, 1)
    num:SetShadowColor(0, 0, 0, 1)
    num:SetShadowOffset(1, -1)
    sw:SetScript("OnClick", function()
        local token = CP_SLOT_TOKENS[idx]
        local r, gCol, bCol
        if GetComboPointColorMode() == "custom" then
            r, gCol, bCol = F.GetEffectiveClassPowerColor(token)
        else
            r, gCol, bCol = F.GetDefaultClassPowerColor(token)
        end
        OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
            local g = F.EnsureClassPowerColorsDB()
            g.classPowerColorOverrides[token] = { nr, ng, nb }
            MSUF_DB.bars.classPowerComboPointColorMode = "custom"
            RefreshComboPointModeDropdown()
            F.UpdateClassPowerColorControls()
            if _G.MSUF_ClassPower_InvalidateColors then
                _G.MSUF_ClassPower_InvalidateColors()
            end
            PushVisualUpdates()
        end)
    end)
    cpSlotSwatches[i] = sw
end

local function CPComboPointModeDropdown_Init(self, level)
    local selected = GetComboPointColorMode()
    local modes = {
        { key = "default", label = CP_SLOT_MODE_LABELS.default },
        { key = "ramp",    label = CP_SLOT_MODE_LABELS.ramp },
        { key = "custom",  label = CP_SLOT_MODE_LABELS.custom },
    }
    for _, opt in ipairs(modes) do
        local modeKey = opt.key
        local info = UIDropDownMenu_CreateInfo()
        info.text = opt.label
        info.value = modeKey
        info.func = function()
            ApplyComboPointColorMode(modeKey)
        end
        info.checked = (modeKey == selected)
        UIDropDownMenu_AddButton(info, level)
    end
end

UIDropDownMenu_Initialize(cpSlotModeDrop, CPComboPointModeDropdown_Init)
RefreshComboPointModeDropdown()

cpSlotResetBtn:SetScript("OnClick", function()
    MSUF_ConfirmColorReset("combo point slot", function()
        local g = F.EnsureClassPowerColorsDB()
        for i = 1, #CP_SLOT_TOKENS do
            g.classPowerColorOverrides[CP_SLOT_TOKENS[i]] = nil
        end
        F.UpdateClassPowerColorControls()
        if _G.MSUF_ClassPower_InvalidateColors then
            _G.MSUF_ClassPower_InvalidateColors()
        end
        PushVisualUpdates()
    end)
end)

F.UpdateClassPowerColorControls = function()
    local token = cpColTypeDrop._msufSelectedToken or "COMBO_POINTS"
    local r, gCol, bCol, hasOverride = F.GetEffectiveClassPowerColor(token)
    if cpColTex then
        cpColTex:SetColorTexture(r, gCol, bCol)
    end
    if cpColResetBtn then
        cpColResetBtn:SetEnabled(hasOverride)
        cpColResetBtn:SetAlpha(hasOverride and 1 or 0.35)
    end
    local br, bg, bb, hasBgOverride = F.GetEffectiveClassPowerBgColor(token)
    if cpColBgTex then
        cpColBgTex:SetColorTexture(br, bg, bb)
    end
    if cpColBgResetBtn then
        cpColBgResetBtn:SetEnabled(hasBgOverride)
        cpColBgResetBtn:SetAlpha(hasBgOverride and 1 or 0.35)
    end
    local showSlots = (token == "COMBO_POINTS")
    if cpSlotPanel then
        cpSlotPanel:SetShown(showSlots)
    end
    if showSlots then
        RefreshComboPointModeDropdown()
        RefreshComboPointSlotSwatches()
    end
end

F.ClassPowerTypeDropdown_Init = function(self, level)
    local selected = cpColTypeDrop._msufSelectedToken or "COMBO_POINTS"
    for _, opt in ipairs(CP_TOKEN_OPTIONS) do
        local info = UIDropDownMenu_CreateInfo()
        info.text  = opt.label
        info.value = opt.token
        info.func  = function()
            cpColTypeDrop._msufSelectedToken = opt.token
            UIDropDownMenu_SetSelectedValue(cpColTypeDrop, opt.token)
            UIDropDownMenu_SetText(cpColTypeDrop, opt.label)
            F.UpdateClassPowerColorControls()
        end
        info.checked = (opt.token == selected)
        UIDropDownMenu_AddButton(info, level)
    end
end

UIDropDownMenu_Initialize(cpColTypeDrop, F.ClassPowerTypeDropdown_Init)
cpColTypeDrop._msufSelectedToken = "COMBO_POINTS"
UIDropDownMenu_SetSelectedValue(cpColTypeDrop, "COMBO_POINTS")
UIDropDownMenu_SetText(cpColTypeDrop, "Combo Points")

cpColSwatch:SetScript("OnClick", function()
    local token = cpColTypeDrop._msufSelectedToken or "COMBO_POINTS"
    local r, gCol, bCol = F.GetEffectiveClassPowerColor(token)
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        local g = F.EnsureClassPowerColorsDB()
        g.classPowerColorOverrides[token] = { nr, ng, nb }
        F.UpdateClassPowerColorControls()
        -- Live refresh class power bars
        if _G.MSUF_ClassPower_InvalidateColors then
            _G.MSUF_ClassPower_InvalidateColors()
        end
        PushVisualUpdates()
    end)
end)

cpColResetBtn:SetScript("OnClick", function()
    MSUF_ConfirmColorReset("class power color", function()
        local token = cpColTypeDrop._msufSelectedToken or "COMBO_POINTS"
        F.EnsureClassPowerColorsDB()
        if MSUF_DB and MSUF_DB.general and type(MSUF_DB.general.classPowerColorOverrides) == "table" then
            MSUF_DB.general.classPowerColorOverrides[token] = nil
        end
        F.UpdateClassPowerColorControls()
        if _G.MSUF_ClassPower_InvalidateColors then
            _G.MSUF_ClassPower_InvalidateColors()
        end
        PushVisualUpdates()
    end)
end)

cpColBgSwatch:SetScript("OnClick", function()
    local token = cpColTypeDrop._msufSelectedToken or "COMBO_POINTS"
    local r, gCol, bCol = F.GetEffectiveClassPowerBgColor(token)
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        local g = F.EnsureClassPowerColorsDB()
        g.classPowerBgColorOverrides[token] = { nr, ng, nb }
        F.UpdateClassPowerColorControls()
        if _G.MSUF_ClassPower_InvalidateColors then
            _G.MSUF_ClassPower_InvalidateColors()
        end
        PushVisualUpdates()
    end)
end)

cpColBgResetBtn:SetScript("OnClick", function()
    MSUF_ConfirmColorReset("class power background color", function()
        local token = cpColTypeDrop._msufSelectedToken or "COMBO_POINTS"
        F.EnsureClassPowerColorsDB()
        if MSUF_DB and MSUF_DB.general and type(MSUF_DB.general.classPowerBgColorOverrides) == "table" then
            MSUF_DB.general.classPowerBgColorOverrides[token] = nil
        end
        F.UpdateClassPowerColorControls()
        if _G.MSUF_ClassPower_InvalidateColors then
            _G.MSUF_ClassPower_InvalidateColors()
        end
        PushVisualUpdates()
    end)
end)

F.UpdateClassPowerColorControls()

S.lastControl = cpSlotResetBtn

end -- section 10

--------------------------------------------------
-- Section 11: Auras
--------------------------------------------------
S.sec11Box, S.sec11Body = F.MakeCollapsibleSection(content, 300, "Auras", false)
S.sec11Box:SetPoint("TOPLEFT", S.sec10Box, "BOTTOMLEFT", 0, -6)
do local content = S.sec11Body

local aurasSub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
aurasSub:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
aurasSub:SetWidth(600)
aurasSub:SetJustifyH("LEFT")
aurasSub:SetText("Configure colors used by Auras 2.0 (own highlight borders, advanced filter borders) and stack count text.")

local auraBuffLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
auraBuffLabel:SetPoint("TOPLEFT", aurasSub, "BOTTOMLEFT", 0, -12)
auraBuffLabel:SetText("Own buff highlight color")

local auraBuffSwatch = CreateFrame("Button", "MSUF_Colors_AuraOwnBuffHighlightSwatch", content)
auraBuffSwatch:SetSize(32, 16)
auraBuffSwatch:SetPoint("TOPLEFT", auraBuffLabel, "BOTTOMLEFT", 0, -8)
local auraBuffTex = auraBuffSwatch:CreateTexture(nil, "ARTWORK")
auraBuffTex:SetAllPoints()

local auraDebuffLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
auraDebuffLabel:SetPoint("TOPLEFT", auraBuffSwatch, "BOTTOMLEFT", 0, -12)
auraDebuffLabel:SetText("Own debuff highlight color")

local auraDebuffSwatch = CreateFrame("Button", "MSUF_Colors_AuraOwnDebuffHighlightSwatch", content)
auraDebuffSwatch:SetSize(32, 16)
auraDebuffSwatch:SetPoint("TOPLEFT", auraDebuffLabel, "BOTTOMLEFT", 0, -8)
local auraDebuffTex = auraDebuffSwatch:CreateTexture(nil, "ARTWORK")
auraDebuffTex:SetAllPoints()

local auraStacksLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
auraStacksLabel:SetPoint("TOPLEFT", auraDebuffSwatch, "BOTTOMLEFT", 0, -12)
auraStacksLabel:SetText("Stack count text color")

local auraStacksSwatch = CreateFrame("Button", "MSUF_Colors_AuraStackCountSwatch", content)
auraStacksSwatch:SetSize(32, 16)
auraStacksSwatch:SetPoint("TOPLEFT", auraStacksLabel, "BOTTOMLEFT", 0, -8)
local auraStacksTex = auraStacksSwatch:CreateTexture(nil, "ARTWORK")
auraStacksTex:SetAllPoints()

local auraResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
auraResetBtn:SetSize(110, 22)
auraResetBtn:SetPoint("LEFT", auraStacksSwatch, "RIGHT", 12, 0)
auraResetBtn:SetText("Reset")

-- Pandemic window color (left column, below Stack count)
S.auraPanLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
S.auraPanLabel:SetPoint("TOPLEFT", auraStacksSwatch, "BOTTOMLEFT", 0, -12)
S.auraPanLabel:SetText("Pandemic window color")

S.auraPanSwatch = CreateFrame("Button", "MSUF_Colors_AuraPandemicSwatch", content)
S.auraPanSwatch:SetSize(32, 16)
S.auraPanSwatch:SetPoint("TOPLEFT", S.auraPanLabel, "BOTTOMLEFT", 0, -8)
S.pandemicSwatchTex = S.auraPanSwatch:CreateTexture(nil, "ARTWORK")
S.pandemicSwatchTex:SetAllPoints()

-- Aura cooldown text colors (DurationObject step curve)
local auraCDSafeLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
auraCDSafeLabel:SetPoint("TOPLEFT", aurasSub, "BOTTOMLEFT", 360, -12)
auraCDSafeLabel:SetText("Cooldown text: Safe")

local auraCDSafeSwatch = CreateFrame("Button", "MSUF_Colors_AuraCooldownSafeSwatch", content)
auraCDSafeSwatch:SetSize(32, 16)
auraCDSafeSwatch:SetPoint("TOPLEFT", auraCDSafeLabel, "BOTTOMLEFT", 0, -8)
local auraCDSafeTex = auraCDSafeSwatch:CreateTexture(nil, "ARTWORK")
auraCDSafeTex:SetAllPoints()

local auraCDWarnLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
auraCDWarnLabel:SetPoint("TOPLEFT", auraCDSafeLabel, "BOTTOMLEFT", 0, -32)
auraCDWarnLabel:SetText("Cooldown text: Warning")

local auraCDWarnSwatch = CreateFrame("Button", "MSUF_Colors_AuraCooldownWarningSwatch", content)
auraCDWarnSwatch:SetSize(32, 16)
auraCDWarnSwatch:SetPoint("TOPLEFT", auraCDWarnLabel, "BOTTOMLEFT", 0, -8)
local auraCDWarnTex = auraCDWarnSwatch:CreateTexture(nil, "ARTWORK")
auraCDWarnTex:SetAllPoints()

local auraCDUrgentLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormal")
auraCDUrgentLabel:SetPoint("TOPLEFT", auraCDWarnLabel, "BOTTOMLEFT", 0, -32)
auraCDUrgentLabel:SetText("Cooldown text: Urgent")

local auraCDUrgentSwatch = CreateFrame("Button", "MSUF_Colors_AuraCooldownUrgentSwatch", content)
auraCDUrgentSwatch:SetSize(32, 16)
auraCDUrgentSwatch:SetPoint("TOPLEFT", auraCDUrgentLabel, "BOTTOMLEFT", 0, -8)
local auraCDUrgentTex = auraCDUrgentSwatch:CreateTexture(nil, "ARTWORK")
auraCDUrgentTex:SetAllPoints()

local auraCDResetBtn = CreateFrame("Button", nil, content, "UIPanelButtonTemplate")
auraCDResetBtn:SetSize(110, 22)
auraCDResetBtn:SetPoint("LEFT", auraCDUrgentSwatch, "RIGHT", 12, 0)
auraCDResetBtn:SetText("Reset")

F.EnsureAurasColorsDB = function()
    EnsureDB()
    MSUF_DB.general = MSUF_DB.general or {}
    local g = MSUF_DB.general
    if type(g.aurasOwnBuffHighlightColor) ~= "table" then
        g.aurasOwnBuffHighlightColor = { 1.0, 0.85, 0.2 } -- legacy gold
    end
    if type(g.aurasOwnDebuffHighlightColor) ~= "table" then
        g.aurasOwnDebuffHighlightColor = { 1.0, 0.85, 0.2 } -- legacy gold
    end
    if type(g.aurasStackCountColor) ~= "table" then
        g.aurasStackCountColor = { 1, 1, 1 } -- white
    end
    if type(g.aurasCooldownTextWarningColor) ~= "table" then
        g.aurasCooldownTextWarningColor = { 1.00, 0.85, 0.20 } -- warning (yellow)
    end
    if type(g.aurasCooldownTextUrgentColor) ~= "table" then
        g.aurasCooldownTextUrgentColor = { 1.00, 0.55, 0.10 } -- urgent (orange/red)
    end
    return g
end

F.GetAurasOwnBuffHighlightColor = function()
    local g = F.EnsureAurasColorsDB()
    local t = g.aurasOwnBuffHighlightColor
    return t[1] or 1.0, t[2] or 0.85, t[3] or 0.2
end

F.GetAurasOwnDebuffHighlightColor = function()
    local g = F.EnsureAurasColorsDB()
    local t = g.aurasOwnDebuffHighlightColor
    return t[1] or 1.0, t[2] or 0.85, t[3] or 0.2
end

F.GetAurasStackCountColor = function()
    local g = F.EnsureAurasColorsDB()
    local t = g.aurasStackCountColor
    return t[1] or 1, t[2] or 1, t[3] or 1
end

F.GetAurasCooldownTextSafeColor = function()
    local g = F.EnsureAurasColorsDB()
    local t = g.aurasCooldownTextSafeColor
    if type(t) == "table" then
        local r = t[1] or t.r
        local gg = t[2] or t.g
        local b = t[3] or t.b
        if type(r) == "number" and type(gg) == "number" and type(b) == "number" then
            return r, gg, b
        end
    end
    return GetGlobalFontColor()
end

F.GetAurasCooldownTextWarningColor = function()
    local g = F.EnsureAurasColorsDB()
    local t = g.aurasCooldownTextWarningColor
    return (t[1] or 1.00), (t[2] or 0.85), (t[3] or 0.20)
end

F.GetAurasCooldownTextUrgentColor = function()
    local g = F.EnsureAurasColorsDB()
    local t = g.aurasCooldownTextUrgentColor
    return (t[1] or 1.00), (t[2] or 0.55), (t[3] or 0.10)
end

F.GetPandemicColor = function()
    EnsureDB()
    local a2 = MSUF_DB and MSUF_DB.auras2
    local sh = a2 and a2.shared
    local r = (sh and type(sh.pandemicR) == "number") and sh.pandemicR or 0.0
    local g = (sh and type(sh.pandemicG) == "number") and sh.pandemicG or 0.4
    local b = (sh and type(sh.pandemicB) == "number") and sh.pandemicB or 1.0
    return r, g, b
end

F.SetPandemicColor = function(r, g, b)
    EnsureDB()
    MSUF_DB.auras2 = MSUF_DB.auras2 or {}
    MSUF_DB.auras2.shared = MSUF_DB.auras2.shared or {}
    MSUF_DB.auras2.shared.pandemicR = r
    MSUF_DB.auras2.shared.pandemicG = g
    MSUF_DB.auras2.shared.pandemicB = b
end

F.PushAuras2ColorRefresh = function()
    if _G.MSUF_Auras2_RefreshAll then
        _G.MSUF_Auras2_RefreshAll()
    end
    if _G.MSUF_GF_ForceAuraTextColorRefresh then
        _G.MSUF_GF_ForceAuraTextColorRefresh()
    end
    if _G.MSUF_Auras2Options_RefreshTimerColorControls then
        _G.MSUF_Auras2Options_RefreshTimerColorControls()
    end
    if _G.MSUF_GFAurasOptions_RefreshTimerColorControls then
        _G.MSUF_GFAurasOptions_RefreshTimerColorControls()
    end
    if PushVisualUpdates then
        PushVisualUpdates()
    end
end

-- Live recolor helper for Aura cooldown text (preview + active icons)
F.ForceAurasCooldownTextRecolor = function()
    if type(_G.MSUF_A2_ForceCooldownTextRecolor) == 'function' then
        _G.MSUF_A2_ForceCooldownTextRecolor()
    end
    if type(_G.MSUF_GF_ForceCooldownTextRecolor) == 'function' then
        _G.MSUF_GF_ForceCooldownTextRecolor()
    end
end

F.UpdateAurasColorControls = function()
    local br, bg, bb = F.GetAurasOwnBuffHighlightColor()
    local dr, dg, db = F.GetAurasOwnDebuffHighlightColor()
    local sr, sg, sb = F.GetAurasStackCountColor()
    local cr, cg, cb = F.GetAurasCooldownTextSafeColor()
    local wr, wg, wb = F.GetAurasCooldownTextWarningColor()
    local ur, ug, ub = F.GetAurasCooldownTextUrgentColor()
    if auraBuffTex then auraBuffTex:SetColorTexture(br, bg, bb) end
    if auraDebuffTex then auraDebuffTex:SetColorTexture(dr, dg, db) end
    if auraStacksTex then auraStacksTex:SetColorTexture(sr, sg, sb) end
    if auraCDSafeTex then auraCDSafeTex:SetColorTexture(cr, cg, cb) end
    if auraCDWarnTex then auraCDWarnTex:SetColorTexture(wr, wg, wb) end
    if auraCDUrgentTex then auraCDUrgentTex:SetColorTexture(ur, ug, ub) end
    if S.pandemicSwatchTex then
        local pr, pg, pb = F.GetPandemicColor()
        S.pandemicSwatchTex:SetColorTexture(pr, pg, pb)
    end

    -- Bucket-coloring master toggle: when disabled, only Safe should be configurable.
    EnsureDB()
    local gg = (MSUF_DB and MSUF_DB.general) or nil
    local bucketsEnabled = not (gg and gg.aurasCooldownTextUseBuckets == false)
    local a = bucketsEnabled and 1 or 0.35

    if auraCDWarnSwatch then
        auraCDWarnSwatch:EnableMouse(bucketsEnabled)
        auraCDWarnSwatch:SetAlpha(a)
    end
    if auraCDWarnLabel then
        auraCDWarnLabel:SetAlpha(a)
    end

    if auraCDUrgentSwatch then
        auraCDUrgentSwatch:EnableMouse(bucketsEnabled)
        auraCDUrgentSwatch:SetAlpha(a)
    end
    if auraCDUrgentLabel then
        auraCDUrgentLabel:SetAlpha(a)
    end
end

_G.MSUF_Colors_RefreshAurasColorControls = function()
    if F.UpdateAurasColorControls then
        F.UpdateAurasColorControls()
    end
end

F.SetAurasOwnBuffHighlightColor = function(r, gCol, bCol)
    local g = F.EnsureAurasColorsDB()
    g.aurasOwnBuffHighlightColor = { r, gCol, bCol }
    F.UpdateAurasColorControls()
    F.PushAuras2ColorRefresh()
end

F.SetAurasOwnDebuffHighlightColor = function(r, gCol, bCol)
    local g = F.EnsureAurasColorsDB()
    g.aurasOwnDebuffHighlightColor = { r, gCol, bCol }
    F.UpdateAurasColorControls()
    F.PushAuras2ColorRefresh()
end

F.SetAurasStackCountColor = function(r, gCol, bCol)
    local g = F.EnsureAurasColorsDB()
    g.aurasStackCountColor = { r, gCol, bCol }
    F.UpdateAurasColorControls()
    F.PushAuras2ColorRefresh()
end

F.SetAurasCooldownTextSafeColor = function(r, gCol, bCol)
    local g = F.EnsureAurasColorsDB()
    if r == nil or gCol == nil or bCol == nil then
        g.aurasCooldownTextSafeColor = nil -- fallback to Global font color
    else
        g.aurasCooldownTextSafeColor = { r, gCol, bCol }
    end
    F.UpdateAurasColorControls()
    if _G.MSUF_A2_InvalidateCooldownTextCurve then
        _G.MSUF_A2_InvalidateCooldownTextCurve()
    end
    if _G.MSUF_GF_InvalidateCooldownTextCurve then
        _G.MSUF_GF_InvalidateCooldownTextCurve()
    end
    F.ForceAurasCooldownTextRecolor()
    F.PushAuras2ColorRefresh()
end

F.SetAurasCooldownTextWarningColor = function(r, gCol, bCol)
    local g = F.EnsureAurasColorsDB()
    g.aurasCooldownTextWarningColor = { r, gCol, bCol }
    F.UpdateAurasColorControls()
    if _G.MSUF_A2_InvalidateCooldownTextCurve then
        _G.MSUF_A2_InvalidateCooldownTextCurve()
    end
    if _G.MSUF_GF_InvalidateCooldownTextCurve then
        _G.MSUF_GF_InvalidateCooldownTextCurve()
    end
    F.ForceAurasCooldownTextRecolor()
    F.PushAuras2ColorRefresh()
end

F.SetAurasCooldownTextUrgentColor = function(r, gCol, bCol)
    local g = F.EnsureAurasColorsDB()
    g.aurasCooldownTextUrgentColor = { r, gCol, bCol }
    F.UpdateAurasColorControls()
    if _G.MSUF_A2_InvalidateCooldownTextCurve then
        _G.MSUF_A2_InvalidateCooldownTextCurve()
    end
    if _G.MSUF_GF_InvalidateCooldownTextCurve then
        _G.MSUF_GF_InvalidateCooldownTextCurve()
    end
    F.ForceAurasCooldownTextRecolor()
    F.PushAuras2ColorRefresh()
end

auraBuffSwatch:SetScript("OnMouseUp", function(self, button)
    if button == "RightButton" then
        F.SetAurasOwnBuffHighlightColor(1.0, 0.85, 0.2)
        return
    end
    local r, gCol, bCol = F.GetAurasOwnBuffHighlightColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetAurasOwnBuffHighlightColor(nr, ng, nb)
    end)
end)

auraDebuffSwatch:SetScript("OnMouseUp", function(self, button)
    if button == "RightButton" then
        F.SetAurasOwnDebuffHighlightColor(1.0, 0.85, 0.2)
        return
    end
    local r, gCol, bCol = F.GetAurasOwnDebuffHighlightColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetAurasOwnDebuffHighlightColor(nr, ng, nb)
    end)
end)

auraStacksSwatch:SetScript("OnMouseUp", function(self, button)
    if button == "RightButton" then
        F.SetAurasStackCountColor(1, 1, 1)
        return
    end
    local r, gCol, bCol = F.GetAurasStackCountColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetAurasStackCountColor(nr, ng, nb)
    end)
end)

S.auraPanSwatch:SetScript("OnMouseUp", function(self, button)
    if button == "RightButton" then
        F.SetPandemicColor(0.0, 0.4, 1.0)
        F.UpdateAurasColorControls()
        F.PushAuras2ColorRefresh()
        return
    end
    local r, gCol, bCol = F.GetPandemicColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetPandemicColor(nr, ng, nb)
        F.UpdateAurasColorControls()
        F.PushAuras2ColorRefresh()
    end)
end)

auraCDSafeSwatch:SetScript("OnMouseUp", function(self, button)
    if button == "RightButton" then
        F.SetAurasCooldownTextSafeColor(nil, nil, nil) -- reset to Global font color
        return
    end
    local r, gCol, bCol = F.GetAurasCooldownTextSafeColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetAurasCooldownTextSafeColor(nr, ng, nb)
    end)
end)

auraCDWarnSwatch:SetScript("OnMouseUp", function(self, button)
    if button == "RightButton" then
        F.SetAurasCooldownTextWarningColor(1.00, 0.85, 0.20)
        return
    end
    local r, gCol, bCol = F.GetAurasCooldownTextWarningColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetAurasCooldownTextWarningColor(nr, ng, nb)
    end)
end)

auraCDUrgentSwatch:SetScript("OnMouseUp", function(self, button)
    if button == "RightButton" then
        F.SetAurasCooldownTextUrgentColor(1.00, 0.55, 0.10)
        return
    end
    local r, gCol, bCol = F.GetAurasCooldownTextUrgentColor()
    OpenColorPicker(r, gCol, bCol, function(nr, ng, nb)
        F.SetAurasCooldownTextUrgentColor(nr, ng, nb)
    end)
end)

auraCDResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("aura cooldown colors", function()
                F.EnsureAurasColorsDB()
                MSUF_DB.general.aurasCooldownTextSafeColor = nil
                MSUF_DB.general.aurasCooldownTextWarningColor = { 1.00, 0.85, 0.20 }
                MSUF_DB.general.aurasCooldownTextUrgentColor = { 1.00, 0.55, 0.10 }
                if _G.MSUF_A2_InvalidateCooldownTextCurve then
                    _G.MSUF_A2_InvalidateCooldownTextCurve()
                end
                if _G.MSUF_GF_InvalidateCooldownTextCurve then
                    _G.MSUF_GF_InvalidateCooldownTextCurve()
                end
                F.ForceAurasCooldownTextRecolor()
                F.UpdateAurasColorControls()
                F.PushAuras2ColorRefresh()
        end)
    end)

auraResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("aura colors", function()
                F.EnsureAurasColorsDB()
                MSUF_DB.general.aurasOwnBuffHighlightColor = { 1.0, 0.85, 0.2 }
                MSUF_DB.general.aurasOwnDebuffHighlightColor = { 1.0, 0.85, 0.2 }
                MSUF_DB.general.aurasStackCountColor = { 1, 1, 1 }
                F.SetPandemicColor(0.0, 0.4, 1.0)
                MSUF_DB.general.aurasCooldownTextSafeColor = nil
                MSUF_DB.general.aurasCooldownTextWarningColor = { 1.00, 0.85, 0.20 }
                MSUF_DB.general.aurasCooldownTextUrgentColor = { 1.00, 0.55, 0.10 }
                if _G.MSUF_A2_InvalidateCooldownTextCurve then
                    _G.MSUF_A2_InvalidateCooldownTextCurve()
                end
                if _G.MSUF_GF_InvalidateCooldownTextCurve then
                    _G.MSUF_GF_InvalidateCooldownTextCurve()
                end
                F.ForceAurasCooldownTextRecolor()
                F.UpdateAurasColorControls()
                F.PushAuras2ColorRefresh()
        end)
    end)

F.UpdateAurasColorControls()

-- Auras section is now the lowest control for dynamic height
S.lastControl = S.auraPanSwatch

    end -- section 11

    --------------------------------------------------
    -- Section 12: Portrait Colors
    --------------------------------------------------
    S.sec12Box, S.sec12Body = F.MakeCollapsibleSection(content, 220, "Portrait Colors", false)
    S.sec12Box:SetPoint("TOPLEFT", S.sec11Box, "BOTTOMLEFT", 0, -6)
    do local content = S.sec12Body

    local portraitSub = content:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    portraitSub:SetPoint("TOPLEFT", content, "TOPLEFT", 12, -6)
    portraitSub:SetWidth(600)
    portraitSub:SetJustifyH("LEFT")
    portraitSub:SetText("Portrait border color used by Solid/Custom border styles, plus background color.")

    local function RefreshPortraitColorConsumers(reason)
        if _G.MSUF_PortraitDecoration_RefreshAll then
            _G.MSUF_PortraitDecoration_RefreshAll()
        end
        if _G.MSUF_UFPreview_RequestRefresh then
            _G.MSUF_UFPreview_RequestRefresh(reason or "PORTRAIT_COLORS")
        end
    end

    -- Portrait Border Color
    local pBorderLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
    pBorderLabel:SetPoint("TOPLEFT", portraitSub, "BOTTOMLEFT", 0, -16)
    pBorderLabel:SetText("Border custom color")

    local pBorderSwatch = CreateFrame("Button", "MSUF_Colors_PortraitBorderSwatch", content)
    pBorderSwatch:SetSize(32, 16)
    pBorderSwatch:SetPoint("TOPLEFT", pBorderLabel, "BOTTOMLEFT", 0, -6)
    S.portraitBorderTex = pBorderSwatch:CreateTexture(nil, "ARTWORK")
    S.portraitBorderTex:SetAllPoints()

    pBorderSwatch:SetScript("OnClick", function()
        EnsureDB()
        local g = MSUF_DB.general
        local r = g.portraitBorderColorR or 1
        local gv = g.portraitBorderColorG or 1
        local b = g.portraitBorderColorB or 1
        OpenColorPicker(r, gv, b, function(nr, ng, nb)
            g.portraitBorderColorR = nr
            g.portraitBorderColorG = ng
            g.portraitBorderColorB = nb
            S.portraitBorderTex:SetColorTexture(nr, ng, nb)
            -- Portrait styling is per-unit now; this Global Style control acts as
            -- an explicit "apply to all unit portraits" color shortcut.
            for _, uk in ipairs({"player","target","focus","targettarget","pet","boss"}) do
                MSUF_DB[uk] = MSUF_DB[uk] or {}
                local u = MSUF_DB[uk]
                u.portraitBorderColorR = nr
                u.portraitBorderColorG = ng
                u.portraitBorderColorB = nb
            end
            RefreshPortraitColorConsumers("PORTRAIT_BORDER_COLOR")
        end)
    end)

    -- Portrait Background Color
    local pBgLabel = content:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
    pBgLabel:SetPoint("TOPLEFT", pBorderSwatch, "BOTTOMLEFT", 0, -16)
    pBgLabel:SetText("Background color")

    local pBgSwatch = CreateFrame("Button", "MSUF_Colors_PortraitBgSwatch", content)
    pBgSwatch:SetSize(32, 16)
    pBgSwatch:SetPoint("TOPLEFT", pBgLabel, "BOTTOMLEFT", 0, -6)
    S.portraitBgTex = pBgSwatch:CreateTexture(nil, "ARTWORK")
    S.portraitBgTex:SetAllPoints()

    pBgSwatch:SetScript("OnClick", function()
        EnsureDB()
        local g = MSUF_DB.general
        local r = g.portraitBgColorR or 0.05
        local gv = g.portraitBgColorG or 0.05
        local b = g.portraitBgColorB or 0.05
        OpenColorPicker(r, gv, b, function(nr, ng, nb)
            g.portraitBgColorR = nr
            g.portraitBgColorG = ng
            g.portraitBgColorB = nb
            S.portraitBgTex:SetColorTexture(nr, ng, nb)
            for _, uk in ipairs({"player","target","focus","targettarget","pet","boss"}) do
                MSUF_DB[uk] = MSUF_DB[uk] or {}
                local u = MSUF_DB[uk]
                u.portraitBgColorR = nr
                u.portraitBgColorG = ng
                u.portraitBgColorB = nb
            end
            RefreshPortraitColorConsumers("PORTRAIT_BG_COLOR")
        end)
    end)

    -- Reset portrait colors
    local pResetBtn = CreateFrame("Button", "MSUF_Colors_PortraitResetButton", content, "UIPanelButtonTemplate")
    pResetBtn:SetSize(160, 22)
    pResetBtn:SetPoint("TOPLEFT", pBgSwatch, "BOTTOMLEFT", 0, -12)
    pResetBtn:SetText("Reset portrait colors")
    pResetBtn:SetScript("OnClick", function()
        MSUF_ConfirmColorReset("portrait colors", function()
            EnsureDB()
            local g = MSUF_DB.general
            g.portraitBorderColorR = 1; g.portraitBorderColorG = 1; g.portraitBorderColorB = 1; g.portraitBorderColorA = 1
            g.portraitBgColorR = 0.05; g.portraitBgColorG = 0.05; g.portraitBgColorB = 0.05; g.portraitBgColorA = 0.85
            for _, uk in ipairs({"player","target","focus","targettarget","pet","boss"}) do
                MSUF_DB[uk] = MSUF_DB[uk] or {}
                local u = MSUF_DB[uk]
                u.portraitBorderColorR = 1; u.portraitBorderColorG = 1; u.portraitBorderColorB = 1; u.portraitBorderColorA = 1
                u.portraitBgColorR = 0.05; u.portraitBgColorG = 0.05; u.portraitBgColorB = 0.05; u.portraitBgColorA = 0.85
            end
            S.portraitBorderTex:SetColorTexture(1, 1, 1)
            S.portraitBgTex:SetColorTexture(0.05, 0.05, 0.05)
            RefreshPortraitColorConsumers("PORTRAIT_COLOR_RESET")
        end)
    end)

    S.lastControl = pResetBtn

    end -- section 12

    -- Update lastControl to the last section box for dynamic height
    S.lastControl = S.sec12Box

    --------------------------------------------------
    -- F.Refresh function
    --------------------------------------------------
    F.Refresh = function()
        -- Global font
        local fr, fg, fb = GetGlobalFontColor()
        if S.fontSwatchTex then
            S.fontSwatchTex:SetColorTexture(fr, fg, fb)
        end

        -- Class colors + Label-Kontrast
        for _, token in ipairs(CLASS_TOKENS) do
            local tex   = S.classSwatches[token]
            local label = S.classLabels[token]
            if tex then
                local r, g, b = GetClassColor(token)
                tex:SetColorTexture(r, g, b)
                F.SetLabelContrast(label, r, g, b)
            end
        end

        -- Class bar background
        if S.classBgSwatchTex then
            local br, bg, bb = GetClassBarBgColor()
            S.classBgSwatchTex:SetColorTexture(br, bg, bb)
        end

        -- Bar background tint: optional Match-HP behavior (makes swatch read-only)
        if S.classBgMatchCheck then
            local match = GetBarBgMatchHP()
            S.classBgMatchCheck:SetChecked(match)
            if _G.MSUF_Colors_ClassBarBgSwatch and _G.MSUF_Colors_ClassBarBgSwatch.EnableMouse then
                _G.MSUF_Colors_ClassBarBgSwatch:EnableMouse(not match)
                _G.MSUF_Colors_ClassBarBgSwatch:SetAlpha(match and 0.5 or 1)
            end
            if classBgResetBtn and classBgResetBtn.SetEnabled then
                classBgResetBtn:SetEnabled(not match)
            end
        end

        -- Gameplay combat state colors
        if F.UpdateGameplayCombatColorControls then
            F.UpdateGameplayCombatColorControls()
        end

        -- Gameplay crosshair range colors
        if F.UpdateGameplayCrosshairColorControls then
            F.UpdateGameplayCrosshairColorControls()
        end

        -- Power bar colors
        if F.UpdatePowerColorControls then
            F.UpdatePowerColorControls()
        end

        -- Class power colors (CP, DH, Stagger, etc.)
        if F.UpdateClassPowerColorControls then
            F.UpdateClassPowerColorControls()
        end

        -- Auras colors
        if F.UpdateAurasColorControls then
            F.UpdateAurasColorControls()
        end
-- Bar appearance (moved from Bars menu)
        if S.barModeDrop or S.darkToneSlider then
            EnsureDB()
            local g = (MSUF_DB and MSUF_DB.general) or {}
            S.barAppearanceRefreshing = true

            -- Refresh unified swatch color (in case profile changed)
            if _G.MSUF_Colors_UnifiedBarSwatch and _G.MSUF_Colors_UnifiedBarSwatch.GetRegions then
                local r, gg, b = (function()
                    local rr, ggg, bb = g.unifiedBarR, g.unifiedBarG, g.unifiedBarB
                    if type(rr) ~= "number" or type(ggg) ~= "number" or type(bb) ~= "number" then
                        rr, ggg, bb = 0.10, 0.60, 0.90
                    end
                    if rr < 0 then rr = 0 elseif rr > 1 then rr = 1 end
                    if ggg < 0 then ggg = 0 elseif ggg > 1 then ggg = 1 end
                    if bb < 0 then bb = 0 elseif bb > 1 then bb = 1 end
                    return rr, ggg, bb
                end)()
                if unifiedTex and unifiedTex.SetColorTexture then
                    unifiedTex:SetColorTexture(r, gg, b)
                end
            end

            if S.barModeDrop then
                local mode = g.barMode
                if mode ~= "dark" and mode ~= "class" and mode ~= "unified" and mode ~= "gradient" then
                    mode = (g.useClassColors and "class") or "dark"
                    g.barMode = mode
                end
                local label = "Dark Mode (dark black bars)"
                if mode == "class" then
                    label = "Class Color Mode (color HP bars)"
                elseif mode == "unified" then
                    label = "Unified Color Mode (one color for all frames)"
                elseif mode == "gradient" then
                    label = "Color Gradient"
                end
                UIDropDownMenu_SetSelectedValue(S.barModeDrop, mode)
                UIDropDownMenu_SetText(S.barModeDrop, label)
            end
if S.darkToneSlider then
    local pct
    if type(g.darkBarGray) == "number" then
        pct = math.floor(g.darkBarGray * 100 + 0.5)
    else
        local toneKey = g.darkBarTone
        if type(toneKey) ~= "string" or toneKey == "" then
            toneKey = "black"
        end
        if toneKey == "darkgray" then
            pct = 25
        elseif toneKey == "softgray" then
            pct = 45
        else
            pct = 0
        end
    end
    if pct < 0 then pct = 0 end
    if pct > 100 then pct = 100 end
    S.darkToneSlider:SetValue(pct)
    if F.UpdateDarkToneValueText then
        F.UpdateDarkToneValueText(pct)
    end
end

            if F.UpdateDarkBarControls then F.UpdateDarkBarControls() end
            if F.UpdateDarkBgCustomControls then F.UpdateDarkBgCustomControls() end
            if F.UpdateUnifiedBarControls then F.UpdateUnifiedBarControls() end
            S.barAppearanceRefreshing = false
        end

        -- NPC colors
        if S.npcFriendlyTex then
            local r1, g1, b1 = GetNPCColor("friendly")
            S.npcFriendlyTex:SetColorTexture(r1, g1, b1)
        end
        if S.npcNeutralTex then
            local r2, g2, b2 = GetNPCColor("neutral")
            S.npcNeutralTex:SetColorTexture(r2, g2, b2)
        end
        if S.npcEnemyTex then
            local r3, g3, b3 = GetNPCColor("enemy")
            S.npcEnemyTex:SetColorTexture(r3, g3, b3)
        end
        if S.npcDeadTex then
            local r4, g4, b4 = GetNPCColor("dead")
            S.npcDeadTex:SetColorTexture(r4, g4, b4)
        end
        if S.petFrameTex then
            local pr, pg, pb = GetPetFrameColor()
            S.petFrameTex:SetColorTexture(pr, pg, pb)
        end

           -- Castbar colors
        if S.interruptibleTex or S.nonInterruptibleTex or S.interruptFeedbackTex then
            if S.interruptibleTex then
                local r, g2, b2 = GetInterruptibleCastColor()
                S.interruptibleTex:SetColorTexture(r, g2, b2)
            end
            if S.nonInterruptibleTex then
                local r, g2, b2 = GetNonInterruptibleCastColor()
                S.nonInterruptibleTex:SetColorTexture(r, g2, b2)
            end
            if S.interruptFeedbackTex then
                local r, g2, b2 = GetInterruptFeedbackCastColor()
                S.interruptFeedbackTex:SetColorTexture(r, g2, b2)
            end
        end
        -- Castbar background color
        if S.castbarBgTex then
            local r, g2, b2 = GetCastbarBackgroundColor()
            S.castbarBgTex:SetColorTexture(r, g2, b2)
        end
        -- Mouseover highlight (enable + colorpicker)
        if S.highlightEnableCheck or S.highlightColorTex then
            if F.UpdateHighlightControls then
                F.UpdateHighlightControls()
            else
                EnsureDB()
                local g = MSUF_DB.general or {}
                if S.highlightEnableCheck then
                    S.highlightEnableCheck:SetChecked(g.highlightEnabled ~= false)
                end
            end
            if S.highlightColorTex then
                local hr, hg, hb = F.GetHighlightColor()
                S.highlightColorTex:SetColorTexture(hr, hg, hb)
            end
        end

        -- Portrait colors
        if S.portraitBorderTex then
            local g = MSUF_DB.general or {}
            S.portraitBorderTex:SetColorTexture(g.portraitBorderColorR or 1, g.portraitBorderColorG or 1, g.portraitBorderColorB or 1)
        end
        if S.portraitBgTex then
            local g = MSUF_DB.general or {}
            S.portraitBgTex:SetColorTexture(g.portraitBgColorR or 0.05, g.portraitBgColorG or 0.05, g.portraitBgColorB or 0.05)
        end

        -- Pandemic window color
        if S.pandemicSwatchTex and F.GetPandemicColor then
            local pr, pg, pb = F.GetPandemicColor()
            S.pandemicSwatchTex:SetColorTexture(pr, pg, pb)
        end
end

    --------------------------------------------------
    -- Dynamic content height
    --------------------------------------------------
    F.UpdateContentHeight = function()
        local minHeight = 400
        if not S.lastControl then
            content:SetHeight(minHeight)
            return
        end

        local bottom = S.lastControl:GetBottom()
        local top    = content:GetTop()
        if not bottom or not top then
            content:SetHeight(minHeight)
            return
        end

        local padding = 40
        local height  = top - bottom + padding
        if height < minHeight then
            height = minHeight
        end
        content:SetHeight(height)
    end

    --------------------------------------------------
    -- Register as sub-category under the main MSUF panel
    -- NOTE: Slash-menu-only mode must NOT register any Blizzard settings / interface options categories.
    --------------------------------------------------
    if not (_G.MSUF_SLASHMENU_ONLY or _G.MSUF_DISABLE_BLIZZARD_OPTIONS) then
        if (not panel.__MSUF_SettingsRegistered) and Settings and Settings.RegisterCanvasLayoutSubcategory and parentCategory then
            local subcategory = Settings.RegisterCanvasLayoutSubcategory(parentCategory, panel, panel.name)
            Settings.RegisterAddOnCategory(subcategory)
            panel.__MSUF_SettingsRegistered = true
            ns.MSUF_ColorsCategory = subcategory
        elseif InterfaceOptions_AddCategory then
            panel.parent = "Midnight Simple Unit Frames"
            InterfaceOptions_AddCategory(panel)
        end
    end

    panel:SetScript("OnShow", function()
        if _G.MSUF_StyleAllToggles then _G.MSUF_StyleAllToggles(panel) end
        F.Refresh()
        -- Auto-open first section if none open
        local anyOpen = false
        for i = 1, #S._allSections do
            if not S._allSections[i]._msufCollapsed then anyOpen = true; break end
        end
        if not anyOpen and S._allSections[1] then
            S._allSections[1]._msufCollapsed = false
            if S._allSections[1]._msufApplyCollapseState then S._allSections[1]._msufApplyCollapseState() end
        end
        F.UpdateContentHeight()
    end)

    -- Initial refresh
    F.Refresh()
    F.UpdateContentHeight()

    if _G.MSUF_StyleAllToggles then _G.MSUF_StyleAllToggles(panel) end

    -- Upgrade to smart accordion (radio + memory + auto-open)
    if _G.MSUF_UpgradeAccordion then
        local colorSections = {
            S.sec1Box, S.sec2Box, S.sec3Box, S.sec4Box, S.sec5Box,
            S.sec5tBox, S.sec5bBox, S.sec6Box, S.sec7Box, S.sec8Box,
            S.sec9Box, S.sec10Box, S.sec11Box, S.sec12Box,
        }
        _G.MSUF_UpgradeAccordion(colorSections, F.UpdateContentHeight, "colors", panel)
    end

    -- Search registration
    if _G.MSUF_Search_RegisterRoots then
        _G.MSUF_Search_RegisterRoots(
            { "colors", "opt_colors", "font color", "class color", "bar color",
              "npc color", "castbar color", "highlight", "reaction", "gradient" },
            { "MSUF_ColorsScrollChild" }, "Colors"
        )
    end

    panel.__MSUF_ColorsBuilt = true
    return panel
end

-- Lightweight wrapper: register the category at login, but build the heavy UI only when opened.
function ns.MSUF_RegisterColorsOptions(parentCategory)
    if _G.MSUF_SLASHMENU_ONLY or _G.MSUF_DISABLE_BLIZZARD_OPTIONS then
        -- Slash-menu-only: never register Colors as a Blizzard Settings/Interface Options category.
        -- The Slash Menu is the only configuration UI.
        return
    end
    if not Settings or not Settings.RegisterCanvasLayoutSubcategory or not parentCategory then
        return ns.MSUF_RegisterColorsOptions_Full(parentCategory)
    end

    local panel = (_G.MSUF_ColorsPanel) or CreateFrame("Frame", "MSUF_ColorsPanel", UIParent)
    panel.name = "Colors"

    -- IMPORTANT: Panels created with UIParent are shown by default.
    -- If we rely on OnShow for first-time build, we must ensure the panel starts hidden,
    -- otherwise the first Settings click may not fire OnShow.
    if not panel.__MSUF_ForceHidden then
        panel.__MSUF_ForceHidden = true
        panel:Hide()
    end

    if not panel.__MSUF_SettingsRegistered then
        local subcategory = Settings.RegisterCanvasLayoutSubcategory(parentCategory, panel, panel.name)
        Settings.RegisterAddOnCategory(subcategory)
        ns.MSUF_ColorsCategory = subcategory
        panel.__MSUF_SettingsRegistered = true
    end

    if panel.__MSUF_ColorsBuilt then
        return panel
    end

    if not panel.__MSUF_LazyBuildHooked then
        panel.__MSUF_LazyBuildHooked = true

        panel:HookScript("OnShow", function()
            if panel.__MSUF_ColorsBuilt or panel.__MSUF_ColorsBuilding then return end
            panel.__MSUF_ColorsBuilding = true

            -- Build immediately (no C_Timer.After(0)): avoids "needs second click" issues.
            ns.MSUF_RegisterColorsOptions_Full(parentCategory)

            panel.__MSUF_ColorsBuilding = nil
        end)
    end

    return panel
end
