local _, private = ...

-- Lua Globals --
local next = _G.next
local tostring = _G.tostring

-- RealUI --
local RealUI = _G.RealUI
local L = RealUI.L
local round = RealUI.Round

local CombatFader = RealUI:GetModule("CombatFader")
local FramePoint = RealUI:GetModule("FramePoint")
local uiWidth, uiHeight = RealUI.GetInterfaceSize()

local ValidateOffset = private.ValidateOffset
local CloseHuDWindow = private.CloseHuDWindow
local options = private.options
local debug = private.debug

-- Safe layout accessor: returns the current layout index, falling back to
-- the character DB value or 1 if RealUI.cLayout is nil/tainted.
local function safeLayout()
    return RealUI.cLayout or (RealUI.db and RealUI.db.char.layout.current) or 1
end

-- Anchor targets for FramePoint-managed HuD elements. Keys match
-- FramePoint.ANCHOR_FRAMES; "screen" means the legacy UIParent-relative
-- LibWindow position.
local ANCHOR_TO_VALUES = {
    screen = "Screen",
    player = _G.PLAYER or "Player",
    target = _G.TARGET or "Target",
    focus  = _G.FOCUS or "Focus",
}
local ANCHOR_TO_ORDER = { "screen", "player", "target", "focus" }

-- Safe position accessor: returns the positions table for the current layout,
-- or nil if unavailable.
local function safePositions()
    local layout = safeLayout()
    return RealUI.db and RealUI.db.profile.positions[layout]
end

--- Write a HuD position key, honouring the "Link Layouts" toggle.
--
-- `positionsLink` used to be a ONE-SHOT copy performed at the moment the
-- toggle was ticked (see the linkLayout setter): every position slider
-- afterwards wrote only the layout you happened to be on, so the two layouts
-- silently drifted apart while the UI still claimed they were linked. A
-- beta 7 tester hit this from the healer side — with Link Layouts on, the
-- HuD Vertical slider moved the DPS/Tank HuD and left Healing behind.
--
-- Writing through to the other layout keeps the toggle's promise. It matches
-- the semantics the one-shot copy already established (a full DeepCopy of the
-- positions table, i.e. the layouts are meant to be identical while linked).
--- The other layout's positions table, in the PROFILE that layout runs under.
--
-- The layouts do not share a profile (layout 1 → "RealUI", layout 2 →
-- "RealUI-Healing") while `positions` lives on the profile, so mirroring only
-- inside `db.profile.positions` writes into a table the other layout NEVER
-- reads. LayoutManager owns the mapping and the store; see the full note on
-- `GetLayoutPositionsStore`.
local function otherLayoutPositions(otherLayout)
    local LayoutManager = RealUI.LayoutManager
    if not (LayoutManager and LayoutManager.GetLayoutPositionsStore) then return end
    return LayoutManager:GetLayoutPositionsStore(otherLayout)
end

local function writePosition(key, value)
    local db = RealUI.db
    if not db then return end

    local layout = safeLayout()
    local positions = db.profile.positions
    if not positions then return end

    -- CREATE the layout table if it is absent rather than skipping the write.
    -- These tables are populated lazily and are routinely sparse — the whole
    -- B79/B80 family came from code that quietly did nothing when a position
    -- entry was missing. Guarding with `if positions[n] then` meant the mirror
    -- silently no-opped whenever the OTHER layout had never been written to,
    -- which is exactly the case where linking matters most.
    positions[layout] = positions[layout] or {}
    positions[layout][key] = value

    if db.global.positionsLink then
        local other = layout == 1 and 2 or 1

        --[[ B104: link the RESULT, not the raw number.

             Several keys are read as an offset from a PER-LAYOUT baseline in
             `RealUI.defaultPositions`, not as an absolute. `ActionBarsY` is
             the clearest: `RealUI_ActionBars/Integration.lua` computes
             `sliderDelta = abY - defaultPositions[cLayout].ActionBarsY`, and
             the two baselines ship 46px apart (−161.5 DPS, −115.5 Healing).
             Copying the number verbatim therefore produces two different
             offsets — reported as the same setting sitting over the Infobar on
             DPS and under it on Healing, with bars 2 and 3 across it.

             So translate through the baselines: keep the offset from baseline
             identical, which is what "these layouts are linked" means to
             someone looking at the screen. Keys whose baselines match — HuDY
             among them — are unaffected and still copy verbatim, so B86's
             verified behaviour is unchanged.

             Same lesson as B89, one level down: linking has to carry the
             transform, and where the transform cannot be shared it has to be
             compensated for. ]]
        local otherValue = value
        local defaults = RealUI.defaultPositions
        local baseHere = defaults and defaults[layout] and defaults[layout][key]
        local baseThere = defaults and defaults[other] and defaults[other][key]
        if baseHere and baseThere and baseHere ~= baseThere then
            otherValue = value + (baseThere - baseHere)
        end

        positions[other] = positions[other] or {}
        positions[other][key] = otherValue

        -- ...and into the profile that layout runs under, which is the copy it
        -- will actually read.
        local otherProfile = otherLayoutPositions(other)
        if otherProfile then
            otherProfile[key] = otherValue
        end
    end
end


options.HuD = {
    type = "group",
    args = {
        toggle = { -- This is for button creation
            name = L["HuD_ShowElements"],
            type = "group",
            order = 0,
            args = {
            },
        },
        close = { -- This is for button creation
            name = _G.CLOSE,
            icon = "close",
            type = "group",
            order = -1,
            args = {
            },
        },
    }
}

local optArgs = options.HuD.args


do -- Other
    debug("HuD Other")
    local MODNAME = "ActionBars"
    local ActionBars = RealUI:GetModule(MODNAME)
    optArgs.other = {
        name = _G.BINDING_HEADER_OTHER,
        icon = "sliders",
        type = "group",
        childGroups = "tab",
        order = 1,
        args = {
            advanced = {
                name = _G.ADVANCED_OPTIONS,
                type = "execute",
                func = function(info, ...)
                    RealUI.Debug("Config", "Config Bar")
                    RealUI.LoadConfig("RealUI")
                end,
                order = 0,
            },
            addon = {
                name = L["Control_AddonControl"],
                type = "execute",
                func = function(info, ...)
                    -- B61: toggle like Advanced Options, don't just open
                    RealUI:GetModule("AddonControl"):ToggleOptionsWindow()
                end,
                order = 2,
            },
            displaySetup = {
                name = "Display Setup",
                type = "execute",
                func = function()
                    if RealUI.DisplayStage then
                        RealUI.DisplayStage.Toggle()
                    end
                end,
                order = 3,
            },
            general = {
                name = _G.GENERAL,
                type = "group",
                order = 10,
                args = {
                    layout = {
                        name = L["Layout_Layout"],
                        desc = "|cffffcc00⚠|r This setting may be reset by the Install Wizard during first-time setup or upgrade.",
                        type = "select",
                        values = function()
                            return {
                                L["Layout_DPSTank"],
                                L["Layout_Healing"],
                            }
                        end,
                        get = function(info)
                            return RealUI.db.char.layout.current
                        end,
                        set = function(info, value)
                            RealUI.db.char.layout.spec[RealUI.charInfo.specs.current.index] = value
                            if _G.issecretvalue(value) then
                                _G.print("Layout_Layout value is secret. Changing layout skipped.")
                                _G.print("Please report this to the RealUI author.")
                            end
                            RealUI:UpdateLayout(value)
                        end,
                        order = 10,
                    },
                    -- B60: which EditMode layout each role activates. RealUI
                    -- re-asserts the role's layout on reload and spec swaps
                    -- (WoW 12's per-spec EditMode tracking resets to a preset
                    -- otherwise); these pickers let that re-assert target a
                    -- user-made layout instead of always forcing RealUI's own.
                    editModeDpsTank = {
                        name = "Edit Mode layout: DPS/Tank",
                        desc = "The Edit Mode layout RealUI keeps active for DPS and Tank specs. Default: RealUI.",
                        type = "select",
                        values = function()
                            return RealUI.EditModeManager:GetSavedLayoutNames()
                        end,
                        get = function()
                            return RealUI.EditModeManager:GetConfiguredLayoutName("dpstank")
                        end,
                        set = function(info, value)
                            RealUI.EditModeManager:SetRoleLayout("dpstank", value)
                        end,
                        order = 12,
                    },
                    editModeHealing = {
                        name = "Edit Mode layout: Healing",
                        desc = "The Edit Mode layout RealUI keeps active for Healing specs. Default: RealUI-Healing.",
                        type = "select",
                        values = function()
                            return RealUI.EditModeManager:GetSavedLayoutNames()
                        end,
                        get = function()
                            return RealUI.EditModeManager:GetConfiguredLayoutName("healing")
                        end,
                        set = function(info, value)
                            RealUI.EditModeManager:SetRoleLayout("healing", value)
                        end,
                        order = 14,
                    },
                    linkLayout = {
                        name = L["Layout_Link"],
                        desc = L["Layout_LinkDesc"],
                        type = "toggle",
                        get = function() return RealUI.db.global.positionsLink end,
                        set = function(info, value)
                            RealUI.cLayout = RealUI.db.char.layout.current
                            RealUI.ncLayout = RealUI.cLayout == 1 and 2 or 1

                            -- Seeding the other layout (and the profile it
                            -- actually reads) lives in LayoutManager, shared
                            -- with the install wizard's Link Layouts option.
                            RealUI.LayoutManager:SetPositionsLink(value)
                        end,
                        order = 20,
                    },
                    useLarge = {
                        name = L["HuD_UseLarge"],
                        desc = L["HuD_UseLargeDesc"]
                            .. "\n\n|cffffcc00⚠|r This setting may be reset by the Install Wizard during first-time setup or upgrade.",
                        type = "toggle",
                        get = function() return RealUI.db.profile.settings.hudSize == 2 end,
                        set = function(info, value)
                            RealUI.db.profile.settings.hudSize = value and 2 or 1
                            -- hudSize is the transform every position value is
                            -- rendered through (`Positioners.GetKeyAdjust` adds
                            -- `hudSizeOffsets[hudSize][key]`), so while Link
                            -- Layouts is on it has to travel with them — else
                            -- the two layouts hold matching numbers and draw in
                            -- different places.
                            RealUI.LayoutManager:MirrorLinkedSettings()
                            _G.StaticPopup_Show("RUI_ChangeHuDSize")
                        end,
                        order = 30,
                    },
                    hudVert = {
                        name = L["HuD_Vertical"],
                        desc = L["HuD_VerticalDesc"],
                        type = "range",
                        width = "full",
                        min = -round(uiHeight * 0.3),
                        max = round(uiHeight * 0.3),
                        step = 1,
                        bigStep = 4,
                        order = 40,
                        get = function(info)
                            local pos = safePositions()
                            return pos and pos["HuDY"] or 0
                        end,
                        set = function(info, value)
                            local pos = safePositions()
                            if not pos then return end

                            local previous = pos["HuDY"] or 0
                            writePosition("HuDY", value)
                            RealUI:UpdatePositioners()

                            -- Elements the user has dragged are anchored to
                            -- UIParent, not to a positioner, so UpdatePositioners
                            -- alone moves nothing for them — the slider looked
                            -- dead in whichever profile carried saved drag
                            -- positions. Move them by the same delta.
                            local delta = value - previous
                            if delta ~= 0 then
                                FramePoint:ShiftScreenAnchored(0, delta)
                            end
                        end,
                    },
                    -- The tester's own ask: nothing on this panel said what
                    -- "Link Layouts" covers, so a per-spec Vertical difference
                    -- read as a bug in the toggle rather than as data it had
                    -- never been given a chance to copy.
                    hudVertNote = {
                        name = L["Layout_LinkNote"],
                        type = "description",
                        fontSize = "medium",
                        order = 41,
                    },
                    -- B93: dragging an element detaches it from the positioners
                    -- for good, and after that these sliders cannot place it.
                    -- Without a way back, a profile that has ever been hand-
                    -- positioned can never be made to match another one.
                    reattach = {
                        name = L["HuD_Reattach"],
                        desc = L["HuD_ReattachDesc"],
                        type = "execute",
                        confirm = true,
                        confirmText = L["HuD_ReattachConfirm"],
                        order = 42,
                        func = function()
                            local count = FramePoint:ReattachToPositioners()
                            _G.print(("|cff30d0ffRealUI|r: %d HuD element(s) re-attached to the position sliders."):format(count))
                        end,
                    },
                    undoReattach = {
                        name = L["HuD_ReattachUndo"],
                        desc = L["HuD_ReattachUndoDesc"],
                        type = "execute",
                        order = 43,
                        hidden = function()
                            return FramePoint:GetReattachUndoCount() == 0
                        end,
                        func = function()
                            local count = FramePoint:UndoReattach()
                            _G.print(("|cff30d0ffRealUI|r: %d hand-placed position(s) restored."):format(count))
                        end,
                    }
                }
            },
            spellalert = {
                name = _G.COMBAT_TEXT_SHOW_REACTIVES_TEXT,
                desc = L["Misc_SpellAlertsDesc"],
                type = "group",
                args = {
                    enabled = {
                        name = L["General_Enabled"],
                        desc = L["General_EnabledDesc"]:format(_G.COMBAT_TEXT_SHOW_REACTIVES_TEXT),
                        type = "toggle",
                        get = function() return RealUI:GetModuleEnabled("SpellAlerts") end,
                        set = function(info, value)
                            RealUI:SetModuleEnabled("SpellAlerts", value)
                            RealUI:ReloadUIDialog()
                        end,
                        order = 30,
                    },
                    -- B13: spell alerts are statically centered on the character;
                    -- the only settings are on/off and scale (the old Width slider
                    -- wrote the retired SpellAlertWidth position key).
                    scale = {
                        name = L["General_Scale"],
                        desc = "Adjust the size of the Spell Alerts around your character.",
                        type = "range",
                        width = "full",
                        min = 0.5,
                        max = 2,
                        step = 0.05,
                        isPercent = true,
                        order = 40,
                        disabled = function() return not RealUI:GetModuleEnabled("SpellAlerts") end,
                        get = function(info)
                            local SpellAlerts = RealUI:GetModule("SpellAlerts")
                            return (SpellAlerts.db and SpellAlerts.db.profile.scale) or 1
                        end,
                        set = function(info, value)
                            local SpellAlerts = RealUI:GetModule("SpellAlerts")
                            if SpellAlerts.db then
                                SpellAlerts.db.profile.scale = value
                            end
                            SpellAlerts:UpdatePosition()
                        end,
                    }
                }
            },
            actionbars = {
                name = _G.ACTIONBARS_LABEL,
                desc = L["ActionBars_ActionBarsDesc"],
                type = "group",
                args = {
                    advanced = {
                        name = "Action Bar Settings",
                        type = "execute",
                        func = function(info, ...)
                            local rab = _G.LibStub("AceAddon-3.0"):GetAddon("RealUIActionBars", true)
                            if rab and rab.OpenConfig then
                                rab:OpenConfig()
                            else
                                _G.print("RealUI_ActionBars is not loaded.")
                            end
                        end,
                        order = 10,
                    },
                    showDoodads = {
                        name = L["ActionBars_ShowDoodads"],
                        desc = L["ActionBars_ShowDoodadsDesc"],
                        type = "toggle",
                        get = function() return ActionBars.db.profile.showDoodads end,
                        set = function(info, value)
                            ActionBars.db.profile.showDoodads = value
                            ActionBars:RefreshDoodads()
                        end,
                        order = 20,
                    },
                    enableNagaBar = {
                        name = "Enable Razer Naga Action Bar",
                        desc = "Enable action bar 6 for use with Razer Naga or similar multi-button mice. This bar appears at the bottom center of the screen.",
                        type = "toggle",
                        get = function() return ActionBars.db.profile.enableNagaBar end,
                        set = function(info, value)
                            ActionBars.db.profile.enableNagaBar = value
                            ActionBars:ToggleNagaBar(value)
                        end,
                        order = 25,
                    },
                    header = {
                        name = L["General_Position"],
                        type = "header",
                        order = 39,
                    },
                    position = {
                        name = "",
                        type = "group",
                        inline = true,
                        args = {
                            move = {
                                name = "",
                                type = "group",
                                inline = true,
                                order = 10,
                                args = {
                                    moveStance = {
                                        name = L["ActionBars_Move"]:format(L["ActionBars_Stance"]),
                                        desc = L["ActionBars_MoveDesc"]:format(L["ActionBars_Stance"]),
                                        type = "toggle",
                                        get = function() return ActionBars.db.profile[safeLayout()].moveBars.stance end,
                                        set = function(info, value)
                                            ActionBars.db.profile[safeLayout()].moveBars.stance = value
                                            ActionBars:ApplyABSettings()
                                        end,
                                        order = 10,
                                    },
                                    movePet = {
                                        name = L["ActionBars_Move"]:format(L["ActionBars_Pet"]),
                                        desc = L["ActionBars_MoveDesc"]:format(L["ActionBars_Pet"]),
                                        type = "toggle",
                                        get = function() return ActionBars.db.profile[safeLayout()].moveBars.pet end,
                                        set = function(info, value)
                                            ActionBars.db.profile[safeLayout()].moveBars.pet = value
                                            ActionBars:ApplyABSettings()
                                        end,
                                        order = 20,
                                    },
                                    moveEAB = {
                                        name = L["ActionBars_Move"]:format(L["ActionBars_EAB"]),
                                        desc = L["ActionBars_MoveDesc"]:format(L["ActionBars_EAB"]),
                                        type = "toggle",
                                        get = function() return ActionBars.db.profile[safeLayout()].moveBars.eab end,
                                        set = function(info, value)
                                            ActionBars.db.profile[safeLayout()].moveBars.eab = value
                                            ActionBars:ApplyABSettings()
                                        end,
                                        order = 30,
                                    },
                                }
                            },
                            center = {
                                name = L["ActionBars_Center"],
                                desc = L["ActionBars_CenterDesc"],
                                type = "select",
                                values = function()
                                    return {
                                        L["ActionBars_CenterOption"]:format(0, 3),
                                        L["ActionBars_CenterOption"]:format(1, 2),
                                        L["ActionBars_CenterOption"]:format(2, 1),
                                        L["ActionBars_CenterOption"]:format(3, 0),
                                    }
                                end,
                                get = function(info)
                                    return ActionBars.db.profile[safeLayout()].centerPositions
                                end,
                                set = function(info, value)
                                    ActionBars.db.profile[safeLayout()].centerPositions = value
                                    ActionBars:ApplyABSettings()
                                    RealUI:UpdatePositioners()
                                end,
                                order = 20,
                            },
                            side = {
                                name = L["ActionBars_Sides"],
                                desc = L["ActionBars_SidesDesc"],
                                type = "select",
                                values = function()
                                    return {
                                        L["ActionBars_SidesOption"]:format(0, 2),
                                        L["ActionBars_SidesOption"]:format(1, 1),
                                        L["ActionBars_SidesOption"]:format(2, 0),
                                    }
                                end,
                                get = function(info)
                                    return ActionBars.db.profile[safeLayout()].sidePositions
                                end,
                                set = function(info, value)
                                    ActionBars.db.profile[safeLayout()].sidePositions = value
                                    ActionBars:ApplyABSettings()
                                    RealUI:UpdatePositioners()
                                end,
                                order = 30,
                            },
                            vertical = {
                                name = L["HuD_Vertical"],
                                desc = L["HuD_VerticalActionBarDesc"],
                                type = "range",
                                width = "full",
                                min = -round(uiHeight * 0.3), max = round(uiHeight * 0.3),
                                step = 1, bigStep = 4,
                                order = -1,
                                get = function(info)
                                    local pos = safePositions()
                                    if pos and pos["ActionBarsY"] then
                                        return pos["ActionBarsY"]
                                    end
                                    -- The fallback used to be a hard-coded
                                    -- -161.5 — layout 1's baseline, shown on
                                    -- layout 2 as well, where the baseline is
                                    -- -115.5 (B104). Read the layout's own.
                                    local layout = safeLayout()
                                    local defaults = RealUI.defaultPositions
                                    local base = defaults and defaults[layout]
                                    return (base and base.ActionBarsY) or -161.5
                                end,
                                set = function(info, value)
                                    local pos = safePositions()
                                    if pos then
                                        writePosition("ActionBarsY", value - .5)
                                        ActionBars:ApplyABSettings()
                                        RealUI:UpdatePositioners()
                                    end
                                end,
                            },
                            -- B104: this slider goes through `writePosition`,
                            -- so "Link Layouts" governs it — but that toggle
                            -- lives on HuD → General and nothing here said so.
                            -- Reported as "the vertical for actionbar is shared
                            -- between the two even tho there is no linked
                            -- option there".
                            --
                            -- Shown only while linking is ON, so it reports the
                            -- state the user is actually in rather than
                            -- describing a feature they may not be using. The
                            -- panel stays clean for everyone else.
                            verticalNote = {
                                name = L["Layout_LinkNoteBars"],
                                type = "description",
                                fontSize = "medium",
                                order = -0.5,
                                hidden = function()
                                    local db = RealUI.db
                                    return not (db and db.global and db.global.positionsLink)
                                end,
                            }
                        }
                    }
                }
            }
        }
    }
end
do -- UnitFrames
    debug("HuD UnitFrames")
    local MODNAME = "UnitFrames"
    local UnitFrames = RealUI:GetModule(MODNAME)
    optArgs.unitframes = {
        name = _G.UNITFRAME_LABEL,
        icon = "th",
        type = "group",
        childGroups = "tab",
        order = 2,
        args = {
            enable = {
                name = L["General_Enabled"],
                desc = L["General_EnabledDesc"]:format("RealUI ".._G.UNITFRAME_LABEL),
                type = "toggle",
                get = function(info) return RealUI:GetModuleEnabled(MODNAME) end,
                set = function(info, value)
                    RealUI:SetModuleEnabled("UnitFrames", value)
                    CloseHuDWindow()
                    RealUI:ReloadUIDialog()
                end,
            },
            general = {
                name = _G.GENERAL,
                type = "group",
                disabled = function() return not(RealUI:GetModuleEnabled(MODNAME)) end,
                order = 10,
                args = {
                    classColor = {
                        name = L["Appearance_ClassColorHealth"],
                        type = "toggle",
                        get = function() return UnitFrames.db.profile.overlay.classColor end,
                        set = function(info, value)
                            UnitFrames.db.profile.overlay.classColor = value
                            UnitFrames:RefreshUnits("ClassColorBars")
                        end,
                        order = 10,
                    },
                    classColorNames = {
                        name = L["Appearance_ClassColorNames"],
                        type = "toggle",
                        get = function() return UnitFrames.db.profile.overlay.classColorNames end,
                        set = function(info, value)
                            UnitFrames.db.profile.overlay.classColorNames = value
                        end,
                        order = 15,
                    },
                    -- "Colored when full" — intended to make bars start full and drain.
                    -- Not yet implemented correctly; disabled for now.
                    -- FIXMELATER: Implement as a visual mode, not a reverse fill toggle.
                    --[[
                    reverseBars = {
                        name = L["HuD_ReverseBars"],
                        type = "toggle",
                        get = function() return RealUI.db.profile.settings.reverseUnitFrameBars end,
                        set = function(info, value)
                            RealUI.db.profile.settings.reverseUnitFrameBars = value
                            UnitFrames:RefreshUnits("ReverseBars")
                        end,
                        order = 20,
                    },
                    ]]
                    statusText = {
                        name = _G.STATUS_TEXT,
                        desc = _G.OPTION_TOOLTIP_STATUS_TEXT_DISPLAY,
                        type = "select",
                        values = function()
                            return {
                                both = _G.STATUS_TEXT_BOTH,
                                perc = _G.STATUS_TEXT_PERCENT,
                                value = _G.STATUS_TEXT_VALUE,
                            }
                        end,
                        get = function(info)
                            return UnitFrames.db.profile.misc.statusText
                        end,
                        set = function(info, value)
                            UnitFrames.db.profile.misc.statusText = value
                            UnitFrames:RefreshUnits("StatusText")
                        end,
                        order = 30,
                    },
                    statusTextOutline = {
                        name = "Status Text Outline",
                        desc = "Choose how health and power status text is outlined.",
                        type = "select",
                        values = function()
                            return {
                                shadow = "Shadow",
                                outline = "Outline",
                                thick = "Thick Outline",
                            }
                        end,
                        get = function()
                            return UnitFrames.db.profile.misc.statusTextOutline or "outline"
                        end,
                        set = function(_, value)
                            UnitFrames.db.profile.misc.statusTextOutline = value
                            UnitFrames:RefreshUnits("StatusTextOutline")
                        end,
                        order = 31,
                    },
                    focusClick = {
                        name = L["UnitFrames_SetFocus"],
                        desc = L["UnitFrames_SetFocusDesc"],
                        type = "toggle",
                        get = function() return UnitFrames.db.profile.misc.focusclick end,
                        set = function(info, value)
                            UnitFrames.db.profile.misc.focusclick = value
                        end,
                        order = 40,
                    },
                    focusKey = {
                        name = L["UnitFrames_ModifierKey"],
                        type = "select",
                        values = function()
                            return {
                                shift = _G.SHIFT_KEY_TEXT,
                                ctrl = _G.CTRL_KEY_TEXT,
                                alt = _G.ALT_KEY_TEXT,
                            }
                        end,
                        disabled = function() return not UnitFrames.db.profile.misc.focusclick end,
                        get = function(info)
                            return UnitFrames.db.profile.misc.focuskey
                        end,
                        set = function(info, value)
                            UnitFrames.db.profile.misc.focuskey = value
                        end,
                        order = 41,
                    },
                    showPrediction = {
                        name = "Health Prediction",
                        desc = "Show incoming heals, damage absorbs and heal absorbs on health bars.",
                        type = "toggle",
                        get = function() return UnitFrames.db.profile.misc.showPrediction end,
                        set = function(_, value)
                            UnitFrames.db.profile.misc.showPrediction = value
                            UnitFrames:RefreshUnits("HealthPrediction")
                        end,
                        order = 42,
                    },
                    showPrivateAuras = {
                        name = "Private Auras",
                        desc = "Show Blizzard private aura anchors below the player frame (visible during certain boss encounters).",
                        type = "toggle",
                        get = function() return UnitFrames.db.profile.misc.showPrivateAuras end,
                        set = function(_, value)
                            UnitFrames.db.profile.misc.showPrivateAuras = value
                            UnitFrames:RefreshUnits("PrivateAuras")
                        end,
                        order = 43,
                    },
                    -- Health Bar Colors
                    healthBarHeader = {
                        name = "Health Bar Colors",
                        type = "header",
                        hidden = function() return not UnitFrames.db.profile.misc.alternativeBarStyle end,
                        order = 50,
                    },
                    foregroundColor = {
                        name = "Foreground Color",
                        type = "color",
                        hasAlpha = false,
                        hidden = function() return not UnitFrames.db.profile.misc.alternativeBarStyle end,
                        order = 51,
                        get = function()
                            local db = UnitFrames.db.profile
                            local c = db.units.player.healthBar.foreground
                            return c[1], c[2], c[3]
                        end,
                        set = function(_, r, g, b)
                            local db = UnitFrames.db.profile
                            for _, unitKey in next, {"player", "target", "boss"} do
                                if db.units[unitKey] and db.units[unitKey].healthBar then
                                    db.units[unitKey].healthBar.foreground = {r, g, b}
                                end
                            end
                            UnitFrames:RefreshUnits("HealthBarColors")
                        end,
                    },
                    foregroundOpacity = {
                        name = "Foreground Opacity",
                        type = "range",
                        min = 0, max = 1, step = 0.05,
                        isPercent = true,
                        hidden = function() return not UnitFrames.db.profile.misc.alternativeBarStyle end,
                        order = 52,
                        get = function()
                            return UnitFrames.db.profile.units.player.healthBar.foregroundOpacity
                        end,
                        set = function(_, val)
                            local db = UnitFrames.db.profile
                            for _, unitKey in next, {"player", "target", "boss"} do
                                if db.units[unitKey] and db.units[unitKey].healthBar then
                                    db.units[unitKey].healthBar.foregroundOpacity = val
                                end
                            end
                            UnitFrames:RefreshUnits("HealthBarColors")
                        end,
                    },
                    backgroundColor = {
                        name = "Background Color",
                        type = "color",
                        hasAlpha = false,
                        hidden = function() return not UnitFrames.db.profile.misc.alternativeBarStyle end,
                        order = 53,
                        get = function()
                            local c = UnitFrames.db.profile.units.player.healthBar.background
                            return c[1], c[2], c[3]
                        end,
                        set = function(_, r, g, b)
                            local db = UnitFrames.db.profile
                            for _, unitKey in next, {"player", "target", "boss"} do
                                if db.units[unitKey] and db.units[unitKey].healthBar then
                                    db.units[unitKey].healthBar.background = {r, g, b}
                                end
                            end
                            UnitFrames:RefreshUnits("HealthBarColors")
                        end,
                    },
                    backgroundOpacity = {
                        name = "Background Opacity",
                        type = "range",
                        min = 0, max = 1, step = 0.05,
                        isPercent = true,
                        hidden = function() return not UnitFrames.db.profile.misc.alternativeBarStyle end,
                        order = 54,
                        get = function()
                            return UnitFrames.db.profile.units.player.healthBar.backgroundOpacity
                        end,
                        set = function(_, val)
                            local db = UnitFrames.db.profile
                            for _, unitKey in next, {"player", "target", "boss"} do
                                if db.units[unitKey] and db.units[unitKey].healthBar then
                                    db.units[unitKey].healthBar.backgroundOpacity = val
                                end
                            end
                            UnitFrames:RefreshUnits("HealthBarColors")
                        end,
                    },
                    colorForegroundByClass = {
                        name = "Class Color Foreground",
                        type = "toggle",
                        hidden = function() return not UnitFrames.db.profile.misc.alternativeBarStyle end,
                        order = 55,
                        get = function()
                            return UnitFrames.db.profile.units.player.healthBar.colorForegroundByClass
                        end,
                        set = function(_, val)
                            local db = UnitFrames.db.profile
                            for _, unitKey in next, {"player", "target", "boss"} do
                                if db.units[unitKey] and db.units[unitKey].healthBar then
                                    db.units[unitKey].healthBar.colorForegroundByClass = val
                                end
                            end
                            UnitFrames:RefreshUnits("HealthBarColors")
                        end,
                    },
                    colorBackgroundByClass = {
                        name = "Class Color Background",
                        type = "toggle",
                        hidden = function() return not UnitFrames.db.profile.misc.alternativeBarStyle end,
                        order = 56,
                        get = function()
                            return UnitFrames.db.profile.units.player.healthBar.colorBackgroundByClass
                        end,
                        set = function(_, val)
                            local db = UnitFrames.db.profile
                            for _, unitKey in next, {"player", "target", "boss"} do
                                if db.units[unitKey] and db.units[unitKey].healthBar then
                                    db.units[unitKey].healthBar.colorBackgroundByClass = val
                                end
                            end
                            UnitFrames:RefreshUnits("HealthBarColors")
                        end,
                    },
                    -- Text Colors
                    textColorHeader = {
                        name = "Text Colors",
                        type = "header",
                        order = 60,
                    },
                    healthTextColor = {
                        name = "Health Text Color",
                        type = "color",
                        hasAlpha = false,
                        order = 61,
                        get = function()
                            local c = UnitFrames.db.profile.misc.textColors and UnitFrames.db.profile.misc.textColors.health
                            if c then return c[1], c[2], c[3] end
                            return 0.66, 0.22, 0.22
                        end,
                        set = function(_, r, g, b)
                            UnitFrames.db.profile.misc.textColors.health = {r, g, b}
                            UnitFrames:RefreshUnits("TextColors")
                        end,
                    },
                    healthTextColorReset = {
                        name = "Reset Health Text Color",
                        type = "execute",
                        order = 62,
                        func = function()
                            UnitFrames.db.profile.misc.textColors.health = nil
                            UnitFrames:RefreshUnits("TextColors")
                        end,
                    },
                    powerTextColor = {
                        name = "Power Text Color",
                        type = "color",
                        hasAlpha = false,
                        order = 63,
                        get = function()
                            local c = UnitFrames.db.profile.misc.textColors and UnitFrames.db.profile.misc.textColors.power
                            if c then return c[1], c[2], c[3] end
                            return 1, 1, 1
                        end,
                        set = function(_, r, g, b)
                            UnitFrames.db.profile.misc.textColors.power = {r, g, b}
                            UnitFrames:RefreshUnits("TextColors")
                        end,
                    },
                    powerTextColorReset = {
                        name = "Reset Power Text Color",
                        type = "execute",
                        order = 64,
                        func = function()
                            UnitFrames.db.profile.misc.textColors.power = nil
                            UnitFrames:RefreshUnits("TextColors")
                        end,
                    },
                    nameTextColor = {
                        name = "Name Text Color",
                        type = "color",
                        hasAlpha = false,
                        order = 65,
                        get = function()
                            local c = UnitFrames.db.profile.misc.textColors and UnitFrames.db.profile.misc.textColors.name
                            if c then return c[1], c[2], c[3] end
                            return 1, 1, 1
                        end,
                        set = function(_, r, g, b)
                            UnitFrames.db.profile.misc.textColors.name = {r, g, b}
                            UnitFrames:RefreshUnits("TextColors")
                        end,
                    },
                    nameTextColorReset = {
                        name = "Reset Name Text Color",
                        type = "execute",
                        order = 66,
                        func = function()
                            UnitFrames.db.profile.misc.textColors.name = nil
                            UnitFrames:RefreshUnits("TextColors")
                        end,
                    },
                    -- Alternative Bar Style
                    altBarStyleHeader = {
                        name = "Bar Style",
                        type = "header",
                        order = 75,
                    },
                    alternativeBarStyle = {
                        name = "Alternative Bar Style",
                        desc = "Use a dark foreground that shrinks to reveal a colored background bar. When disabled, bars use the standard solid color fill.",
                        type = "toggle",
                        order = 76,
                        get = function()
                            return UnitFrames.db.profile.misc.alternativeBarStyle
                        end,
                        set = function(_, val)
                            UnitFrames.db.profile.misc.alternativeBarStyle = val
                            UnitFrames:RefreshUnits("AlternativeBarStyle")
                        end,
                    },
                }
            },
            units = {
                name = L["UnitFrames_Units"],
                type = "group",
                childGroups = "tab",
                disabled = function() return not(RealUI:GetModuleEnabled(MODNAME)) end,
                order = 20,
                args = {
                    player = {
                        name = _G.PLAYER,
                        type = "group",
                        order = 10,
                        args = {}
                    },
                    pet = {
                        name = _G.PET,
                        type = "group",
                        order = 20,
                        args = {}
                    },
                    target = {
                        name = _G.TARGET,
                        type = "group",
                        order = 30,
                        args = {}
                    },
                    targettarget = {
                        name = _G.SHOW_TARGET_OF_TARGET_TEXT,
                        type = "group",
                        order = 40,
                        args = {}
                    },
                    focus = {
                        name = _G.FOCUS,
                        type = "group",
                        order = 50,
                        args = {}
                    },
                    focustarget = {
                        name = _G.BINDING_NAME_FOCUSTARGET,
                        type = "group",
                        order = 60,
                        args = {}
                    },
                }
            },
            groups = {
                name = _G.GROUPS,
                type = "group",
                childGroups = "tab",
                disabled = function() return not(RealUI:GetModuleEnabled(MODNAME)) end,
                order = 30,
                args = {
                    boss = {
                        name = _G.BOSS,
                        type = "group",
                        order = 10,
                        args = {
                        }
                    },
                    arena = {
                        name = _G.ARENA,
                        type = "group",
                        order = 20,
                        args = {
                            enabled = {
                                name = L["General_Enabled"],
                                desc = L["General_EnabledDesc"]:format("RealUI ".._G.SHOW_ARENA_ENEMY_FRAMES_TEXT),
                                type = "toggle",
                                get = function() return UnitFrames.db.profile.arena.enabled end,
                                set = function(info, value)
                                    UnitFrames.db.profile.arena.enabled = value
                                end,
                                order = 10,
                            },
                            options = {
                                name = "",
                                type = "group",
                                inline = true,
                                disabled = function() return not UnitFrames.db.profile.arena.enabled end,
                                order = 20,
                                args = {
                                    announceUse = {
                                        name = L["UnitFrames_AnnounceTrink"],
                                        desc = L["UnitFrames_AnnounceTrinkDesc"],
                                        type = "toggle",
                                        get = function() return UnitFrames.db.profile.arena.announceUse end,
                                        set = function(info, value)
                                            UnitFrames.db.profile.arena.announceUse = value
                                        end,
                                        order = 10,
                                    },
                                    announceChat = {
                                        name = _G.CHAT,
                                        desc = L["UnitFrames_AnnounceChatDesc"],
                                        type = "select",
                                        values = function()
                                            return {
                                                group = _G.INSTANCE_CHAT,
                                                say = _G.CHAT_MSG_SAY,
                                            }
                                        end,
                                        disabled = function() return not UnitFrames.db.profile.arena.announceUse end,
                                        get = function(info)
                                            return _G.strlower(UnitFrames.db.profile.arena.announceChat)
                                        end,
                                        set = function(info, value)
                                            UnitFrames.db.profile.arena.announceChat = value
                                        end,
                                        order = 20,
                                    },
                                    --[[showPets = {
                                        name = SHOW_ARENA_ENEMY_PETS_TEXT,
                                        desc = OPTION_TOOLTIP_SHOW_ARENA_ENEMY_PETS,
                                        type = "toggle",
                                        get = function() return db.arena.showPets end,
                                        set = function(info, value)
                                            db.arena.showPets = value
                                        end,
                                        order = 30,
                                    },
                                    showCast = {
                                        name = SHOW_ARENA_ENEMY_CASTBAR_TEXT,
                                        desc = OPTION_TOOLTIP_SHOW_ARENA_ENEMY_CASTBAR,
                                        type = "toggle",
                                        get = function() return db.arena.showCast end,
                                        set = function(info, value)
                                            db.arena.showCast = value
                                        end,
                                        order = 40,
                                    },]]
                                },
                            },
                        }
                    },
                    -- B15: the RealUIParty header shares the raid cells' style and
                    -- DB (units.raid), so party and raid are configured together
                    -- on one tab. Party-only settings (B31: own anchor +
                    -- orientation) live on the same tab; split it into its own
                    -- tab if they ever outgrow it.
                    raid = {
                        name = ("%s / %s"):format(_G.PARTY, _G.RAID),
                        type = "group",
                        childGroups = "tab",
                        order = 30,
                        args = {
                            sharedNote = {
                                name = "Party and raid frames share these cell settings. The party frames have their own anchor (RealUIPartyAnchor) — move it in config mode.",
                                type = "description",
                                order = 2,
                                fontSize = "medium",
                            },
                            grid2Note = {
                                name = "Grid2 is handling group frames — RealUI's built-in raid frames are inactive while it is enabled.",
                                type = "description",
                                hidden = not _G.Grid2,
                                order = 0,
                            },
                            grid2Config = {
                                name = "Grid 2",
                                type = "execute",
                                hidden = not _G.Grid2,
                                func = function(info, ...)
                                    _G.Grid2:OnChatCommand("")
                                end,
                                order = 1,
                            },
                            enabled = {
                                name = L["General_Enabled"] or "Enabled",
                                desc = "Show RealUI's built-in party/raid frames. Requires a UI reload.",
                                type = "toggle",
                                disabled = function() return _G.Grid2 ~= nil end,
                                get = function() return UnitFrames.db.profile.units.raid.enabled ~= false end,
                                set = function(info, value)
                                    UnitFrames.db.profile.units.raid.enabled = value
                                    if UnitFrames.RefreshRaid then UnitFrames:RefreshRaid() end
                                    -- Always prompt: the headers are spawn-time,
                                    -- so both enabling and disabling leave the
                                    -- frames in a stale layout until a reload.
                                    RealUI:ReloadUIDialog()
                                end,
                                order = 5,
                            },
                            -- B31: party orientation is a spawn-time header
                            -- attribute — see the note in Groups/Raid.lua's
                            -- RefreshRaid for why it is not applied live.
                            partyHorizontal = {
                                name = "Horizontal party layout",
                                desc = "Arrange the party frames in a row instead of a column. Requires a UI reload.",
                                type = "toggle",
                                disabled = function() return _G.Grid2 ~= nil end,
                                get = function()
                                    local rdb = UnitFrames.db.profile.units.raid
                                    return rdb.party and rdb.party.horizontal or false
                                end,
                                set = function(info, value)
                                    local rdb = UnitFrames.db.profile.units.raid
                                    rdb.party = rdb.party or {}
                                    rdb.party.horizontal = value
                                    RealUI:ReloadUIDialog()
                                end,
                                order = 6,
                            },
                            width = {
                                name = "Cell width",
                                desc = "Requires a UI reload.",
                                type = "range", min = 50, max = 140, step = 1,
                                disabled = function() return _G.Grid2 ~= nil end,
                                get = function() return UnitFrames.db.profile.units.raid.size.x end,
                                set = function(info, value)
                                    UnitFrames.db.profile.units.raid.size.x = value
                                    RealUI:ReloadUIDialog()
                                end,
                                order = 10,
                            },
                            height = {
                                name = "Cell height",
                                desc = "Requires a UI reload.",
                                type = "range", min = 20, max = 60, step = 1,
                                disabled = function() return _G.Grid2 ~= nil end,
                                get = function() return UnitFrames.db.profile.units.raid.size.y end,
                                set = function(info, value)
                                    UnitFrames.db.profile.units.raid.size.y = value
                                    RealUI:ReloadUIDialog()
                                end,
                                order = 11,
                            },
                            spacing = {
                                name = "Spacing",
                                desc = "Requires a UI reload.",
                                type = "range", min = 0, max = 10, step = 1,
                                disabled = function() return _G.Grid2 ~= nil end,
                                get = function() return UnitFrames.db.profile.units.raid.spacing end,
                                set = function(info, value)
                                    UnitFrames.db.profile.units.raid.spacing = value
                                    RealUI:ReloadUIDialog()
                                end,
                                order = 12,
                            },
                            rangeAlpha = {
                                name = "Out-of-range opacity",
                                type = "range", min = 0.1, max = 1, step = 0.05, isPercent = true,
                                disabled = function() return _G.Grid2 ~= nil end,
                                get = function() return UnitFrames.db.profile.units.raid.rangeAlpha end,
                                set = function(info, value)
                                    UnitFrames.db.profile.units.raid.rangeAlpha = value
                                    if UnitFrames.RefreshRaid then UnitFrames:RefreshRaid() end
                                end,
                                order = 13,
                            },
                            centerDebuff = {
                                name = "Dispellable debuff icon",
                                desc = "Requires a UI reload.",
                                type = "toggle",
                                disabled = function() return _G.Grid2 ~= nil end,
                                get = function() return UnitFrames.db.profile.units.raid.icons.centerDebuff end,
                                set = function(info, value)
                                    UnitFrames.db.profile.units.raid.icons.centerDebuff = value
                                    RealUI:ReloadUIDialog()
                                end,
                                order = 20,
                            },
                            hots = {
                                name = "My buffs icon",
                                desc = "Requires a UI reload.",
                                type = "toggle",
                                disabled = function() return _G.Grid2 ~= nil end,
                                get = function() return UnitFrames.db.profile.units.raid.icons.hots end,
                                set = function(info, value)
                                    UnitFrames.db.profile.units.raid.icons.hots = value
                                    RealUI:ReloadUIDialog()
                                end,
                                order = 21,
                            },
                            hotsCount = {
                                name = "My buffs shown",
                                type = "range", min = 1, max = 4, step = 1,
                                disabled = function() return _G.Grid2 ~= nil or not UnitFrames.db.profile.units.raid.icons.hots end,
                                get = function() return UnitFrames.db.profile.units.raid.icons.hotsCount or 2 end,
                                set = function(info, value)
                                    UnitFrames.db.profile.units.raid.icons.hotsCount = value
                                    if UnitFrames.RefreshRaid then UnitFrames:RefreshRaid() end
                                end,
                                order = 22,
                            },
                            hotsFilter = {
                                name = "HoTs/shields only",
                                desc = "Limit the left icons to a curated heal-over-time and shield list instead of all your buffs.",
                                type = "toggle",
                                disabled = function() return _G.Grid2 ~= nil or not UnitFrames.db.profile.units.raid.icons.hots end,
                                get = function() return UnitFrames.db.profile.units.raid.icons.hotsFilter ~= false end,
                                set = function(info, value)
                                    UnitFrames.db.profile.units.raid.icons.hotsFilter = value
                                    if UnitFrames.RefreshRaid then UnitFrames:RefreshRaid() end
                                end,
                                order = 23,
                            },
                        }
                    },
                }
            },
        },
    }

    local ufArgs = optArgs.unitframes.args
    CombatFader:AddFadeConfig("UnitFrames", ufArgs.general, 50, true)
    do -- import hideRaidFilters from minimap
        local MinimapAdv = RealUI:GetModule("MinimapAdv")
        ufArgs.groups.args.raid.args.hideRaidFilters = {
            type = "toggle",
            name = L["Raid_HideRaidFilter"],
            desc = L["Raid_HideRaidFilterDesc"],
            get = function(info) return MinimapAdv.db.profile.information.hideRaidFilters end,
            set = function(info, value)
                MinimapAdv.db.profile.information.hideRaidFilters = value
            end,
            order = 50,
        }
    end
    --[[ B112: filter/sort controls for one aura group.

         Built by a factory rather than written out per group — there are three
         groups already (player buffs, target buffs, target debuffs) and the
         focus/ToT frames are next, so hand-copying four option blocks each is
         how they drift apart.

         These four are LIVE: RefreshAuraElement re-applies filter, candidate
         filters and sort on the running container. The size slider sitting a
         few rows above is not, so the descriptions say which is which — the
         inconsistency is real and confuses people who assume one reload rule.

         `getGroup` is a closure, not a resolved table: AceDB hands out a new
         profile table on every profile switch, so a captured reference would
         write into the old profile after a spec swap (the B103 shape). ]]
    local function AddAuraFilterOptions(unit, getGroup, isEnabled, baseOrder, label, refreshEvent)
        local function refresh()
            UnitFrames:RefreshUnits(refreshEvent)
        end
        local function values(source)
            local out = {}
            for key, def in next, source do out[key] = def.name end
            return out
        end
        local function sorting(source)
            local keys = {}
            for key in next, source do keys[#keys + 1] = key end
            table.sort(keys, function(a, b) return source[a].order < source[b].order end)
            return keys
        end

        unit.args[label .. "FilterPreset"] = {
            name = "Show",
            desc = "Which " .. label .. " appear. Applies immediately — no reload needed.",
            type = "select",
            values = function() return values(UnitFrames.auraFilterPresets) end,
            sorting = function() return sorting(UnitFrames.auraFilterPresets) end,
            order = baseOrder,
            disabled = function() return not isEnabled() end,
            get = function() return getGroup().filterPreset or "all" end,
            set = function(_, val) getGroup().filterPreset = val; refresh() end,
        }
        unit.args[label .. "Sort"] = {
            name = "Sort by",
            desc = "Order the icons are laid out in. Applies immediately.",
            type = "select",
            values = function() return values(UnitFrames.auraSortMethods) end,
            sorting = function() return sorting(UnitFrames.auraSortMethods) end,
            order = baseOrder + 1,
            disabled = function() return not isEnabled() end,
            get = function() return getGroup().sort or "default" end,
            set = function(_, val) getGroup().sort = val; refresh() end,
        }
        unit.args[label .. "SortReverse"] = {
            name = "Reverse order",
            type = "toggle",
            order = baseOrder + 2,
            disabled = function() return not isEnabled() or (getGroup().sort or "default") == "default" end,
            get = function() return getGroup().sortReverse and true or false end,
            set = function(_, val) getGroup().sortReverse = val; refresh() end,
        }
        unit.args[label .. "MaxDuration"] = {
            name = "Hide longer than",
            desc = "Seconds. 0 shows everything. Any other value also hides permanent auras,"
                .. " which is usually the point — it leaves only what is actually ticking.",
            type = "range",
            min = 0, max = 600, step = 5,
            order = baseOrder + 3,
            disabled = function() return not isEnabled() end,
            get = function() return getGroup().maxDuration or 0 end,
            set = function(_, val) getGroup().maxDuration = val; refresh() end,
        }
    end

    --[[ B122/B123: pin a secondary frame to the primary it belongs to.

         Only the SECONDARY frames get this. Anchoring the player frame to the
         target frame is not a thing anyone wants, and offering it would just
         invite someone to build a cycle.

         Everything this needs already existed — pet and ToT are registered
         with `FramePoint:PositionFrame` (Units/Pet.lua:35,
         Units/TargetTarget.lua:34), `FramePoint.ANCHOR_FRAMES` already
         resolves player/target/focus, and `SetAnchorTo` already rewrites the
         offsets between coordinate spaces so the frame does not jump. This is
         the same control the cast bars and class resource have shipped since
         B12; the unit panels simply never exposed it. ]]
    local ANCHORABLE_UNITS = {
        pet          = "player",
        targettarget = "target",
        focustarget  = "focus",
    }

    --[[ Is FramePoint driving this frame instead of the positioner?

         The condition is `framePoint.x`, NOT `anchorTo`. `RestorePosition`
         acts on any frame with saved coordinates, so a frame that was merely
         DRAGGED is just as detached from the positioner as one that was
         pinned — the documented B93 behaviour, restated in
         `FramePoint:ShiftScreenAnchored`'s own comment: *"A managed frame
         follows its positioner only while it has NEVER been dragged."*

         Keying the check on `anchorTo` would re-enable the offset boxes as
         soon as someone set Anchor To back to Screen, at which point they
         would look live and still do nothing. ]]
    local function IsFramePointControlled(unitSlug)
        local unitDB = UnitFrames.db.profile.units[unitSlug]
        local fp = unitDB and unitDB.framePoint
        return (fp and fp.x) ~= nil
    end

    local units = ufArgs.units.args
    for unitSlug, unit in next, units do
        --[[ The offset inputs below write `db.profile.positions[layout][unit]`,
             which is the HuD POSITIONER value — a different coordinate system
             from the FramePoint offsets a pinned frame rides on. Once a frame
             is pinned, the positioner is out of the chain and typing in these
             boxes does nothing visible.

             They are disabled rather than hidden while pinned. B59 in the beta
             feedback is exactly this failure — "options panel offers settings
             the layout engine overwrites" — and a control that silently does
             nothing is the same bug wearing a different hat. ]]
        local function OffsetsDisabled()
            return IsFramePointControlled(unitSlug)
        end
        local offsetPinnedDesc = "\n\n|cffffcc00Disabled because this frame has been moved by"
            .. " dragging or pinning, which hands it to the frame mover — these offsets no longer"
            .. " drive it. Drag the frame itself to adjust.|r"

        unit.args.x = {
            name = L["General_XOffset"],
            desc = offsetPinnedDesc,
            type = "input",
            order = 10,
            disabled = OffsetsDisabled,
            get = function(info) return tostring(UnitFrames.db.profile.positions[safeLayout()][unitSlug].x) end,
            set = function(info, value)
                value = ValidateOffset(value)
                UnitFrames.db.profile.positions[safeLayout()][unitSlug].x = value
                UnitFrames:RepositionFrames()
            end,
        }
        unit.args.y = {
            name = L["General_YOffset"],
            desc = offsetPinnedDesc,
            type = "input",
            order = 20,
            disabled = OffsetsDisabled,
            get = function(info) return tostring(UnitFrames.db.profile.positions[safeLayout()][unitSlug].y) end,
            set = function(info, value)
                value = ValidateOffset(value)
                UnitFrames.db.profile.positions[safeLayout()][unitSlug].y = value
                UnitFrames:RepositionFrames()
            end,
        }
        if ANCHORABLE_UNITS[unitSlug] then
            local suggested = ANCHORABLE_UNITS[unitSlug]
            unit.args.anchorTo = {
                name = "Anchor To",
                desc = ("Pin this frame to a unit frame so it follows that frame, or leave it on the screen.")
                    .. ("\n\nSuggested: |cff00ff00%s|r."):format(ANCHOR_TO_VALUES[suggested])
                    .. "\n\nThis frame already starts out positioned relative to "
                    .. ANCHOR_TO_VALUES[suggested]
                    .. ", but that link is lost the moment the frame is dragged. Pinning restores it"
                    .. " permanently — the offset is stored against the anchor, so the frame keeps"
                    .. " following it however either one moves."
                    .. "\n\nWhen pinned, the X/Y offsets above stop applying. Drag the frame to"
                    .. " fine-tune; the drag is saved as an offset from the anchor.",
                type = "select",
                values = ANCHOR_TO_VALUES,
                sorting = ANCHOR_TO_ORDER,
                order = 5,
                get = function()
                    local unitDB = UnitFrames.db.profile.units[unitSlug]
                    return (unitDB and unitDB.framePoint and unitDB.framePoint.anchorTo) or "screen"
                end,
                set = function(_, value)
                    -- Must go through SetAnchorTo: it captures where the frame
                    -- currently sits and rewrites x/y into the new coordinate
                    -- space, so switching modes never teleports the frame.
                    FramePoint:SetAnchorTo(UnitFrames,
                        {"profile", "units", unitSlug, "framePoint"}, value)
                end,
            }
        end
        -- reverseFill is generic (GetReverseFill/RefreshUnits key off db.units[unit]
        -- for any unit), so it applies to every frame with a health bar, not just
        -- player/target. Pet and TargetTarget inherit their parent frame's
        -- direction (pet→player, targettarget→target) automatically; their own
        -- toggle flips them relative to that inherited direction.
        if unitSlug == "player" or unitSlug == "target"
            or unitSlug == "pet" or unitSlug == "targettarget" then
            unit.args.reverseFill = {
                name = L["UnitFrames_ReverseFill"],
                desc = L["UnitFrames_ReverseFillDesc"],
                type = "toggle",
                order = 25,
                get = function() return UnitFrames.db.profile.units[unitSlug].reverseFill end,
                set = function(info, value)
                    UnitFrames.db.profile.units[unitSlug].reverseFill = value
                    UnitFrames:RefreshUnits("ReverseFill")
                end,
            }
        end
        if unitSlug == "player" or unitSlug == "target" then
            unit.args.reversePercent = {
                name = L["UnitFrames_ReversePercent"],
                desc = L["UnitFrames_ReversePercentDesc"],
                type = "toggle",
                order = 26,
                get = function() return UnitFrames.db.profile.units[unitSlug].reversePercent end,
                set = function(info, value)
                    UnitFrames.db.profile.units[unitSlug].reversePercent = value
                    UnitFrames:RefreshUnits("ReversePercent")
                end,
            }
        end
        if unitSlug == "player" then
            unit.args.showPlayerBuffs = {
                name = "Show Player Buffs",
                type = "toggle",
                order = 35,
                get = function() return UnitFrames.db.profile.units.player.showPlayerBuffs end,
                set = function(_, val)
                    UnitFrames.db.profile.units.player.showPlayerBuffs = val
                    UnitFrames:RefreshUnits("PlayerAuras")
                end,
            }
            unit.args.buffCount = {
                name = L["UnitFrames_BuffCount"],
                type = "range",
                min = 0, max = 40, step = 1,
                order = 36,
                disabled = function() return not UnitFrames.db.profile.units.player.showPlayerBuffs end,
                get = function() return UnitFrames.db.profile.units.player.buffCount end,
                set = function(_, val)
                    UnitFrames.db.profile.units.player.buffCount = val
                    UnitFrames:RefreshUnits("PlayerAuras")
                end,
            }
            unit.args.buffSize = {
                name = L["UnitFrames_BuffSize"],
                type = "range",
                min = 10, max = 60, step = 1,
                order = 37,
                disabled = function() return not UnitFrames.db.profile.units.player.showPlayerBuffs end,
                get = function() return UnitFrames.db.profile.units.player.buffSize end,
                set = function(_, val)
                    UnitFrames.db.profile.units.player.buffSize = val
                    UnitFrames:RefreshUnits("PlayerAuras")
                end,
            }
            unit.args.buffLayoutHeader = {
                name = "Buff Layout",
                type = "header",
                order = 38,
            }
            unit.args.buffAnchor = {
                name = L["UnitFrames_AuraLayoutBuffAnchor"],
                desc = L["UnitFrames_AuraLayoutBuffAnchorDesc"],
                type = "select",
                values = function() return {
                    BOTTOMLEFT = "Bottom Left",
                    BOTTOMRIGHT = "Bottom Right",
                    TOPLEFT = "Top Left",
                    TOPRIGHT = "Top Right",
                    LEFTTOP = "Left Top",
                    LEFTBOTTOM = "Left Bottom",
                    RIGHTTOP = "Right Top",
                    RIGHTBOTTOM = "Right Bottom",
                    LEFT = "Left",
                    RIGHT = "Right",
                } end,
                order = 39,
                disabled = function() return not UnitFrames.db.profile.units.player.showPlayerBuffs end,
                get = function() return UnitFrames.db.profile.units.player.auraLayout.buffs.anchor end,
                set = function(_, val)
                    UnitFrames.db.profile.units.player.auraLayout.buffs.anchor = val
                    UnitFrames:RefreshUnits("PlayerAurasLayout")
                end,
            }
            unit.args.buffGrowthX = {
                name = L["UnitFrames_AuraLayoutBuffGrowthX"],
                desc = L["UnitFrames_AuraLayoutBuffGrowthXDesc"],
                type = "select",
                values = function() return {
                    LEFT = "Left",
                    RIGHT = "Right",
                } end,
                order = 40,
                disabled = function() return not UnitFrames.db.profile.units.player.showPlayerBuffs end,
                get = function() return UnitFrames.db.profile.units.player.auraLayout.buffs.growthX end,
                set = function(_, val)
                    UnitFrames.db.profile.units.player.auraLayout.buffs.growthX = val
                    UnitFrames:RefreshUnits("PlayerAurasLayout")
                end,
            }
            unit.args.buffGrowthY = {
                name = L["UnitFrames_AuraLayoutBuffGrowthY"],
                desc = L["UnitFrames_AuraLayoutBuffGrowthYDesc"],
                type = "select",
                values = function() return {
                    DOWN = "Down",
                    UP = "Up",
                } end,
                order = 41,
                disabled = function() return not UnitFrames.db.profile.units.player.showPlayerBuffs end,
                get = function() return UnitFrames.db.profile.units.player.auraLayout.buffs.growthY end,
                set = function(_, val)
                    UnitFrames.db.profile.units.player.auraLayout.buffs.growthY = val
                    UnitFrames:RefreshUnits("PlayerAurasLayout")
                end,
            }
            unit.args.buffMaxWidth = {
                name = L["UnitFrames_AuraLayoutBuffMaxWidth"],
                desc = L["UnitFrames_AuraLayoutBuffMaxWidthDesc"],
                type = "range",
                min = 0, max = 400, step = 5,
                order = 42,
                disabled = function() return not UnitFrames.db.profile.units.player.showPlayerBuffs end,
                get = function() return UnitFrames.db.profile.units.player.auraLayout.buffs.maxWidth end,
                set = function(_, val)
                    UnitFrames.db.profile.units.player.auraLayout.buffs.maxWidth = val
                    UnitFrames:RefreshUnits("PlayerAurasLayout")
                end,
            }
            AddAuraFilterOptions(unit,
                function() return UnitFrames.db.profile.units.player.auraLayout.buffs end,
                function() return UnitFrames.db.profile.units.player.showPlayerBuffs end,
                43, "buff", "PlayerAurasLayout")
        end
        if unitSlug == "target" then
            unit.args.showTargetDebuffs = {
                name = "Show Target Debuffs",
                type = "toggle",
                order = 35,
                get = function() return UnitFrames.db.profile.units.target.showTargetDebuffs end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.showTargetDebuffs = val
                    UnitFrames:RefreshUnits("TargetAuras")
                end,
            }
            unit.args.debuffCount = {
                name = L["UnitFrames_DebuffCount"],
                type = "range",
                min = 0, max = 40, step = 1,
                order = 36,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetDebuffs end,
                get = function() return UnitFrames.db.profile.units.target.debuffCount end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.debuffCount = val
                    UnitFrames:RefreshUnits("TargetAuras")
                end,
            }
            unit.args.debuffSize = {
                name = L["UnitFrames_DebuffSize"],
                type = "range",
                min = 10, max = 60, step = 1,
                order = 37,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetDebuffs end,
                get = function() return UnitFrames.db.profile.units.target.debuffSize end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.debuffSize = val
                    UnitFrames:RefreshUnits("TargetAuras")
                end,
            }
            unit.args.showTargetBuffs = {
                name = "Show Target Buffs",
                type = "toggle",
                order = 38,
                get = function() return UnitFrames.db.profile.units.target.showTargetBuffs end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.showTargetBuffs = val
                    UnitFrames:RefreshUnits("TargetAuras")
                end,
            }
            unit.args.buffCount = {
                name = L["UnitFrames_BuffCount"],
                type = "range",
                min = 0, max = 40, step = 1,
                order = 39,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetBuffs end,
                get = function() return UnitFrames.db.profile.units.target.buffCount end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.buffCount = val
                    UnitFrames:RefreshUnits("TargetAuras")
                end,
            }
            unit.args.buffSize = {
                name = L["UnitFrames_BuffSize"],
                type = "range",
                min = 10, max = 60, step = 1,
                order = 40,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetBuffs end,
                get = function() return UnitFrames.db.profile.units.target.buffSize end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.buffSize = val
                    UnitFrames:RefreshUnits("TargetAuras")
                end,
            }
            -- Debuff Layout Options
            unit.args.debuffLayoutHeader = {
                name = "Debuff Layout",
                type = "header",
                order = 41,
            }
            unit.args.debuffAnchor = {
                name = L["UnitFrames_AuraLayoutDebuffAnchor"],
                desc = L["UnitFrames_AuraLayoutDebuffAnchorDesc"],
                type = "select",
                values = function() return {
                    BOTTOMLEFT = "Bottom Left",
                    BOTTOMRIGHT = "Bottom Right",
                    TOPLEFT = "Top Left",
                    TOPRIGHT = "Top Right",
                    LEFTTOP = "Left Top",
                    LEFTBOTTOM = "Left Bottom",
                    RIGHTTOP = "Right Top",
                    RIGHTBOTTOM = "Right Bottom",
                    LEFT = "Left",
                    RIGHT = "Right",
                } end,
                order = 42,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetDebuffs end,
                get = function() return UnitFrames.db.profile.units.target.auraLayout.debuffs.anchor end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.auraLayout.debuffs.anchor = val
                    UnitFrames:RefreshUnits("TargetAurasLayout")
                end,
            }
            unit.args.debuffGrowthX = {
                name = L["UnitFrames_AuraLayoutDebuffGrowthX"],
                desc = L["UnitFrames_AuraLayoutDebuffGrowthXDesc"],
                type = "select",
                values = function() return {
                    LEFT = "Left",
                    RIGHT = "Right",
                } end,
                order = 43,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetDebuffs end,
                get = function() return UnitFrames.db.profile.units.target.auraLayout.debuffs.growthX end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.auraLayout.debuffs.growthX = val
                    UnitFrames:RefreshUnits("TargetAurasLayout")
                end,
            }
            unit.args.debuffGrowthY = {
                name = L["UnitFrames_AuraLayoutDebuffGrowthY"],
                desc = L["UnitFrames_AuraLayoutDebuffGrowthYDesc"],
                type = "select",
                values = function() return {
                    DOWN = "Down",
                    UP = "Up",
                } end,
                order = 44,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetDebuffs end,
                get = function() return UnitFrames.db.profile.units.target.auraLayout.debuffs.growthY end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.auraLayout.debuffs.growthY = val
                    UnitFrames:RefreshUnits("TargetAurasLayout")
                end,
            }
            unit.args.debuffMaxWidth = {
                name = L["UnitFrames_AuraLayoutDebuffMaxWidth"],
                desc = L["UnitFrames_AuraLayoutDebuffMaxWidthDesc"],
                type = "range",
                min = 0, max = 400, step = 5,
                order = 45,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetDebuffs end,
                get = function() return UnitFrames.db.profile.units.target.auraLayout.debuffs.maxWidth end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.auraLayout.debuffs.maxWidth = val
                    UnitFrames:RefreshUnits("TargetAurasLayout")
                end,
            }
            -- Buff Layout Options
            unit.args.buffLayoutHeader = {
                name = "Buff Layout",
                type = "header",
                order = 46,
            }
            unit.args.buffAnchor = {
                name = L["UnitFrames_AuraLayoutBuffAnchor"],
                desc = L["UnitFrames_AuraLayoutBuffAnchorDesc"],
                type = "select",
                values = function() return {
                    BOTTOMLEFT = "Bottom Left",
                    BOTTOMRIGHT = "Bottom Right",
                    TOPLEFT = "Top Left",
                    TOPRIGHT = "Top Right",
                    LEFTTOP = "Left Top",
                    LEFTBOTTOM = "Left Bottom",
                    RIGHTTOP = "Right Top",
                    RIGHTBOTTOM = "Right Bottom",
                    LEFT = "Left",
                    RIGHT = "Right",
                } end,
                order = 47,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetBuffs end,
                get = function() return UnitFrames.db.profile.units.target.auraLayout.buffs.anchor end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.auraLayout.buffs.anchor = val
                    UnitFrames:RefreshUnits("TargetAurasLayout")
                end,
            }
            unit.args.buffGrowthX = {
                name = L["UnitFrames_AuraLayoutBuffGrowthX"],
                desc = L["UnitFrames_AuraLayoutBuffGrowthXDesc"],
                type = "select",
                values = function() return {
                    LEFT = "Left",
                    RIGHT = "Right",
                } end,
                order = 48,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetBuffs end,
                get = function() return UnitFrames.db.profile.units.target.auraLayout.buffs.growthX end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.auraLayout.buffs.growthX = val
                    UnitFrames:RefreshUnits("TargetAurasLayout")
                end,
            }
            unit.args.buffGrowthY = {
                name = L["UnitFrames_AuraLayoutBuffGrowthY"],
                desc = L["UnitFrames_AuraLayoutBuffGrowthYDesc"],
                type = "select",
                values = function() return {
                    DOWN = "Down",
                    UP = "Up",
                } end,
                order = 49,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetBuffs end,
                get = function() return UnitFrames.db.profile.units.target.auraLayout.buffs.growthY end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.auraLayout.buffs.growthY = val
                    UnitFrames:RefreshUnits("TargetAurasLayout")
                end,
            }
            unit.args.buffMaxWidth = {
                name = L["UnitFrames_AuraLayoutBuffMaxWidth"],
                desc = L["UnitFrames_AuraLayoutBuffMaxWidthDesc"],
                type = "range",
                min = 0, max = 400, step = 5,
                order = 50,
                disabled = function() return not UnitFrames.db.profile.units.target.showTargetBuffs end,
                get = function() return UnitFrames.db.profile.units.target.auraLayout.buffs.maxWidth end,
                set = function(_, val)
                    UnitFrames.db.profile.units.target.auraLayout.buffs.maxWidth = val
                    UnitFrames:RefreshUnits("TargetAurasLayout")
                end,
            }
            AddAuraFilterOptions(unit,
                function() return UnitFrames.db.profile.units.target.auraLayout.debuffs end,
                function() return UnitFrames.db.profile.units.target.showTargetDebuffs end,
                51, "debuff", "TargetAurasLayout")
            AddAuraFilterOptions(unit,
                function() return UnitFrames.db.profile.units.target.auraLayout.buffs end,
                function() return UnitFrames.db.profile.units.target.showTargetBuffs end,
                55, "buff", "TargetAurasLayout")
        end
        -- The anchor-width slider drives the shared UFHorizontal position key
        -- (the gap between the player and target frames), so it only belongs
        -- on the two anchored frames.
        if unitSlug == "player" or unitSlug == "target" then
            unit.args.anchorWidth = {
                name = L["UnitFrames_AnchorWidth"],
                desc = L["UnitFrames_AnchorWidthDesc"],
                type = "range",
                width = "full",
                min = 0,
                max = round(uiWidth * 0.5),
                step = 1,
                bigStep = 4,
                order = 30,
                get = function(info)
                    local pos = safePositions()
                    return pos and pos["UFHorizontal"] or 200
                end,
                set = function(info, value)
                    local pos = safePositions()
                    if pos then
                        writePosition("UFHorizontal", value)
                        RealUI:UpdatePositioners()
                    end
                end,
            }
        end
        -- B14: per-unit width/height for every unit frame. All six units go
        -- through db.units[unit].size + UnitFrames:ResizeFrames(), which uses
        -- the frame's ApplySize (defined for all angled frames). The small
        -- frames (pet/ToT/focus/focustarget) get smaller ranges to match
        -- their defaults (126-138 x 10-13).
        local isBigFrame = unitSlug == "player" or unitSlug == "target"
        unit.args.frameSizeHeader = {
            name = "Frame Size",
            type = "header",
            order = 31,
        }
        unit.args.frameWidth = {
            name = L["HuD_Width"],
            type = "range",
            min = isBigFrame and 150 or 60,
            max = isBigFrame and 400 or 300,
            step = 1, bigStep = 5,
            order = 32,
            get = function()
                return UnitFrames.db.profile.units[unitSlug].size.x
            end,
            set = function(_, val)
                UnitFrames.db.profile.units[unitSlug].size.x = val
                UnitFrames:ResizeFrames()
            end,
        }
        unit.args.frameHeight = {
            name = L["HuD_Height"],
            type = "range",
            min = isBigFrame and 18 or 8,
            max = isBigFrame and 50 or 30,
            step = 1, bigStep = 2,
            order = 33,
            get = function()
                return UnitFrames.db.profile.units[unitSlug].size.y
            end,
            set = function(_, val)
                UnitFrames.db.profile.units[unitSlug].size.y = val
                UnitFrames:ResizeFrames()
            end,
        }
    end
    local groups = ufArgs.groups.args
    for groupSlug, group in next, groups do
        if groupSlug == "boss" or groupSlug == "arena" then
            local args = groupSlug == "boss" and group.args or group.args.options.args
            args.horizontal = {
                name = L["HuD_Horizontal"],
                type = "range",
                width = "full",
                min = -round(uiWidth * 0.85),
                max = -30,
                step = 1,
                bigStep = 4,
                get = function(info)
                    local pos = safePositions()
                    return pos and pos["BossX"] or -32
                end,
                set = function(info, value)
                    local pos = safePositions()
                    if pos then
                        writePosition("BossX", value)
                        RealUI:UpdatePositioners()
                    end
                end,
                order = 2,
            }
            args.vertical = {
                name = L["HuD_Vertical"],
                type = "range",
                width = "full",
                min = -round(uiHeight * 0.4),
                max = round(uiHeight * 0.4),
                step = 1,
                bigStep = 2,
                get = function(info)
                    local pos = safePositions()
                    return pos and pos["BossY"] or 314
                end,
                set = function(info, value)
                    local pos = safePositions()
                    if pos then
                        writePosition("BossY", value)
                        RealUI:UpdatePositioners()
                    end
                end,
                order = 4,
            }
            args.gap = {
                name = L["UnitFrames_Gap"],
                desc = L["UnitFrames_GapDesc"],
                type = "range",
                min = 0, max = 10, step = 1,
                get = function(info) return UnitFrames.db.profile.boss.gap end,
                set = function(info, value) UnitFrames.db.profile.boss.gap = value end,
                order = 6,
            }
            if groupSlug == "boss" then
                args.altPowerOnly = {
                    name = "Power Bar Only With Alt Power",
                    desc = "Hide the boss power bar unless the encounter provides alternative power. Leaving this off keeps boss mana visible on drain/interrupt fights.",
                    type = "toggle",
                    width = "full",
                    order = 8,
                    get = function() return UnitFrames.db.profile.boss.altPowerOnly end,
                    set = function(_, val)
                        UnitFrames.db.profile.boss.altPowerOnly = val
                        UnitFrames:RefreshUnits("BossAltPower")
                    end,
                }
                args.showBossDebuffs = {
                    name = "Show Boss Debuffs",
                    type = "toggle",
                    order = 10,
                    get = function() return UnitFrames.db.profile.boss.showBossDebuffs end,
                    set = function(_, val)
                        UnitFrames.db.profile.boss.showBossDebuffs = val
                        UnitFrames:RefreshUnits("BossAuras")
                    end,
                }
                args.debuffCount = {
                    name = L["UnitFrames_DebuffCount"],
                    type = "range",
                    min = 0, max = 40, step = 1,
                    order = 11,
                    disabled = function() return not UnitFrames.db.profile.boss.showBossDebuffs end,
                    get = function() return UnitFrames.db.profile.boss.debuffCount end,
                    set = function(_, val)
                        UnitFrames.db.profile.boss.debuffCount = val
                        UnitFrames:RefreshUnits("BossAuras")
                    end,
                }
                args.debuffSize = {
                    name = L["UnitFrames_DebuffSize"],
                    type = "range",
                    min = 10, max = 60, step = 1,
                    order = 12,
                    disabled = function() return not UnitFrames.db.profile.boss.showBossDebuffs end,
                    get = function() return UnitFrames.db.profile.boss.debuffSize end,
                    set = function(_, val)
                        UnitFrames.db.profile.boss.debuffSize = val
                        UnitFrames:RefreshUnits("BossAuras")
                    end,
                }
                args.showBossBuffs = {
                    name = "Show Boss Buffs",
                    type = "toggle",
                    order = 13,
                    get = function() return UnitFrames.db.profile.boss.showBossBuffs end,
                    set = function(_, val)
                        UnitFrames.db.profile.boss.showBossBuffs = val
                        UnitFrames:RefreshUnits("BossAuras")
                    end,
                }
                args.buffCount = {
                    name = L["UnitFrames_BuffCount"],
                    type = "range",
                    min = 0, max = 40, step = 1,
                    order = 14,
                    disabled = function() return not UnitFrames.db.profile.boss.showBossBuffs end,
                    get = function() return UnitFrames.db.profile.boss.buffCount end,
                    set = function(_, val)
                        UnitFrames.db.profile.boss.buffCount = val
                        UnitFrames:RefreshUnits("BossAuras")
                    end,
                }
                args.buffSize = {
                    name = L["UnitFrames_BuffSize"],
                    type = "range",
                    min = 10, max = 60, step = 1,
                    order = 15,
                    disabled = function() return not UnitFrames.db.profile.boss.showBossBuffs end,
                    get = function() return UnitFrames.db.profile.boss.buffSize end,
                    set = function(_, val)
                        UnitFrames.db.profile.boss.buffSize = val
                        UnitFrames:RefreshUnits("BossAuras")
                    end,
                }
            end
        end
    end
end
do -- CastBars
    debug("HuD CastBars")
    local MODNAME = "CastBars"
    local CastBars = RealUI:GetModule(MODNAME)

    local function CreateFrameOptions(unit, order)
        return {
            name = _G[unit:upper()],
            type = "group",
            disabled = function(info)
                return not RealUI:GetModuleEnabled(MODNAME)
            end,
            order = order,
            args = {
                scale = {
                    name = L["General_Scale"] or "Scale",
                    type = "range",
                    min = 0.5, max = 2.0, step = 0.05,
                    isPercent = true,
                    order = 0.5,
                    get = function() return CastBars.db.profile[unit].scale end,
                    set = function(info, value)
                        CastBars.db.profile[unit].scale = value
                        CastBars:UpdateSettings(unit)
                    end,
                },
                reverse = {
                    name = L["HuD_ReverseBars"],
                    type = "toggle",
                    get = function() return CastBars.db.profile[unit].reverse end,
                    set = function(info, value)
                        CastBars.db.profile[unit].reverse = value
                        CastBars:UpdateSettings(unit)
                    end,
                    order = 1,
                },
                showGCD = {
                    name = _G.SHOW_GLOBAL_COOLDOWN or "Show Global Cooldown",
                    desc = "Show the global cooldown on the cast bar (requires /reload)",
                    type = "toggle",
                    hidden = unit ~= "player",
                    get = function() return CastBars.db.profile[unit].showGCD end,
                    set = function(info, value)
                        CastBars.db.profile[unit].showGCD = value
                    end,
                    order = 1.5,
                },
                text = {
                    name = _G.LOCALE_TEXT_LABEL,
                    type = "select",
                    hidden = unit == "focus",
                    values = RealUI.globals.cornerPoints,
                    get = function(info)
                        for k,v in next, RealUI.globals.cornerPoints do
                            if v == CastBars.db.profile[unit].text then return k end
                        end
                    end,
                    set = function(info, value)
                        CastBars.db.profile[unit].text = RealUI.globals.cornerPoints[value]
                        CastBars:UpdateSettings(unit)
                    end,
                    order = 2,
                },
                position = {
                    name = L["General_Position"],
                    type = "group",
                    inline = true,
                    order = 3,
                    args = {
                        anchorTo = {
                            name = "Anchor To",
                            desc = "Anchor this cast bar to the screen, or pin it to a unit frame so it follows that frame."
                                .. "\n\nWhen pinned, the offsets below are measured from the unit frame instead of the screen.",
                            type = "select",
                            values = ANCHOR_TO_VALUES,
                            sorting = ANCHOR_TO_ORDER,
                            get = function(info)
                                return CastBars.db.profile[unit].position.anchorTo or "screen"
                            end,
                            set = function(info, value)
                                -- Goes through SetAnchorTo so the offsets are
                                -- rewritten into the new coordinate space and
                                -- the bar does not jump.
                                FramePoint:SetAnchorTo(CastBars, {"profile", unit, "position"}, value)
                            end,
                            order = 5,
                        },
                        point = {
                            name = L["General_AnchorPoint"],
                            type = "select",
                            values = RealUI.globals.anchorPoints,
                            get = function(info)
                                for k,v in next, RealUI.globals.anchorPoints do
                                    if v == CastBars.db.profile[unit].position.point then return k end
                                end
                            end,
                            set = function(info, value)
                                CastBars.db.profile[unit].position.point = RealUI.globals.anchorPoints[value]
                                FramePoint:RestorePosition(CastBars)
                            end,
                            order = 10,
                        },
                        x = {
                            name = L["General_XOffset"],
                            desc = L["General_XOffsetDesc"],
                            type = "input",
                            dialogControl = "NumberEditBox",
                            get = function(info)
                                return _G.tostring(CastBars.db.profile[unit].position.x)
                            end,
                            set = function(info, value)
                                CastBars.db.profile[unit].position.x = round(_G.tonumber(value), 1)
                                FramePoint:RestorePosition(CastBars)
                            end,
                            order = 11,
                        },
                        y = {
                            name = L["General_YOffset"],
                            desc = L["General_YOffsetDesc"],
                            type = "input",
                            dialogControl = "NumberEditBox",
                            get = function(info) return _G.tostring(CastBars.db.profile[unit].position.y) end,
                            set = function(info, value)
                                CastBars.db.profile[unit].position.y = round(_G.tonumber(value), 1)
                                FramePoint:RestorePosition(CastBars)
                            end,
                            order = 12,
                        },
                    }
                }
            }
        }
    end

    do -- Nameplates (RealUI_Nameplates standalone addon)
        local Nameplates = _G.LibStub("AceAddon-3.0"):GetAddon("RealUI_Nameplates", true)
        if Nameplates and Nameplates.GetConfigOptions then
            local nameplateOpts = Nameplates:GetConfigOptions()
            nameplateOpts.name = "Nameplates"
            nameplateOpts.icon = "crosshairs"
            nameplateOpts.order = 5 -- must be unique and contiguous; drives the HuD bar button slot
            optArgs.nameplates = nameplateOpts
        end
    end
    optArgs.castbars = {
        name = L[MODNAME],
        icon = "bolt",
        type = "group",
        childGroups = "tab",
        order = 3,
        args = {
            enable = {
                name = L["General_Enabled"],
                desc = L["General_EnabledDesc"]:format(L[MODNAME]),
                type = "toggle",
                get = function(info) return RealUI:GetModuleEnabled(MODNAME) end,
                set = function(info, value)
                    RealUI:SetModuleEnabled("CastBars", value)
                    CloseHuDWindow()
                    RealUI:ReloadUIDialog()
                end,
                order = 1,
            },
            lock = {
                name = L["General_Lock"],
                desc = L["General_LockDesc"],
                type = "toggle",
                disabled = function(info)
                    return not RealUI:GetModuleEnabled(MODNAME)
                end,
                get = function(info) return FramePoint:IsModLocked(CastBars) end,
                set = function(info, value)
                    if value then
                        FramePoint:LockMod(CastBars)
                    else
                        FramePoint:UnlockMod(CastBars)
                    end
                end,
                order = 2,
            },
            player = CreateFrameOptions("player", 10),
            target = CreateFrameOptions("target", 20),
            focus = CreateFrameOptions("focus", 30),
        }
    }
end
do -- ClassResource
    debug("HuD ClassResource")
    local MODNAME = "ClassResource"
    local ClassResource = RealUI:GetModule(MODNAME)

    local points, bars = ClassResource:GetResources()
    debug("points and bars", points, bars)
    if points or bars then
        local barOptions, pointOptions
        pointOptions = {
            name = points.name,
            type = "group",
            disabled = function(info)
                return not RealUI:GetModuleEnabled(MODNAME)
            end,
            order = 20,
            args = {
                hideempty = {
                    name = L["Resource_HideUnused"]:format(points.name),
                    desc = L["Resource_HideUnusedDesc"]:format(points.name),
                    type = "toggle",
                    hidden = RealUI.charInfo.class.token == "DEATHKNIGHT",
                    get = function(info) return ClassResource.db.class.points.hideempty end,
                    set = function(info, value)
                        ClassResource.db.class.points.hideempty = value
                        ClassResource:ForceUpdate()
                    end,
                    order = 1,
                },
                reverse = {
                    name = L["Resource_Reverse"],
                    desc = L["Resource_ReverseDesc"]:format(points.name),
                    type = "toggle",
                    hidden = points.token ~= "COMBO_POINTS",
                    get = function(info) return ClassResource.db.class.points.reverse end,
                    set = function(info, value)
                        ClassResource.db.class.points.reverse = value
                        ClassResource:SettingsUpdate("points", "gap")
                    end,
                    order = 2,
                },
                width = {
                    name = L["HuD_Width"],
                    type = "input",
                    hidden = RealUI.charInfo.class.token ~= "DEATHKNIGHT",
                    get = function(info) return tostring(ClassResource.db.class.points.size.width) end,
                    set = function(info, value)
                        ClassResource.db.class.points.size.width = value
                        ClassResource:SettingsUpdate("points", "size")
                    end,
                    order = 10,
                },
                height = {
                    name = L["HuD_Height"],
                    type = "input",
                    hidden = RealUI.charInfo.class.token ~= "DEATHKNIGHT",
                    get = function(info) return tostring(ClassResource.db.class.points.size.height) end,
                    set = function(info, value)
                        ClassResource.db.class.points.size.height = value
                        ClassResource:SettingsUpdate("points", "size")
                    end,
                    order = 11,
                },
                gap = {
                    name = L["Resource_Gap"],
                    desc = L["Resource_GapDesc"]:format(points.name),
                    type = "input",
                    hidden = RealUI.charInfo.class.token == "PALADIN",
                    get = function(info) return tostring(ClassResource.db.class.points.size.gap) end,
                    set = function(info, value)
                        value = ValidateOffset(value)
                        ClassResource.db.class.points.size.gap = value
                        ClassResource:SettingsUpdate("points", "gap")
                    end,
                    order = 12,
                },
                position = {
                    name = L["General_Position"],
                    type = "group",
                    inline = true,
                    order = 20,
                    args = {
                        anchorTo = {
                            name = "Anchor To",
                            desc = "Anchor the class resource to the screen, or pin it to a unit frame so it follows that frame."
                                .. "\n\nWhen pinned, the offsets below are measured from the unit frame instead of the screen.",
                            type = "select",
                            values = ANCHOR_TO_VALUES,
                            sorting = ANCHOR_TO_ORDER,
                            get = function(info)
                                return ClassResource.db.class.points.position.anchorTo or "screen"
                            end,
                            set = function(info, value)
                                FramePoint:SetAnchorTo(ClassResource, {"class", "points", "position"}, value)
                            end,
                            order = 0,
                        },
                        point = {
                            name = L["General_AnchorPoint"],
                            type = "select",
                            values = RealUI.globals.anchorPoints,
                            get = function(info)
                                for k,v in next, RealUI.globals.anchorPoints do
                                    if v == ClassResource.db.class.points.position.point then return k end
                                end
                            end,
                            set = function(info, value)
                                ClassResource.db.class.points.position.point = RealUI.globals.anchorPoints[value]
                                FramePoint:RestorePosition(ClassResource)
                            end,
                            order = 1,
                        },
                        x = {
                            name = L["General_XOffset"],
                            desc = L["General_XOffsetDesc"],
                            type = "input",
                            dialogControl = "NumberEditBox",
                            get = function(info)
                                return _G.tostring(ClassResource.db.class.points.position.x)
                            end,
                            set = function(info, value)
                                ClassResource.db.class.points.position.x = round(_G.tonumber(value), 1)
                                FramePoint:RestorePosition(ClassResource)
                            end,
                            order = 2,
                        },
                        y = {
                            name = L["General_YOffset"],
                            desc = L["General_YOffsetDesc"],
                            type = "input",
                            dialogControl = "NumberEditBox",
                            get = function(info) return _G.tostring(ClassResource.db.class.points.position.y) end,
                            set = function(info, value)
                                ClassResource.db.class.points.position.y = round(_G.tonumber(value), 1)
                                FramePoint:RestorePosition(ClassResource)
                            end,
                            order = 3,
                        },
                    }
                }
            }
        }
        CombatFader:AddFadeConfig(MODNAME, pointOptions, 50, true)

        if bars then
            barOptions = {
                name = bars.name,
                type = "group",
                disabled = function(info)
                    return not RealUI:GetModuleEnabled(MODNAME)
                end,
                order = 20,
                args = {
                    width = {
                        name = L["HuD_Width"],
                        type = "input",
                        get = function(info) return tostring(ClassResource.db.class.bar.size.width) end,
                        set = function(info, value)
                            ClassResource.db.class.bar.size.width = value
                            ClassResource:SettingsUpdate("bar", "size")
                        end,
                        order = 1,
                    },
                    height = {
                        name = L["HuD_Height"],
                        type = "input",
                        get = function(info) return tostring(ClassResource.db.class.bar.size.height) end,
                        set = function(info, value)
                            ClassResource.db.class.bar.size.height = value
                            ClassResource:SettingsUpdate("bar", "size")
                        end,
                        order = 2,
                    },
                    position = {
                        name = L["General_Position"],
                        type = "group",
                        inline = true,
                        order = 3,
                        args = {
                            point = {
                                name = L["General_AnchorPoint"],
                                type = "select",
                                values = RealUI.globals.anchorPoints,
                                get = function(info)
                                    for k,v in next, RealUI.globals.anchorPoints do
                                        if v == ClassResource.db.class.bar.position.point then return k end
                                    end
                                end,
                                set = function(info, value)
                                    ClassResource.db.class.bar.position.point = RealUI.globals.anchorPoints[value]
                                    FramePoint:RestorePosition(ClassResource)
                                end,
                                order = 1,
                            },
                            x = {
                                name = L["General_XOffset"],
                                desc = L["General_XOffsetDesc"],
                                type = "input",
                                dialogControl = "NumberEditBox",
                                get = function(info)
                                    return _G.tostring(ClassResource.db.class.bar.position.x)
                                end,
                                set = function(info, value)
                                    ClassResource.db.class.bar.position.x = round(_G.tonumber(value), 1)
                                    FramePoint:RestorePosition(ClassResource)
                                end,
                                order = 2,
                            },
                            y = {
                                name = L["General_YOffset"],
                                desc = L["General_YOffsetDesc"],
                                type = "input",
                                dialogControl = "NumberEditBox",
                                get = function(info) return _G.tostring(ClassResource.db.class.bar.position.y) end,
                                set = function(info, value)
                                    ClassResource.db.class.bar.position.y = round(_G.tonumber(value), 1)
                                    FramePoint:RestorePosition(ClassResource)
                                end,
                                order = 3,
                            },
                        }
                    }
                }
            }
        end

        optArgs.classresource = {
            name = L["Resource"],
            icon = "cogs",
            type = "group",
            childGroups = "tab",
            order = 4,
            args = {
                enable = {
                    name = L["General_Enabled"],
                    desc = L["General_EnabledDesc"]:format(L["Resource"]),
                    type = "toggle",
                    get = function(info)
                        return RealUI:GetModuleEnabled(MODNAME)
                    end,
                    set = function(info, value)
                        RealUI:SetModuleEnabled(MODNAME, value)
                        CloseHuDWindow()
                        RealUI:ReloadUIDialog()
                    end,
                    order = 1,
                },
                lock = {
                    name = L["General_Lock"],
                    desc = L["General_LockDesc"],
                    type = "toggle",
                    disabled = function(info)
                        return not RealUI:GetModuleEnabled(MODNAME)
                    end,
                    get = function(info) return FramePoint:IsModLocked(ClassResource) end,
                    set = function(info, value)
                        if value then
                            FramePoint:LockMod(ClassResource)
                        else
                            FramePoint:UnlockMod(ClassResource)
                        end
                    end,
                    order = 2,
                },
                bars = barOptions,
                points = pointOptions,
            }
        }
    end
end

debug("HuD Options")
