-- Portal Authority
-- Settings panel registration and controls.

PortalAuthority = PortalAuthority or {}

if PortalAuthority.IsSettingsBaselineGateEnabled and PortalAuthority:IsSettingsBaselineGateEnabled() then
    return
end

if not Settings or not Settings.RegisterCanvasLayoutCategory then
    return
end

local settingsEagerBuildGateEnabled = PortalAuthority.IsSettingsEagerBuildGateEnabled and PortalAuthority:IsSettingsEagerBuildGateEnabled() or false
local settingsWindowHostGateEnabled = PortalAuthority.IsSettingsWindowHostEnabled and PortalAuthority:IsSettingsWindowHostEnabled() or false

local DEBUG_SETTINGS = false
local DEBUG_OPTIONS = false
local SHARED_RESET_ANCHOR_SHIFT_X = 10 -- single knob: moves Timers + Combat Alerts Reset Anchor buttons together (horizontal)
local SHARED_RESET_ANCHOR_SHIFT_Y = -7 -- single knob: moves Timers + Combat Alerts Reset Anchor buttons together (vertical; positive goes up)
local createCanonicalDockFontSizeStepperControl = nil
local function debugSettingsLog(...)
    if not DEBUG_SETTINGS then
        return
    end
    local prefix = "[PortalAuthority:Options]"
    if PortalAuthority and PortalAuthority.DebugPrint then
        PortalAuthority:DebugPrint(prefix, ...)
    else
        print(prefix, ...)
    end
end

local function debugOptionsLog(...)
    if not DEBUG_OPTIONS then
        return
    end
    local prefix = "[PortalAuthority:Options:Modules]"
    if PortalAuthority and PortalAuthority.DebugPrint then
        PortalAuthority:DebugPrint(prefix, ...)
    else
        print(prefix, ...)
    end
end

local function trim(text)
    if type(text) ~= "string" then
        return ""
    end
    local cleaned = text:gsub("^%s+", ""):gsub("%s+$", "")
    return cleaned
end

local function rgba255(r, g, b, a)
    return (tonumber(r) or 255) / 255,
        (tonumber(g) or 255) / 255,
        (tonumber(b) or 255) / 255,
        a == nil and 1 or math.max(0, math.min(1, tonumber(a) or 1))
end

local FLAT_SETTINGS_BACKDROP = {
    bgFile = "Interface\\Buttons\\WHITE8x8",
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    edgeSize = 1,
    insets = { left = 0, right = 0, top = 0, bottom = 0 },
}

local SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE = 6
local SETTINGS_WINDOW_SCROLLBAR_WIDTH = 8
local SETTINGS_WINDOW_SCROLLBAR_GAP = 10
local SETTINGS_WINDOW_SCROLLBAR_MIN_THUMB_HEIGHT = 24
local SETTINGS_WINDOW_HOST_COLORS = {
    idleBg = { rgba255(26, 28, 36, 0.95) },
    idleBorder = { rgba255(61, 69, 82, 1.0) },
    idleText = { rgba255(200, 200, 210, 1.0) },
    hoverBg = { rgba255(34, 37, 46, 0.97) },
    hoverBorder = { rgba255(88, 98, 112, 1.0) },
    hoverText = { rgba255(222, 224, 230, 1.0) },
    onBg = { rgba255(18, 48, 52, 0.96) },
    onBorder = { rgba255(40, 130, 120, 0.80) },
    onText = { rgba255(170, 240, 230, 1.0) },
    offBg = { rgba255(48, 14, 30, 0.93) },
    offBorder = { rgba255(60, 16, 35, 1.0) },
    offText = { rgba255(220, 185, 200, 1.0) },
    disabledBg = { rgba255(44, 46, 54, 0.92) },
    disabledBorder = { rgba255(86, 92, 102, 0.88) },
    disabledText = { rgba255(150, 154, 164, 0.96) },
    statusGoodBorder = { rgba255(40, 130, 120, 0.90) },
    statusGoodText = { rgba255(170, 240, 230, 1.0) },
}
local SETTINGS_WINDOW_SCROLLBAR_TRACK = { rgba255(10, 10, 18, 1.0) }
local SETTINGS_WINDOW_SCROLLBAR_THUMB = { rgba255(42, 42, 58, 0.5) }
local SETTINGS_WINDOW_SCROLLBAR_THUMB_HOVER = { rgba255(58, 58, 72, 0.6) }

local function unpackColor(color)
    if type(color) ~= "table" then
        return 1, 1, 1, 1
    end
    return color[1] or 1, color[2] or 1, color[3] or 1, color[4] or 1
end

local function frameIsAlive(frame)
    return frame ~= nil and type(frame.GetObjectType) == "function"
end

local function isDescendedFromFrame(frame, ancestor)
    if not frame or not ancestor then
        return false
    end
    local current = frame
    while current do
        if current == ancestor then
            return true
        end
        current = current.GetParent and current:GetParent() or nil
    end
    return false
end

local function markSettingsWindowVisualOptIn(frame)
    if frameIsAlive(frame) then
        frame._paSettingsWindowVisualStyleOptIn = true
    end
    return frame
end

local function isSettingsWindowVisualOptedIn(frame)
    local current = frame
    while current do
        if current._paSettingsWindowVisualStyleOptIn == true then
            return true
        end
        current = current.GetParent and current:GetParent() or nil
    end
    return false
end

local function isUsingCustomSettingsWindowVisualStyle(frame)
    if not frameIsAlive(frame) or not PortalAuthority or not PortalAuthority.IsSettingsWindowHostEnabled then
        return false
    end
    if not PortalAuthority:IsSettingsWindowHostEnabled() then
        return false
    end
    if not isSettingsWindowVisualOptedIn(frame) then
        return false
    end

    local runtime = PortalAuthority._settingsWindowRuntime
    local window = runtime and runtime.window or nil
    if frameIsAlive(window) and isDescendedFromFrame(frame, window) then
        return true
    end

    local current = frame
    while current do
        if current._paHostedBySettingsWindow == true then
            return true
        end
        current = current.GetParent and current:GetParent() or nil
    end

    return false
end

local function registerSettingsWindowVisualRefresh(frame, callback)
    if frameIsAlive(frame) and type(callback) == "function" then
        frame._paSettingsWindowVisualRefresh = callback
    end
end

local function setTextureSolidColor(texture, color)
    if not texture then
        return
    end
    local r, g, b, a = unpackColor(color)
    if texture.SetColorTexture then
        texture:SetColorTexture(r, g, b, a)
    elseif texture.SetVertexColor then
        texture:SetVertexColor(r, g, b, a)
    end
end

local function hideDefaultScrollBarPart(part, scrollFrame)
    if not part then
        return
    end
    if part.SetAlpha then
        part:SetAlpha(0)
    end
    if part.Hide then
        part:Hide()
    end
    if part.EnableMouse then
        part:EnableMouse(false)
    end
    if part.SetSize then
        part:SetSize(1, 1)
    elseif part.SetWidth and part.SetHeight then
        part:SetWidth(1)
        part:SetHeight(1)
    end
    if part.HookScript and not part._paSettingsWindowHideHook then
        part._paSettingsWindowHideHook = true
        part:HookScript("OnShow", function(selfPart)
            if isUsingCustomSettingsWindowVisualStyle(scrollFrame) then
                if selfPart.SetAlpha then
                    selfPart:SetAlpha(0)
                end
                if selfPart.Hide then
                    selfPart:Hide()
                end
            end
        end)
    end
end

local function getTemplateScrollBar(scrollFrame)
    if not frameIsAlive(scrollFrame) then
        return nil
    end
    if frameIsAlive(scrollFrame.ScrollBar) then
        return scrollFrame.ScrollBar
    end
    local frameName = scrollFrame.GetName and scrollFrame:GetName() or nil
    if frameName and _G then
        local named = _G[frameName .. "ScrollBar"]
        if frameIsAlive(named) then
            return named
        end
    end
    return nil
end

local function hideDefaultScrollBarChrome(scrollFrame)
    local scrollBar = getTemplateScrollBar(scrollFrame)
    if not frameIsAlive(scrollBar) then
        return nil
    end

    if scrollBar.SetAlpha then
        scrollBar:SetAlpha(0)
    end
    if scrollBar.Hide then
        scrollBar:Hide()
    end
    if scrollBar.EnableMouse then
        scrollBar:EnableMouse(false)
    end
    scrollBar:ClearAllPoints()
    scrollBar:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", SETTINGS_WINDOW_SCROLLBAR_GAP, 0)
    scrollBar:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", SETTINGS_WINDOW_SCROLLBAR_GAP, 0)
    scrollBar:SetWidth(SETTINGS_WINDOW_SCROLLBAR_WIDTH)

    if scrollBar.GetRegions then
        for i = 1, select("#", scrollBar:GetRegions()) do
            local region = select(i, scrollBar:GetRegions())
            if region then
                if region.SetTexture then
                    region:SetTexture(nil)
                end
                if region.SetAlpha then
                    region:SetAlpha(0)
                end
                if region.Hide then
                    region:Hide()
                end
            end
        end
    end

    if scrollBar.GetChildren then
        for i = 1, select("#", scrollBar:GetChildren()) do
            hideDefaultScrollBarPart(select(i, scrollBar:GetChildren()), scrollFrame)
        end
    end

    hideDefaultScrollBarPart(scrollBar.ScrollUpButton, scrollFrame)
    hideDefaultScrollBarPart(scrollBar.ScrollDownButton, scrollFrame)
    hideDefaultScrollBarPart(scrollBar.UpButton, scrollFrame)
    hideDefaultScrollBarPart(scrollBar.DownButton, scrollFrame)

    return scrollBar
end

local function refreshCustomSettingsScrollBarThumb(customBar)
    if not frameIsAlive(customBar) then
        return
    end
    local thumb = customBar._paThumb
    if not thumb then
        return
    end

    local color = customBar._paHovered and SETTINGS_WINDOW_SCROLLBAR_THUMB_HOVER or SETTINGS_WINDOW_SCROLLBAR_THUMB
    local r, g, b, a = unpackColor(color)
    local visibility = tonumber(customBar._paVisibilityMultiplier)
    if visibility == nil then
        visibility = 0
    end
    if visibility < 0 then
        visibility = 0
    elseif visibility > 1 then
        visibility = 1
    end
    a = a * visibility
    if thumb.SetColorTexture then
        thumb:SetColorTexture(r, g, b, a)
    elseif thumb.SetVertexColor then
        thumb:SetVertexColor(r, g, b, a)
    end
end

PortalAuthority._settingsScrollRuntime = PortalAuthority._settingsScrollRuntime or {}
local settingsScrollRuntime = PortalAuthority._settingsScrollRuntime
local ACTIVE_PORTAL_PICKER

settingsScrollRuntime.numbersDiffer = function(a, b)
    a = tonumber(a)
    b = tonumber(b)
    if a == nil or b == nil then
        return a ~= b
    end
    return math.abs(a - b) > 0.5
end

settingsScrollRuntime.fadeDelaySeconds = 1.5
settingsScrollRuntime.fadeDurationSeconds = 0.4

settingsScrollRuntime.getAdapter = function(scrollFrame, scrollChild, viewportHeight, contentHeight)
    local adapter = scrollFrame and scrollFrame._paCustomScrollAdapter or nil
    local resolved = {}

    resolved.panelId = type(adapter) == "table" and adapter.panelId or "settings"

    if type(adapter) == "table" and type(adapter.resolveCanonicalMax) == "function" then
        resolved.resolveCanonicalMax = adapter.resolveCanonicalMax
    else
        resolved.resolveCanonicalMax = function()
            return math.max(0, (tonumber(contentHeight) or 0) - (tonumber(viewportHeight) or 0)), "derived"
        end
    end

    if type(adapter) == "table" and type(adapter.getCurrentValue) == "function" then
        resolved.getCurrentValue = adapter.getCurrentValue
    else
        resolved.getCurrentValue = function()
            if not scrollFrame or type(scrollFrame.GetVerticalScroll) ~= "function" then
                return 0
            end
            return math.max(0, tonumber(scrollFrame:GetVerticalScroll()) or 0)
        end
    end

    if type(adapter) == "table" and type(adapter.applyValue) == "function" then
        resolved.applyValue = adapter.applyValue
    else
        resolved.applyValue = function(value)
            if not scrollFrame or type(scrollFrame.SetVerticalScroll) ~= "function" then
                return false
            end
            scrollFrame._paSkipNextCustomScrollBarHookSync = true
            scrollFrame:SetVerticalScroll(math.max(0, tonumber(value) or 0))
            return true
        end
    end

    return resolved
end

settingsScrollRuntime.canReveal = function(customBar)
    if not frameIsAlive(customBar) then
        return false
    end
    if not customBar.IsShown or not customBar:IsShown() then
        return false
    end
    local maxScroll = math.max(
        tonumber(customBar._paBoundMax) or 0,
        tonumber(customBar._paRenderedMaxScroll) or 0
    )
    return maxScroll > 0
end

settingsScrollRuntime.stopFadeTween = function(customBar)
    if not frameIsAlive(customBar) then
        return
    end
    local fadeDriver = customBar._paFadeDriver
    if frameIsAlive(fadeDriver) and fadeDriver.GetScript and fadeDriver:GetScript("OnUpdate") ~= nil then
        fadeDriver:SetScript("OnUpdate", nil)
    end
    customBar._paFadeTweenActive = nil
end

settingsScrollRuntime.cancelFade = function(customBar)
    if not frameIsAlive(customBar) then
        return
    end
    customBar._paFadeToken = (tonumber(customBar._paFadeToken) or 0) + 1
    settingsScrollRuntime.stopFadeTween(customBar)
end

settingsScrollRuntime.setThumbVisibility = function(customBar, alpha)
    if not frameIsAlive(customBar) then
        return
    end
    alpha = tonumber(alpha) or 0
    if alpha < 0 then
        alpha = 0
    elseif alpha > 1 then
        alpha = 1
    end
    customBar._paVisibilityMultiplier = alpha

    local thumbButton = customBar._paThumbButton
    if frameIsAlive(thumbButton) and thumbButton.EnableMouse then
        thumbButton:EnableMouse(customBar._paDragging == true or alpha > 0.01)
    end

    refreshCustomSettingsScrollBarThumb(customBar)
end

settingsScrollRuntime.hideImmediately = function(customBar)
    if not frameIsAlive(customBar) then
        return
    end
    settingsScrollRuntime.cancelFade(customBar)
    settingsScrollRuntime.setThumbVisibility(customBar, 0)
end

settingsScrollRuntime.beginFade = function(customBar, token)
    if not frameIsAlive(customBar) then
        return
    end
    if customBar._paDragging == true or customBar._paThumbHovered == true or customBar._paTrackHovered == true then
        return
    end
    if not settingsScrollRuntime.canReveal(customBar) then
        settingsScrollRuntime.setThumbVisibility(customBar, 0)
        return
    end

    local fadeDriver = customBar._paFadeDriver
    if not frameIsAlive(fadeDriver) then
        settingsScrollRuntime.setThumbVisibility(customBar, 0)
        return
    end

    local startAlpha = tonumber(customBar._paVisibilityMultiplier)
    if startAlpha == nil then
        startAlpha = 0
    end
    if startAlpha <= 0 then
        settingsScrollRuntime.setThumbVisibility(customBar, 0)
        return
    end

    settingsScrollRuntime.stopFadeTween(customBar)
    customBar._paFadeTweenActive = true
    local elapsedTime = 0
    fadeDriver:SetScript("OnUpdate", function(_, elapsed)
        if not frameIsAlive(customBar) then
            return
        end
        if customBar._paFadeToken ~= token then
            settingsScrollRuntime.stopFadeTween(customBar)
            return
        end
        if customBar._paDragging == true or customBar._paThumbHovered == true or customBar._paTrackHovered == true then
            settingsScrollRuntime.stopFadeTween(customBar)
            settingsScrollRuntime.setThumbVisibility(customBar, 1)
            return
        end
        if not settingsScrollRuntime.canReveal(customBar) then
            settingsScrollRuntime.stopFadeTween(customBar)
            settingsScrollRuntime.setThumbVisibility(customBar, 0)
            return
        end

        elapsedTime = elapsedTime + (tonumber(elapsed) or 0)
        local duration = settingsScrollRuntime.fadeDurationSeconds
        local progress = duration > 0 and math.max(0, math.min(1, elapsedTime / duration)) or 1
        settingsScrollRuntime.setThumbVisibility(customBar, startAlpha * (1 - progress))
        if progress >= 1 then
            settingsScrollRuntime.stopFadeTween(customBar)
            settingsScrollRuntime.setThumbVisibility(customBar, 0)
        end
    end)
end

settingsScrollRuntime.armFade = function(customBar)
    if not frameIsAlive(customBar) then
        return
    end
    if customBar._paDragging == true or customBar._paThumbHovered == true or customBar._paTrackHovered == true then
        return
    end
    if not settingsScrollRuntime.canReveal(customBar) then
        settingsScrollRuntime.hideImmediately(customBar)
        return
    end

    settingsScrollRuntime.cancelFade(customBar)
    local token = tonumber(customBar._paFadeToken) or 0
    if not (C_Timer and C_Timer.After) then
        settingsScrollRuntime.beginFade(customBar, token)
        return
    end

    C_Timer.After(settingsScrollRuntime.fadeDelaySeconds, function()
        if not frameIsAlive(customBar) then
            return
        end
        if customBar._paFadeToken ~= token then
            return
        end
        settingsScrollRuntime.beginFade(customBar, token)
    end)
end

settingsScrollRuntime.showThumb = function(customBar)
    if not frameIsAlive(customBar) then
        return
    end
    settingsScrollRuntime.cancelFade(customBar)
    if not settingsScrollRuntime.canReveal(customBar) then
        settingsScrollRuntime.setThumbVisibility(customBar, 0)
        return
    end
    settingsScrollRuntime.setThumbVisibility(customBar, 1)
end

settingsScrollRuntime.noteInteraction = function(customBar)
    if not frameIsAlive(customBar) then
        return
    end
    settingsScrollRuntime.showThumb(customBar)
    if customBar._paDragging ~= true
        and customBar._paThumbHovered ~= true
        and customBar._paTrackHovered ~= true then
        settingsScrollRuntime.armFade(customBar)
    end
end

settingsScrollRuntime.noteFrameInteraction = function(scrollFrame)
    if not frameIsAlive(scrollFrame) then
        return
    end
    local customBar = scrollFrame._paCustomScrollBar
    if not frameIsAlive(customBar) then
        return
    end
    settingsScrollRuntime.noteInteraction(customBar)
end

local function isPointerInsideActivePickerSafeZone()
    if type(MouseIsOver) ~= "function" then
        return false
    end

    local picker = ACTIVE_PORTAL_PICKER
    if not frameIsAlive(picker) or not picker.IsShown or not picker:IsShown() then
        return false
    end

    local function isPointerInside(frame)
        if not frameIsAlive(frame) or not frame.IsShown or not frame:IsShown() then
            return false
        end
        return MouseIsOver(frame) and true or false
    end

    if isPointerInside(picker) then
        return true
    end

    for _, frame in ipairs({
        picker.scroll,
        picker.search,
        picker.clearButton,
        picker.closeButton,
    }) do
        if isPointerInside(frame) then
            return true
        end
    end

    return false
end

settingsScrollRuntime.closeFloatingControlsForParentScroll = function(scrollFrame)
    if not frameIsAlive(scrollFrame) or scrollFrame._paCloseFloatingControlsOnUserScroll ~= true then
        return false
    end

    if isPointerInsideActivePickerSafeZone() then
        return true
    end

    local panel = scrollFrame._paCloseFloatingControlsPanel
        or scrollFrame._paSearchPanel
        or scrollFrame._paOwnerPanel
        or nil

    if ACTIVE_PORTAL_PICKER
        and ACTIVE_PORTAL_PICKER.IsShown
        and ACTIVE_PORTAL_PICKER:IsShown()
        and ACTIVE_PORTAL_PICKER.Close
    then
        ACTIVE_PORTAL_PICKER:Close()
    end

    if type(CloseDropDownMenus) == "function" then
        CloseDropDownMenus()
    end

    if panel and type(panel._paCloseFloatingControlsOnScroll) == "function" then
        panel._paCloseFloatingControlsOnScroll(panel)
    end

    return false
end

settingsScrollRuntime.suppressHoverRevealForCurrentFrame = function(customBar)
    if not frameIsAlive(customBar) then
        return
    end
    customBar._paHoverRevealSuppressed = true
    local token = (tonumber(customBar._paHoverRevealToken) or 0) + 1
    customBar._paHoverRevealToken = token
    if C_Timer and C_Timer.After then
        C_Timer.After(0, function()
            if not frameIsAlive(customBar) then
                return
            end
            if customBar._paHoverRevealToken ~= token then
                return
            end
            customBar._paHoverRevealSuppressed = nil
        end)
    else
        customBar._paHoverRevealSuppressed = nil
    end
end

settingsScrollRuntime.clearDrag = function(customBar)
    if not frameIsAlive(customBar) then
        return
    end

    customBar._paDragSession = nil
    customBar._paDragging = nil
    if customBar.GetScript and customBar:GetScript("OnUpdate") ~= nil then
        customBar:SetScript("OnUpdate", nil)
    end
    customBar._paHovered = customBar._paThumbHovered == true or customBar._paTrackHovered == true
    refreshCustomSettingsScrollBarThumb(customBar)
    if customBar._paHovered == true then
        settingsScrollRuntime.showThumb(customBar)
    else
        settingsScrollRuntime.armFade(customBar)
    end
end

settingsScrollRuntime.setHover = function(customBar, key, isHovered)
    if not frameIsAlive(customBar) then
        return
    end

    if key == "thumb" then
        customBar._paThumbHovered = isHovered and true or nil
    else
        customBar._paTrackHovered = isHovered and true or nil
    end
    customBar._paHovered = customBar._paDragging == true
        or customBar._paThumbHovered == true
        or customBar._paTrackHovered == true
    refreshCustomSettingsScrollBarThumb(customBar)

    if customBar._paHovered == true then
        if settingsScrollRuntime.canReveal(customBar) then
            settingsScrollRuntime.cancelFade(customBar)
            if customBar._paHoverRevealSuppressed ~= true
                or (tonumber(customBar._paVisibilityMultiplier) or 0) > 0 then
                settingsScrollRuntime.setThumbVisibility(customBar, 1)
            end
        end
    elseif customBar._paDragging ~= true then
        settingsScrollRuntime.armFade(customBar)
    end
end

settingsScrollRuntime.layoutThumb = function(customBar, viewportHeight, contentHeight, maxScroll, currentValue)
    if not frameIsAlive(customBar) then
        return
    end

    local thumb = customBar._paThumb
    local thumbButton = customBar._paThumbButton
    if not thumb or not frameIsAlive(thumbButton) then
        return
    end

    local barHeight = math.max(
        tonumber(customBar:GetHeight()) or 0,
        tonumber(viewportHeight) or 0,
        SETTINGS_WINDOW_SCROLLBAR_MIN_THUMB_HEIGHT
    )
    local ratio = (tonumber(contentHeight) or 0) > 0
            and math.max(0, math.min(1, (tonumber(viewportHeight) or 0) / math.max(tonumber(contentHeight) or 1, 1)))
        or 1
    local thumbHeight = math.max(SETTINGS_WINDOW_SCROLLBAR_MIN_THUMB_HEIGHT, math.floor(barHeight * ratio))
    local maxThumbHeight = math.max(1, math.floor(barHeight * 0.60))
    thumbHeight = math.min(barHeight, thumbHeight, maxThumbHeight)

    local clampedMax = math.max(0, tonumber(maxScroll) or 0)
    local clampedValue = math.max(0, math.min(clampedMax, tonumber(currentValue) or 0))
    local usableTravel = math.max(0, barHeight - thumbHeight)
    local pct = clampedMax > 0 and math.max(0, math.min(1, clampedValue / clampedMax)) or 0
    local topOffset = usableTravel * pct
    local roundedOffset = math.floor(topOffset + 0.5)

    if thumb.SetHeight then
        thumb:SetHeight(thumbHeight)
    end
    if thumb.SetWidth then
        thumb:SetWidth(SETTINGS_WINDOW_SCROLLBAR_WIDTH)
    end
    thumb:ClearAllPoints()
    thumb:SetPoint("TOPLEFT", customBar, "TOPLEFT", 0, -roundedOffset)
    thumb:SetPoint("TOPRIGHT", customBar, "TOPRIGHT", 0, -roundedOffset)

    thumbButton:ClearAllPoints()
    thumbButton:SetPoint("TOPLEFT", customBar, "TOPLEFT", 0, -roundedOffset)
    thumbButton:SetSize(SETTINGS_WINDOW_SCROLLBAR_WIDTH, thumbHeight)

    local trackTop = tonumber(customBar.GetTop and customBar:GetTop()) or 0
    local trackBottom = tonumber(customBar.GetBottom and customBar:GetBottom()) or 0
    if settingsScrollRuntime.numbersDiffer(customBar._paGeometryTrackTop, trackTop)
        or settingsScrollRuntime.numbersDiffer(customBar._paGeometryTrackBottom, trackBottom)
        or settingsScrollRuntime.numbersDiffer(customBar._paThumbHeight, thumbHeight)
        or settingsScrollRuntime.numbersDiffer(customBar._paUsableThumbTravel, usableTravel)
        or settingsScrollRuntime.numbersDiffer(customBar._paRenderedMaxScroll, clampedMax) then
        customBar._paGeometryRevision = (tonumber(customBar._paGeometryRevision) or 0) + 1
    end

    customBar._paGeometryTrackTop = trackTop
    customBar._paGeometryTrackBottom = trackBottom
    customBar._paThumbHeight = thumbHeight
    customBar._paUsableThumbTravel = usableTravel
    customBar._paRenderedMaxScroll = clampedMax
    customBar._paRenderedScrollValue = clampedValue
end

settingsScrollRuntime.applyValue = function(customBar, requestedValue, options)
    if not frameIsAlive(customBar) then
        return false
    end

    local scrollFrame = customBar._paOwnerScrollFrame
    if not frameIsAlive(scrollFrame) then
        return false
    end

    local scrollChild = customBar._paOwnerScrollChild
        or (scrollFrame.GetScrollChild and scrollFrame:GetScrollChild())
    local viewportHeight = tonumber(scrollFrame.GetHeight and scrollFrame:GetHeight()) or 0
    local contentHeight = scrollChild and (tonumber(scrollChild.GetHeight and scrollChild:GetHeight()) or 0) or 0
    local adapter = settingsScrollRuntime.getAdapter(scrollFrame, scrollChild, viewportHeight, contentHeight)
    local maxScroll = adapter.resolveCanonicalMax(options, scrollFrame, scrollChild, viewportHeight, contentHeight)
    if type(maxScroll) ~= "number" then
        return false
    end
    maxScroll = math.max(0, maxScroll)
    local currentValue = math.max(0, tonumber(adapter.getCurrentValue(options, scrollFrame, scrollChild, viewportHeight, contentHeight)) or 0)
    local clampedValue = math.max(0, math.min(maxScroll, tonumber(requestedValue) or currentValue))
    if adapter.applyValue(clampedValue, options, scrollFrame, scrollChild, viewportHeight, contentHeight) == false then
        return false
    end

    settingsScrollRuntime.sync(
        scrollFrame,
        scrollChild,
        tonumber(scrollFrame.GetHeight and scrollFrame:GetHeight()) or viewportHeight,
        scrollChild and (tonumber(scrollChild.GetHeight and scrollChild:GetHeight()) or contentHeight) or contentHeight
    )
    return true, clampedValue, maxScroll
end

settingsScrollRuntime.beginThumbDrag = function(customBar)
    if not frameIsAlive(customBar) then
        return
    end

    if settingsScrollRuntime.closeFloatingControlsForParentScroll(customBar._paOwnerScrollFrame) then
        return
    end
    settingsScrollRuntime.clearDrag(customBar)

    local maxScroll = math.max(0, tonumber(customBar._paRenderedMaxScroll) or 0)
    local usableTravel = math.max(0, tonumber(customBar._paUsableThumbTravel) or 0)
    local thumbHeight = math.max(0, tonumber(customBar._paThumbHeight) or 0)
    if maxScroll <= 0 or usableTravel <= 0 or thumbHeight <= 0 then
        return
    end

    local track = customBar._paTrackButton
    local scale = tonumber(track and track.GetEffectiveScale and track:GetEffectiveScale()) or 0
    local trackTop = tonumber(track and track.GetTop and track:GetTop()) or nil
    local trackBottom = tonumber(track and track.GetBottom and track:GetBottom()) or nil
    local cursorY = select(2, GetCursorPosition())
    if not trackTop or not trackBottom or trackTop <= trackBottom or scale <= 0 or not cursorY then
        return
    end

    cursorY = cursorY / scale
    local currentValue = math.max(0, math.min(maxScroll, tonumber(customBar._paRenderedScrollValue) or 0))
    local currentTopOffset = usableTravel * (maxScroll > 0 and (currentValue / maxScroll) or 0)
    local thumbTop = trackTop - currentTopOffset

    customBar._paDragSession = {
        mode = "thumb-drag",
        geometryRevision = tonumber(customBar._paGeometryRevision) or 0,
        trackTop = trackTop,
        usableTravel = usableTravel,
        maxScroll = maxScroll,
        thumbHeight = thumbHeight,
        scale = scale,
        grabOffset = thumbTop - cursorY,
    }
    customBar._paDragging = true
    customBar._paHovered = true
    settingsScrollRuntime.showThumb(customBar)

    customBar:SetScript("OnUpdate", function(selfBar)
        local session = selfBar._paDragSession
        if not session then
            settingsScrollRuntime.clearDrag(selfBar)
            return
        end
        if not IsMouseButtonDown or not IsMouseButtonDown("LeftButton") then
            settingsScrollRuntime.clearDrag(selfBar)
            return
        end
        if session.geometryRevision ~= (tonumber(selfBar._paGeometryRevision) or 0) then
            settingsScrollRuntime.clearDrag(selfBar)
            return
        end

        local dragCursorY = select(2, GetCursorPosition())
        if not dragCursorY or session.scale <= 0 then
            return
        end
        dragCursorY = dragCursorY / session.scale

        local desiredThumbTop = dragCursorY + session.grabOffset
        local topOffset = session.trackTop - desiredThumbTop
        if topOffset < 0 then
            topOffset = 0
        elseif topOffset > session.usableTravel then
            topOffset = session.usableTravel
        end

        local pct = session.usableTravel > 0 and (topOffset / session.usableTravel) or 0
        local targetValue = session.maxScroll * pct
        settingsScrollRuntime.applyValue(selfBar, targetValue, {
            source = "thumb-drag",
            allowFallback = false,
            allowPostRelayoutSync = false,
        })
    end)
end

settingsScrollRuntime.handleTrackClick = function(customBar)
    if not frameIsAlive(customBar) or customBar._paDragSession ~= nil then
        return
    end

    if settingsScrollRuntime.closeFloatingControlsForParentScroll(customBar._paOwnerScrollFrame) then
        return
    end
    local maxScroll = math.max(0, tonumber(customBar._paRenderedMaxScroll) or 0)
    local usableTravel = math.max(0, tonumber(customBar._paUsableThumbTravel) or 0)
    local thumbHeight = math.max(0, tonumber(customBar._paThumbHeight) or 0)
    if maxScroll <= 0 or usableTravel <= 0 or thumbHeight <= 0 then
        return
    end

    local track = customBar._paTrackButton
    local scale = tonumber(track and track.GetEffectiveScale and track:GetEffectiveScale()) or 0
    local trackTop = tonumber(track and track.GetTop and track:GetTop()) or nil
    local cursorY = select(2, GetCursorPosition())
    if not trackTop or scale <= 0 or not cursorY then
        return
    end

    cursorY = cursorY / scale
    local topOffset = trackTop - (cursorY + (thumbHeight * 0.5))
    if topOffset < 0 then
        topOffset = 0
    elseif topOffset > usableTravel then
        topOffset = usableTravel
    end

    local pct = usableTravel > 0 and (topOffset / usableTravel) or 0
    local targetValue = maxScroll * pct
    settingsScrollRuntime.noteInteraction(customBar)
    settingsScrollRuntime.applyValue(customBar, targetValue, {
        source = "track-click",
        allowFallback = false,
        allowPostRelayoutSync = false,
    })
end

settingsScrollRuntime.sync = function(scrollFrame, scrollChild, viewportHeight, contentHeight)
    if not frameIsAlive(scrollFrame) then
        return
    end

    scrollFrame._paOwnerScrollChild = scrollChild
    local isCustomHosted = isUsingCustomSettingsWindowVisualStyle(scrollFrame)
    local customBar = scrollFrame._paCustomScrollBar
    if not isCustomHosted then
        if frameIsAlive(customBar) then
            settingsScrollRuntime.clearDrag(customBar)
            customBar:Hide()
        end
        return
    end

    local defaultScrollBar = hideDefaultScrollBarChrome(scrollFrame)
    if defaultScrollBar then
        scrollFrame.ScrollBar = defaultScrollBar
    end

    if not frameIsAlive(customBar) then
        customBar = CreateFrame("Slider", nil, scrollFrame:GetParent() or scrollFrame)
        customBar:SetOrientation("VERTICAL")
        customBar:SetThumbTexture("Interface\\Buttons\\WHITE8x8")
        customBar:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", SETTINGS_WINDOW_SCROLLBAR_GAP, 0)
        customBar:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", SETTINGS_WINDOW_SCROLLBAR_GAP, 0)
        customBar:SetWidth(SETTINGS_WINDOW_SCROLLBAR_WIDTH)
        customBar:SetMinMaxValues(0, 0)
        customBar:SetValueStep(1)
        customBar:EnableMouse(false)
        customBar._paOwnerScrollFrame = scrollFrame
        customBar._paOwnerScrollChild = scrollChild
        customBar._paVisibilityMultiplier = 0

        local track = customBar:CreateTexture(nil, "BACKGROUND")
        track:SetAllPoints()
        setTextureSolidColor(track, SETTINGS_WINDOW_SCROLLBAR_TRACK)
        customBar._paTrack = track

        local nativeThumb = customBar:GetThumbTexture()
        if nativeThumb then
            nativeThumb:SetTexture(nil)
            nativeThumb:SetAlpha(0)
            nativeThumb:Hide()
        end

        local thumb = customBar:CreateTexture(nil, "ARTWORK")
        thumb:SetTexture("Interface\\Buttons\\WHITE8x8")
        thumb:SetPoint("TOPLEFT", customBar, "TOPLEFT", 0, 0)
        thumb:SetWidth(SETTINGS_WINDOW_SCROLLBAR_WIDTH)
        customBar._paThumb = thumb

        local trackButton = CreateFrame("Button", nil, customBar)
        trackButton:SetAllPoints()
        trackButton:RegisterForClicks("LeftButtonUp")
        trackButton:EnableMouse(true)
        trackButton:SetFrameLevel((customBar:GetFrameLevel() or 0) + 1)
        customBar._paTrackButton = trackButton

        local thumbButton = CreateFrame("Button", nil, customBar)
        thumbButton:RegisterForClicks("LeftButtonDown", "LeftButtonUp")
        thumbButton:EnableMouse(false)
        thumbButton:SetFrameLevel((customBar:GetFrameLevel() or 0) + 2)
        customBar._paThumbButton = thumbButton
        customBar._paFadeDriver = trackButton

        trackButton:SetScript("OnEnter", function()
            settingsScrollRuntime.setHover(customBar, "track", true)
        end)
        trackButton:SetScript("OnLeave", function()
            settingsScrollRuntime.setHover(customBar, "track", false)
        end)
        trackButton:SetScript("OnClick", function()
            settingsScrollRuntime.handleTrackClick(customBar)
        end)

        thumbButton:SetScript("OnEnter", function()
            settingsScrollRuntime.setHover(customBar, "thumb", true)
        end)
        thumbButton:SetScript("OnLeave", function()
            settingsScrollRuntime.setHover(customBar, "thumb", false)
        end)
        thumbButton:SetScript("OnMouseDown", function(_, mouseButton)
            if mouseButton ~= "LeftButton" then
                return
            end
            settingsScrollRuntime.noteInteraction(customBar)
            settingsScrollRuntime.beginThumbDrag(customBar)
        end)
        thumbButton:SetScript("OnMouseUp", function(_, mouseButton)
            if mouseButton ~= "LeftButton" then
                return
            end
            settingsScrollRuntime.clearDrag(customBar)
        end)

        customBar:SetScript("OnValueChanged", function() end)
        customBar:SetScript("OnHide", function(selfBar)
            selfBar._paThumbHovered = nil
            selfBar._paTrackHovered = nil
            selfBar._paHoverRevealSuppressed = nil
            selfBar._paHoverRevealToken = nil
            settingsScrollRuntime.hideImmediately(selfBar)
            settingsScrollRuntime.clearDrag(selfBar)
        end)

        scrollFrame._paCustomScrollBar = customBar

        if scrollFrame.HookScript and not scrollFrame._paCustomScrollBarHooked then
            scrollFrame._paCustomScrollBarHooked = true
            scrollFrame:HookScript("OnVerticalScroll", function(selfFrame)
                if selfFrame._paSkipNextCustomScrollBarHookSync then
                    selfFrame._paSkipNextCustomScrollBarHookSync = nil
                    return
                end
                local slider = selfFrame._paCustomScrollBar
                if not frameIsAlive(slider) then
                    return
                end
                local child = slider._paOwnerScrollChild or (selfFrame.GetScrollChild and selfFrame:GetScrollChild())
                settingsScrollRuntime.sync(
                    selfFrame,
                    child,
                    tonumber(selfFrame.GetHeight and selfFrame:GetHeight()) or 0,
                    child and (tonumber(child.GetHeight and child:GetHeight()) or 0) or 0
                )
            end)
        end
    end

    customBar._paOwnerScrollChild = scrollChild
    local adapter = settingsScrollRuntime.getAdapter(scrollFrame, scrollChild, viewportHeight, contentHeight)
    local range = adapter.resolveCanonicalMax({
        source = "sync",
        allowFallback = true,
        allowPostRelayoutSync = false,
    }, scrollFrame, scrollChild, viewportHeight, contentHeight)
    range = math.max(0, tonumber(range) or 0)
    if range <= 0 or not scrollFrame.IsShown or not scrollFrame:IsShown() then
        customBar._paThumbHovered = nil
        customBar._paTrackHovered = nil
        customBar._paHoverRevealSuppressed = nil
        customBar._paHoverRevealToken = nil
        settingsScrollRuntime.clearDrag(customBar)
        settingsScrollRuntime.hideImmediately(customBar)
        customBar:Hide()
        customBar._paSyncing = true
        customBar:SetMinMaxValues(0, 0)
        customBar:SetValue(0)
        customBar._paSyncing = false
        customBar._paBoundMax = 0
        settingsScrollRuntime.layoutThumb(customBar, viewportHeight, contentHeight, 0, 0)
        return
    end

    local wasShown = customBar.IsShown and customBar:IsShown()
    customBar:SetShown(true)
    if not wasShown then
        settingsScrollRuntime.suppressHoverRevealForCurrentFrame(customBar)
        settingsScrollRuntime.setThumbVisibility(customBar, 0)
    end
    if settingsScrollRuntime.numbersDiffer(customBar._paBoundMax, range) then
        customBar:SetMinMaxValues(0, range)
        customBar._paBoundMax = range
    end
    local currentScroll = adapter.getCurrentValue({
        source = "sync",
    }, scrollFrame, scrollChild, viewportHeight, contentHeight)
    currentScroll = math.max(0, math.min(range, tonumber(currentScroll) or 0))
    customBar._paSyncing = true
    if settingsScrollRuntime.numbersDiffer(customBar:GetValue(), currentScroll) then
        customBar:SetValue(currentScroll)
    end
    customBar._paSyncing = false
    settingsScrollRuntime.layoutThumb(customBar, viewportHeight, contentHeight, range, currentScroll)
    refreshCustomSettingsScrollBarThumb(customBar)
end

local function refreshManagedFontObject(object)
    if not object or object._paGlobalFontManaged ~= true or not object.SetFont then
        return
    end

    local size = tonumber(object._paGlobalFontSize) or select(2, object:GetFont()) or 12
    local flags = object._paGlobalFontFlags
    if flags == nil then
        flags = ""
    end

    if isUsingCustomSettingsWindowVisualStyle(object)
        and PortalAuthority
        and type(PortalAuthority.ApplyPremiumAuthoredFont) == "function" then
        PortalAuthority:ApplyPremiumAuthoredFont(object, size, flags)
        return
    end

    if PortalAuthority and type(PortalAuthority.ApplyGlobalFont) == "function" then
        PortalAuthority:ApplyGlobalFont(object, size, flags)
    end
end

local function refreshSettingsWindowVisualTree(object, visited)
    if not frameIsAlive(object) then
        return
    end
    visited = visited or {}
    if visited[object] then
        return
    end
    visited[object] = true

    refreshManagedFontObject(object)
    if type(object._paSettingsWindowVisualRefresh) == "function" then
        pcall(object._paSettingsWindowVisualRefresh, object)
    end

    if object.GetRegions then
        for i = 1, select("#", object:GetRegions()) do
            local region = select(i, object:GetRegions())
            if frameIsAlive(region) then
                refreshSettingsWindowVisualTree(region, visited)
            else
                refreshManagedFontObject(region)
                if region and type(region._paSettingsWindowVisualRefresh) == "function" then
                    pcall(region._paSettingsWindowVisualRefresh, region)
                end
            end
        end
    end
    if object.GetChildren then
        for i = 1, select("#", object:GetChildren()) do
            refreshSettingsWindowVisualTree(select(i, object:GetChildren()), visited)
        end
    end
end

if PortalAuthority then
    function PortalAuthority:RefreshSettingsWindowHostVisuals(root)
        refreshSettingsWindowVisualTree(root, {})
    end
end

local BUILTIN_FONT_CHOICES = {
    { label = "Global UI Font", value = "" },
    { label = "Friz Quadrata", value = "Fonts\\FRIZQT__.TTF" },
    { label = "Arial Narrow", value = "Fonts\\ARIALN.TTF" },
    { label = "Morpheus", value = "Fonts\\MORPHEUS.ttf" },
    { label = "Skurri", value = "Fonts\\SKURRI.ttf" },
    { label = "2002", value = "Fonts\\2002.ttf" },
    { label = "Nimrod", value = "Fonts\\NIM_____.ttf" },
    { label = "Damage", value = "Fonts\\DAMAGE.ttf" },
}

local SUMMON_SOUND_CHANNEL_CHOICES = {
    { label = "Master", value = "Master" },
    { label = "SFX", value = "SFX" },
    { label = "Music", value = "Music" },
    { label = "Ambience", value = "Ambience" },
    { label = "Dialog", value = "Dialog" },
}

local function getPortalMedia()
    local media = PortalAuthority and PortalAuthority.Media
    if type(media) == "table" then
        return media
    end
    return nil
end

local function normalizeSoundChoiceValue(value)
    local media = getPortalMedia()
    if media and media.NormalizeBundledSoundValue then
        return media.NormalizeBundledSoundValue(value)
    end
    return value
end

local function compareChoiceLabels(left, right)
    return tostring(left.label or ""):lower() < tostring(right.label or ""):lower()
end

local function normalizeChoicePathKey(path)
    if type(path) ~= "string" then
        return nil
    end
    local normalized = trim(path):gsub("/", "\\")
    if normalized == "" then
        return "__GLOBAL_FONT__"
    end
    return normalized:lower()
end

local function resolveFontChoicePath(option)
    if type(option) ~= "table" then
        return nil
    end

    local path = option.path
    if type(path) == "string" then
        path = trim(path):gsub("/", "\\")
        if path ~= "" then
            return path
        end
    end

    local value = option.value
    if value == "" then
        return ""
    end
    if type(value) == "string" then
        local normalized = trim(value):gsub("/", "\\")
        if normalized:find("\\", 1, true) then
            return normalized
        end
    end

    return nil
end

local function getSoundChoiceValueKey(value)
    local normalized = normalizeSoundChoiceValue(value)
    if type(normalized) == "number" then
        return "num:" .. tostring(normalized)
    end
    return "str:" .. tostring(normalized or "")
end

local function buildFallbackSoundChoices(currentValue, opts)
    opts = type(opts) == "table" and opts or {}

    local media = getPortalMedia()
    local choices = {}
    local seen = {}

    local function add(label, value)
        if value == nil then
            value = ""
        end

        local key = getSoundChoiceValueKey(value)
        if seen[key] then
            return
        end

        seen[key] = true
        choices[#choices + 1] = {
            label = tostring(label or value or ""),
            value = value,
        }
    end

    if opts.includeNone then
        add("None", "")
    end

    if media and type(media.BundledSounds) == "table" then
        for _, entry in ipairs(media.BundledSounds) do
            add(entry.label, entry.value)
        end
    else
        add("Overclock: Pause", "Overclock: Pause")
        add("Overclock: OOT Press Start", "Overclock: OOT Press Start")
        add("Overclock: MGS", "Overclock: MGS")
    end

    local lsm = LibStub and LibStub("LibSharedMedia-3.0", true)
    if lsm and lsm.List then
        local external = {}
        for _, name in ipairs(lsm:List("sound") or {}) do
            local label = tostring(name or "")
            if label ~= "" and not label:match("^Overclock:%s") and label ~= "None" then
                external[#external + 1] = {
                    label = label,
                    value = label,
                }
            end
        end
        table.sort(external, compareChoiceLabels)
        for _, entry in ipairs(external) do
            add(entry.label, entry.value)
        end
    end

    if opts.includeBuiltinIDs then
        local builtinChoices = (media and type(media.BuiltinSoundChoices) == "table" and media.BuiltinSoundChoices)
            or ((PortalAuthority.GetBuiltinSummonAlertSounds and PortalAuthority:GetBuiltinSummonAlertSounds()) or {})
        for _, entry in ipairs(builtinChoices) do
            add(entry.label, entry.value)
        end
    end

    local normalizedCurrent = normalizeSoundChoiceValue(currentValue)
    if normalizedCurrent ~= nil and normalizedCurrent ~= "" then
        local label = tostring(normalizedCurrent)
        if type(normalizedCurrent) == "string" and normalizedCurrent:find("[/\\]") then
            local basename = normalizedCurrent:match("([^\\]+)$") or normalizedCurrent
            basename = basename:gsub("%.%w+$", "")
            if basename ~= "" then
                label = "Custom: " .. basename
            end
        end
        add(label, normalizedCurrent)
    end

    return choices
end

local function getSummonSoundChoices(currentValue)
    local media = getPortalMedia()
    if media and media.GetChoices then
        return media.GetChoices("sound", {
            includeNone = true,
            includeBuiltinIDs = true,
            currentValue = currentValue,
        }) or {}
    end
    return buildFallbackSoundChoices(currentValue, {
        includeNone = true,
        includeBuiltinIDs = true,
    })
end

local DOCK_IMPORT_EXPORT_KEYS = {
    { key = "dockEnabled", type = "boolean" },
    { key = "dockOrientation", type = "string" },
    { key = "dockX", type = "number" },
    { key = "dockY", type = "number" },
    { key = "dockLocked", type = "boolean" },
    { key = "dockHideInMajorCity", type = "boolean" },
    { key = "dockHideInDungeon", type = "boolean" },
    { key = "dockHideInCombat", type = "boolean" },
    { key = "dockIconWidth", type = "number" },
    { key = "dockIconHeight", type = "number" },
    { key = "dockRowSpacing", type = "number" },
    { key = "dockTextIconSpacing", type = "number" },
    { key = "dockHideDungeonName", type = "boolean" },
    { key = "dockGizmoMode", type = "boolean" },
    { key = "dockUseShortNames", type = "boolean" },
    { key = "dockVerticalTextSide", type = "string" },
    { key = "dockHorizontalTextPosition", type = "string" },
    { key = "dockFontPath", type = "string" },
    { key = "dockFontSize", type = "number" },
    { key = "dockFontColor", type = "color" },
    { key = "dockTextOutline", type = "string" },
    { key = "dockTextShadow", type = "boolean" },
    { key = "dockShadowOffsetX", type = "number" },
    { key = "dockShadowOffsetY", type = "number" },
    { key = "dockLayoutMode", type = "string" },
    { key = "dockWrapAfter", type = "number" },
    { key = "dockIconSize", type = "number" },
    { key = "dockSpacingX", type = "number" },
    { key = "dockSpacingY", type = "number" },
    { key = "dockPadding", type = "number" },
    { key = "dockGrowthX", type = "string" },
    { key = "dockGrowthY", type = "string" },
    { key = "dockAnchorPoint", type = "string" },
    { key = "dockCenterAlignment", type = "boolean" },
    { key = "dockPreferAxis", type = "string" },
    { key = "dockCompactMode", type = "boolean" },
    { key = "dockTestMode", type = "boolean" },
    { key = "dockSortMode", type = "string" },
    { key = "dockAnimateReflow", type = "boolean" },
    { key = "dockAnimateDuration", type = "number" },
    { key = "dockBackdropEnabled", type = "boolean" },
    { key = "dockInactiveAlpha", type = "number" },
    { key = "dockHoverGlow", type = "boolean" },
    { key = "dockSimpleLayoutMode", type = "string" },
    { key = "dockIconsPerLine", type = "number" },
    { key = "dockIconSpacing", type = "number" },
    { key = "dockDensity", type = "number" },
    { key = "dockTextDirection", type = "string" },
    { key = "dockTextAlign", type = "string" },
    { key = "dockLabelAlignMode", type = "string" },
    { key = "dockTextOffset", type = "number" },
    { key = "dockLabelNudge", type = "number" },
    { key = "dockLabelMode", type = "string" },
    { key = "dockLabelSide", type = "string" },
    { key = "dockLabelSideOutsidePersist", type = "string" },
    { key = "dockHoverGlowAlpha", type = "number" },
    { key = "dockHoverGlowSize", type = "number" },
}

local DOCK_IMPORT_EXPORT_KEYSET = {}
for _, entry in ipairs(DOCK_IMPORT_EXPORT_KEYS) do
    DOCK_IMPORT_EXPORT_KEYSET[entry.key] = entry.type
end

local function getAvailableFontChoices()
    local media = getPortalMedia()
    local seen, choices = {}, {}
    local bundledKeys = {}
    local deferredExternalByPath = {}
    local deferredExternalOrder = {}

    local function add(label, path)
        if type(path) ~= "string" then return end
        local key = normalizeChoicePathKey(path)
        if not key then return end
        if seen[key] then return end
        seen[key] = true
        table.insert(choices, { label = label, value = path })
    end

    local function queueExternal(label, path)
        if type(path) ~= "string" then
            return
        end
        local key = normalizeChoicePathKey(path)
        if not key or key == "__GLOBAL_FONT__" or bundledKeys[key] then
            return
        end

        local entry = deferredExternalByPath[key]
        if not entry then
            entry = {
                label = tostring(label or path or ""),
                value = path,
            }
            deferredExternalByPath[key] = entry
            deferredExternalOrder[#deferredExternalOrder + 1] = key
            return
        end

        local candidateLabel = tostring(label or path or "")
        if candidateLabel ~= "" and candidateLabel:lower() < tostring(entry.label or ""):lower() then
            entry.label = candidateLabel
        end
    end

    add("Global UI Font", "")

    if media and type(media.BundledFonts) == "table" then
        for _, font in ipairs(media.BundledFonts) do
            local path = resolveFontChoicePath(font)
            local key = normalizeChoicePathKey(path)
            if key then
                bundledKeys[key] = true
                add(font.label, path)
            end
        end
    end

    if media and media.GetChoices then
        for _, option in ipairs(media.GetChoices("font", { includeGlobalUi = true }) or {}) do
            local path = resolveFontChoicePath(option)
            queueExternal(tostring(option.label or option.value or path or ""), path)
        end
    end

    for _, font in ipairs(BUILTIN_FONT_CHOICES) do add(font.label, font.value) end

    local lsm = LibStub and LibStub("LibSharedMedia-3.0", true)
    if lsm and lsm.HashTable then
        for label, path in pairs(lsm:HashTable("font") or {}) do
            local normalizedPath = resolveFontChoicePath({ label = label, value = path })
            queueExternal(tostring(label or normalizedPath or ""), normalizedPath)
        end
    end

    local deferredExternal = {}
    for _, key in ipairs(deferredExternalOrder) do
        local entry = deferredExternalByPath[key]
        if entry then
            deferredExternal[#deferredExternal + 1] = entry
        end
    end

    table.sort(deferredExternal, compareChoiceLabels)
    for _, option in ipairs(deferredExternal) do
        add(option.label, option.value)
    end

    return choices
end

local function buildSharedFontPickerChoices()
    local options = {}

    for _, option in ipairs(getAvailableFontChoices() or {}) do
        local value = tostring(option and option.value or "")
        local label = tostring((option and option.label) or value)
        options[#options + 1] = {
            value = value,
            label = label,
            buttonLabel = label,
            secondary = "",
            previewFontPath = (value ~= "") and value or nil,
            aliases = { label },
        }
    end

    if #options == 0 then
        options[1] = {
            value = "",
            label = "Global UI Font",
            buttonLabel = "Global UI Font",
            secondary = "",
            previewFontPath = nil,
            aliases = { "Global UI Font" },
        }
    end

    return options
end

local function restoreColorPickerPrevious(previous, fallback)
    fallback = type(fallback) == "table" and fallback or {}

    local alpha = tonumber(previous and previous.a)
    if alpha == nil then
        local opacity = tonumber(previous and previous.opacity)
        if opacity ~= nil then
            alpha = 1 - opacity
        end
    end
    if alpha == nil then
        alpha = tonumber(fallback.a) or 1
    end

    return {
        r = tonumber(previous and previous.r) or tonumber(fallback.r) or 1,
        g = tonumber(previous and previous.g) or tonumber(fallback.g) or 1,
        b = tonumber(previous and previous.b) or tonumber(fallback.b) or 1,
        a = math.max(0, math.min(1, alpha)),
    }
end

local function openColorPicker(onChanged)
    local c = PortalAuthorityDB.dockFontColor
    if ColorPickerFrame and ColorPickerFrame.SetupColorPickerAndShow then
        ColorPickerFrame:SetupColorPickerAndShow({
            r = c.r,
            g = c.g,
            b = c.b,
            opacity = 1 - c.a,
            hasOpacity = true,
            swatchFunc = function()
                local r, g, b = ColorPickerFrame:GetColorRGB()
                local a = 1 - (OpacitySliderFrame and OpacitySliderFrame:GetValue() or 0)
                PortalAuthorityDB.dockFontColor = { r = r, g = g, b = b, a = a }
                onChanged()
            end,
            opacityFunc = function()
                local r, g, b = ColorPickerFrame:GetColorRGB()
                local a = 1 - (OpacitySliderFrame and OpacitySliderFrame:GetValue() or 0)
                PortalAuthorityDB.dockFontColor = { r = r, g = g, b = b, a = a }
                onChanged()
            end,
            cancelFunc = function(prev)
                PortalAuthorityDB.dockFontColor = restoreColorPickerPrevious(prev, c)
                onChanged()
            end,
        })
    end
end

local function applyGlobalFontToObject(object, size, flags)
    if not object or not object.SetFont then
        return
    end

    object._paGlobalFontManaged = true
    object._paGlobalFontSize = size
    object._paGlobalFontFlags = flags
    refreshManagedFontObject(object)
end

local function createStyledFontString(parent, layer, template, size)
    local fontString = parent:CreateFontString(nil, layer, template)
    applyGlobalFontToObject(fontString, size)
    if parent then
        local current = parent
        local panel = nil
        while current do
            if current._paSearchSectionKey and current._paSearchScrollChild then
                panel = current
                break
            end
            current = current.GetParent and current:GetParent() or nil
        end

        if panel
            and (tonumber(panel._paSearchDescriptorCaptureDepth) or 0) > 0
            and (parent == panel._paSearchScrollChild or parent._paSettingsSearchTextContainer == true)
        then
            panel._paSearchDescriptorState = panel._paSearchDescriptorState or {
                descriptors = {},
                nextOrderIndex = 1,
            }
            local state = panel._paSearchDescriptorState
            local descriptor = {
                kind = "text",
                sectionKey = panel._paSearchSectionKey,
                sectionName = panel._paSearchSectionName or panel.name or "",
                displayRef = fontString,
                anchorRef = fontString,
                controlRef = fontString,
                searchRefs = { fontString },
                searchWidgetRef = nil,
                searchLabelRef = fontString,
                searchHelperRefs = {},
                searchRowFrame = nil,
                orderIndex = state.nextOrderIndex,
                fontSize = tonumber(size) or 0,
                fontTemplate = template,
                parentRef = parent,
            }
            state.nextOrderIndex = state.nextOrderIndex + 1
            state.descriptors[#state.descriptors + 1] = descriptor
            fontString._paSearchDescriptor = descriptor
            panel._paSearchRegistryDirty = true
            if not panel._paSearchTopTarget then
                panel._paSearchTopTarget = fontString
            end
        end
    end
    return fontString
end

local settingsSearchRuntime = {}

function settingsSearchRuntime.markTextContainer(frame)
    if frameIsAlive(frame) then
        frame._paSettingsSearchTextContainer = true
    end
    return frame
end

function settingsSearchRuntime.getPanelFromObject(object)
    local current = object
    while current do
        if current._paSearchSectionKey and current._paSearchScrollChild then
            return current
        end
        current = current.GetParent and current:GetParent() or nil
    end
    return nil
end

function settingsSearchRuntime.ensureDescriptorState(panel)
    if not panel then
        return nil
    end
    panel._paSearchDescriptorState = panel._paSearchDescriptorState or {
        descriptors = {},
        nextOrderIndex = 1,
    }
    return panel._paSearchDescriptorState
end

function settingsSearchRuntime.beginDescriptorCapture(panel)
    if not panel then
        return
    end
    panel._paSearchDescriptorCaptureDepth = (tonumber(panel._paSearchDescriptorCaptureDepth) or 0) + 1
    panel._paSearchRegistryDirty = true
end

function settingsSearchRuntime.endDescriptorCapture(panel)
    if not panel then
        return
    end
    panel._paSearchDescriptorCaptureDepth = math.max((tonumber(panel._paSearchDescriptorCaptureDepth) or 1) - 1, 0)
end

function settingsSearchRuntime.ensureDescriptorForTextRef(textRef, controlRef)
    if not frameIsAlive(textRef) then
        return nil, nil
    end
    local panel = settingsSearchRuntime.getPanelFromObject(textRef)
    if not panel or (tonumber(panel._paSearchDescriptorCaptureDepth) or 0) <= 0 then
        return nil, panel
    end

    local descriptor = textRef._paSearchDescriptor
    if descriptor then
        if frameIsAlive(controlRef) then
            descriptor.controlRef = controlRef
            descriptor.anchorRef = controlRef
            descriptor.searchWidgetRef = controlRef
        end
        descriptor.searchLabelRef = frameIsAlive(textRef) and textRef or descriptor.searchLabelRef
        descriptor.searchHelperRefs = descriptor.searchHelperRefs or {}
        return descriptor, panel
    end

    local state = settingsSearchRuntime.ensureDescriptorState(panel)
    descriptor = {
        kind = "text",
        sectionKey = panel._paSearchSectionKey,
        sectionName = panel._paSearchSectionName or panel.name or "",
        displayRef = textRef,
        anchorRef = frameIsAlive(controlRef) and controlRef or textRef,
        controlRef = frameIsAlive(controlRef) and controlRef or textRef,
        searchRefs = { textRef },
        searchWidgetRef = frameIsAlive(controlRef) and controlRef or nil,
        searchLabelRef = textRef,
        searchHelperRefs = {},
        searchRowFrame = nil,
        orderIndex = state.nextOrderIndex,
        fontSize = tonumber(textRef._paGlobalFontSize) or 0,
        fontTemplate = nil,
        parentRef = textRef.GetParent and textRef:GetParent() or nil,
    }
    state.nextOrderIndex = state.nextOrderIndex + 1
    state.descriptors[#state.descriptors + 1] = descriptor
    textRef._paSearchDescriptor = descriptor
    panel._paSearchRegistryDirty = true
    if not panel._paSearchTopTarget then
        panel._paSearchTopTarget = textRef
    end
    return descriptor, panel
end

function settingsSearchRuntime.resolveExplicitSearchRowFrame(target)
    if type(target) ~= "table" then
        return nil
    end

    local candidates = {
        target.searchRowFrame,
        target.rowFrame,
        target.rowContainer,
        target.row,
    }
    for i = 1, #candidates do
        if frameIsAlive(candidates[i]) then
            return candidates[i]
        end
    end
    return nil
end

function settingsSearchRuntime.appendUniqueSearchRef(refs, ref)
    if type(refs) ~= "table" or not frameIsAlive(ref) then
        return
    end
    for i = 1, #refs do
        if refs[i] == ref then
            return
        end
    end
    refs[#refs + 1] = ref
end

function settingsSearchRuntime.getIconTypeForKind(kind)
    kind = type(kind) == "string" and string.lower(kind) or ""
    if kind == "toggle" or kind == "checkbox" then
        return "toggle"
    end
    if kind == "dropdown" or kind == "picker" or kind == "font_picker" or kind == "sound_picker" or kind == "texture_picker" then
        return "dropdown"
    end
    if kind == "slider" or kind == "premium_slider" or kind == "stepper" then
        return "slider"
    end
    return nil
end

function settingsSearchRuntime.registerControlText(textRef, controlRef, kind, extraRefs, searchRowFrame)
    local descriptor, panel = settingsSearchRuntime.ensureDescriptorForTextRef(textRef, controlRef)
    if not descriptor then
        return nil
    end

    descriptor.kind = kind or descriptor.kind or "control"
    descriptor.controlRef = frameIsAlive(controlRef) and controlRef or descriptor.controlRef
    descriptor.anchorRef = frameIsAlive(controlRef) and controlRef or descriptor.anchorRef
    descriptor.searchWidgetRef = frameIsAlive(controlRef) and controlRef or descriptor.searchWidgetRef
    descriptor.searchLabelRef = frameIsAlive(textRef) and textRef or descriptor.searchLabelRef
    descriptor.searchRowFrame = frameIsAlive(searchRowFrame) and searchRowFrame or descriptor.searchRowFrame
    descriptor.iconType = settingsSearchRuntime.getIconTypeForKind(kind) or descriptor.iconType
    descriptor.searchRefs = descriptor.searchRefs or {}
    descriptor.searchHelperRefs = descriptor.searchHelperRefs or {}
    if frameIsAlive(textRef) then
        descriptor.searchRefs[1] = textRef
    end
    if type(extraRefs) == "table" then
        for i = 1, #extraRefs do
            settingsSearchRuntime.appendUniqueSearchRef(descriptor.searchRefs, extraRefs[i])
            settingsSearchRuntime.appendUniqueSearchRef(descriptor.searchHelperRefs, extraRefs[i])
        end
    end
    if panel then
        panel._paSearchRegistryDirty = true
    end
    return descriptor
end

function settingsSearchRuntime.registerSpec(spec, explicitKind)
    if type(spec) ~= "table" then
        return spec
    end
    local label = spec.label
    local control = spec.control or spec.slider or spec.button or spec.valueButton or nil
    local extraRefs = {}
    local function addExtraRef(ref)
        if frameIsAlive(ref) then
            extraRefs[#extraRefs + 1] = ref
        end
    end
    addExtraRef(spec.helper)
    addExtraRef(spec.description)
    addExtraRef(spec.desc)
    addExtraRef(spec.hint)
    addExtraRef(spec.helperText)
    addExtraRef(spec.secondaryText)
    addExtraRef(spec.subLabel)
    addExtraRef(spec.valueText)
    addExtraRef(spec.valueEdit)
    addExtraRef(spec.text)
    addExtraRef(spec.caret)
    if type(spec.explainers) == "table" then
        for i = 1, #spec.explainers do
            addExtraRef(spec.explainers[i])
        end
    end
    if type(spec.extraSearchRefs) == "table" then
        for i = 1, #spec.extraSearchRefs do
            addExtraRef(spec.extraSearchRefs[i])
        end
    end
    local searchRowFrame = settingsSearchRuntime.resolveExplicitSearchRowFrame(spec)
    if frameIsAlive(label) then
        settingsSearchRuntime.registerControlText(label, control, explicitKind or spec.kind, extraRefs, searchRowFrame)
    elseif control and control.Text then
        settingsSearchRuntime.registerControlText(control.Text, control, explicitKind or spec.kind, extraRefs, searchRowFrame)
    end
    return spec
end

function settingsSearchRuntime.attachExtraSearchRefs(target, extraRefs)
    if type(target) ~= "table" or type(extraRefs) ~= "table" or #extraRefs <= 0 then
        return nil
    end
    local label = target.label
    local control = target.control or target.slider or target.button or target.valueButton or nil
    local searchRowFrame = settingsSearchRuntime.resolveExplicitSearchRowFrame(target)
    if frameIsAlive(label) then
        return settingsSearchRuntime.registerControlText(label, control, target.kind, extraRefs, searchRowFrame)
    end
    if control and control.Text then
        return settingsSearchRuntime.registerControlText(control.Text, control, target.kind, extraRefs, searchRowFrame)
    end
    return nil
end

local function getClassHex(classFile)
    local color = RAID_CLASS_COLORS and RAID_CLASS_COLORS[classFile]
    if color and color.colorStr then
        return color.colorStr
    end
    return "ffffffff"
end

local function createTopRightHeader(parent, yOffset)
    local header = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
    header:SetJustifyH("RIGHT")
    header:SetText("")
    header:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -20, yOffset or -20)
    header:Hide()
    return header
end

local function PA_SafeBool(v)
    local ok, s = pcall(tostring, v)
    if not ok or s == nil then return false end
    local okb, b = pcall(string.byte, s, 1)
    if not okb or b == nil then return false end
    local nb = tonumber(tostring(b)) or 0
    return nb == 116
end

local function createCheckbox(parent, text, key, onApply)
    local check = CreateFrame("CheckButton", nil, parent, "UICheckButtonTemplate")
    check.text:SetText(text)
    applyGlobalFontToObject(check.text, 12)
    check:SetChecked(PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB[key]))
    check:SetScript("OnClick", function(btn)
        if PortalAuthorityDB then
            PortalAuthorityDB[key] = PA_SafeBool(btn:GetChecked())
        end
        if key == "dockHideInCombat" then
            debugSettingsLog("dockHideInCombat updated:", tostring(PortalAuthorityDB[key]))
        end
        if onApply then onApply() end
    end)
    settingsSearchRuntime.registerControlText(check.text, check, "checkbox")
    return check
end

local function createActionButton(parent, text, onClick, width, searchOpts)
    local btn = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
    btn:SetText(text)
    applyGlobalFontToObject(btn.Text, 12)
    searchOpts = type(searchOpts) == "table" and searchOpts or nil
    if btn.Text and searchOpts and searchOpts.textOrigin then
        settingsSearchRuntime.markSearchTextOrigin(btn.Text, searchOpts.textOrigin, searchOpts)
    end
    btn:SetSize(width or 120, 22)
    btn:SetScript("OnClick", function() if onClick then onClick() end end)
    settingsSearchRuntime.registerControlText(btn.Text, btn, "button")
    return btn
end

local function styleSecondaryActionButtonShared(btn, styleOpts)
    if not btn then
        return
    end
    styleOpts = type(styleOpts) == "table" and styleOpts or {}
    local CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A = 0.10, 0.11, 0.14, 0.95
    local CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A = 0.16, 0.17, 0.20, 0.95
    local CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A = 0.24, 0.27, 0.32, 1.0
    local CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A = 0.30, 0.33, 0.38, 1.0

    local baseBg = styleOpts.baseBg or { CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A }
    local hoverBg = styleOpts.hoverBg or { CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A }
    local pressedBg = styleOpts.pressedBg or { 0.08, 0.09, 0.12, 0.96 }
    local baseBorder = styleOpts.baseBorder or { CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, 0.90 }
    local hoverBorder = styleOpts.hoverBorder or { CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, 0.95 }
    local pressedBorder = styleOpts.pressedBorder or { CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, 0.90 }
    local textColor = styleOpts.textColor or { 0.86, 0.86, 0.89, 1 }

    if not btn._paSecondaryBg then
        btn._paSecondaryBg = btn:CreateTexture(nil, "ARTWORK")
        btn._paSecondaryBg:SetAllPoints(btn)
        btn._paSecondaryBg:SetTexture("Interface\\Buttons\\WHITE8x8")

        btn._paSecondaryBorder = CreateFrame("Frame", nil, btn, "BackdropTemplate")
        btn._paSecondaryBorder:SetPoint("TOPLEFT", btn, "TOPLEFT", -1, 1)
        btn._paSecondaryBorder:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", 1, -1)
        btn._paSecondaryBorder:SetBackdrop({
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
        })
    end

    local function hideTemplateChrome(selfBtn)
        local n = selfBtn.GetNormalTexture and selfBtn:GetNormalTexture() or nil
        local p = selfBtn.GetPushedTexture and selfBtn:GetPushedTexture() or nil
        local h = selfBtn.GetHighlightTexture and selfBtn:GetHighlightTexture() or nil
        local d = selfBtn.GetDisabledTexture and selfBtn:GetDisabledTexture() or nil
        if n then n:SetAlpha(0); if n.Hide then n:Hide() end end
        if p then p:SetAlpha(0); if p.Hide then p:Hide() end end
        if h then h:SetAlpha(0); if h.Hide then h:Hide() end end
        if d then d:SetAlpha(0); if d.Hide then d:Hide() end end
        for _, part in ipairs({
            "Left", "Middle", "Right",
            "LeftDisabled", "MiddleDisabled", "RightDisabled",
            "LeftHighlight", "MiddleHighlight", "RightHighlight",
            "LeftPressed", "MiddlePressed", "RightPressed",
        }) do
            local tex = selfBtn[part]
            if tex and tex.SetAlpha then tex:SetAlpha(0) end
            if tex and tex.Hide then tex:Hide() end
        end
    end

    local function applyVisual(selfBtn)
        hideTemplateChrome(selfBtn)
        local hovered = selfBtn._paSecondaryHover and true or false
        local pressed = selfBtn._paSecondaryPressed and true or false
        if pressed then
            selfBtn._paSecondaryBg:SetVertexColor(pressedBg[1], pressedBg[2], pressedBg[3], pressedBg[4])
            selfBtn._paSecondaryBorder:SetBackdropBorderColor(pressedBorder[1], pressedBorder[2], pressedBorder[3], pressedBorder[4])
        elseif hovered then
            selfBtn._paSecondaryBg:SetVertexColor(hoverBg[1], hoverBg[2], hoverBg[3], hoverBg[4])
            selfBtn._paSecondaryBorder:SetBackdropBorderColor(hoverBorder[1], hoverBorder[2], hoverBorder[3], hoverBorder[4])
        else
            selfBtn._paSecondaryBg:SetVertexColor(baseBg[1], baseBg[2], baseBg[3], baseBg[4])
            selfBtn._paSecondaryBorder:SetBackdropBorderColor(baseBorder[1], baseBorder[2], baseBorder[3], baseBorder[4])
        end
        if selfBtn.Text then
            selfBtn.Text:SetTextColor(textColor[1], textColor[2], textColor[3], textColor[4])
        end
    end

    btn:SetScript("OnEnter", function(selfBtn)
        selfBtn._paSecondaryHover = true
        applyVisual(selfBtn)
    end)
    btn:SetScript("OnLeave", function(selfBtn)
        selfBtn._paSecondaryHover = false
        selfBtn._paSecondaryPressed = false
        applyVisual(selfBtn)
    end)
    btn:SetScript("OnMouseDown", function(selfBtn)
        selfBtn._paSecondaryPressed = true
        applyVisual(selfBtn)
    end)
    btn:SetScript("OnMouseUp", function(selfBtn)
        selfBtn._paSecondaryPressed = false
        applyVisual(selfBtn)
    end)
    btn:HookScript("OnShow", function(selfBtn)
        applyVisual(selfBtn)
    end)
    applyVisual(btn)
end

local function createNumeric(parent, labelText, key, min, max, onApply)
    local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
    label:SetText(labelText)

    local box = CreateFrame("EditBox", nil, parent, "InputBoxTemplate")
    box:SetAutoFocus(false)
    box:SetTextInsets(8, 8, 0, 0)
    box:SetTextColor(1, 1, 1, 1)
    box:SetHighlightColor(1, 1, 1, 0.25)
    applyGlobalFontToObject(box, 12)

    local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
    local defaultValue = defaults[key]
    if defaultValue == nil then
        defaultValue = 0
    end

    local isRefreshing = false
    local isProgrammaticSetText = false
    local didUserEdit = false
    local didInitialHydrate = false

    local function setEditBoxText(text)
        if box:GetText() == text then
            return
        end
        isProgrammaticSetText = true
        box:SetText(text)
        isProgrammaticSetText = false
    end

    local function refreshFromDB()
        local value = PortalAuthorityDB[key]
        if value == nil then
            value = defaultValue
        end
        local text = tostring(value or defaultValue)
        isRefreshing = true
        setEditBoxText(text)
        box:ClearFocus()
        box:HighlightText(0, 0)
        box:SetCursorPosition(0)
        didUserEdit = false
        isRefreshing = false
    end

    refreshFromDB()

    local function apply()
        if isRefreshing or isProgrammaticSetText or not didUserEdit then
            return
        end

        local v = tonumber(box:GetText())
        if not v then
            refreshFromDB()
            return
        end
        if min and v < min then v = min end
        if max and v > max then v = max end
        v = math.floor(v)
        local priorValue = tonumber(PortalAuthorityDB[key])
        local changed = priorValue ~= v
        PortalAuthorityDB[key] = v
        refreshFromDB()
        if changed and onApply then onApply() end
    end

    box:SetScript("OnEditFocusGained", function()
        didUserEdit = false
    end)
    box:SetScript("OnTextChanged", function(_, userInput)
        if isRefreshing or isProgrammaticSetText then
            return
        end
        if userInput then
            didUserEdit = true
        end
    end)

    box:SetScript("OnEnterPressed", function(self)
        apply()
        self:ClearFocus()
    end)
    box:SetScript("OnEditFocusLost", apply)
    box:HookScript("OnShow", function()
        if didInitialHydrate then
            return
        end
        didInitialHydrate = true
        refreshFromDB()
    end)

    local spec = {
        kind = "numeric",
        label = label,
        control = box,
        SetValue = function(_, value)
            if box:HasFocus() then return end
            local numericValue = tonumber(value)
            if numericValue == nil then
                refreshFromDB()
                return
            end
            local text = tostring(math.floor(numericValue))
            isRefreshing = true
            setEditBoxText(text)
            box:ClearFocus()
            box:HighlightText(0, 0)
            box:SetCursorPosition(0)
            didUserEdit = false
            isRefreshing = false
        end,
        Refresh = refreshFromDB,
    }
    settingsSearchRuntime.registerSpec(spec)
    return spec
end

local function setSettingsBackdropColors(frame, bgColor, borderColor)
    if frame and frame.SetBackdropColor then
        frame:SetBackdropColor(unpackColor(bgColor))
    end
    if frame and frame.SetBackdropBorderColor then
        frame:SetBackdropBorderColor(unpackColor(borderColor))
    end
end

local function getSettingsWindowSelectVisual(button, hovered, pressed, enabled)
    if not isUsingCustomSettingsWindowVisualStyle(button) then
        return nil
    end
    if not enabled then
        return {
            bg = SETTINGS_WINDOW_HOST_COLORS.disabledBg,
            border = SETTINGS_WINDOW_HOST_COLORS.disabledBorder,
            text = SETTINGS_WINDOW_HOST_COLORS.disabledText,
        }
    end
    if pressed then
        return {
            bg = SETTINGS_WINDOW_HOST_COLORS.hoverBg,
            border = SETTINGS_WINDOW_HOST_COLORS.onBorder,
            text = SETTINGS_WINDOW_HOST_COLORS.hoverText,
        }
    end
    if hovered then
        return {
            bg = SETTINGS_WINDOW_HOST_COLORS.hoverBg,
            border = SETTINGS_WINDOW_HOST_COLORS.hoverBorder,
            text = SETTINGS_WINDOW_HOST_COLORS.hoverText,
        }
    end
    return {
        bg = SETTINGS_WINDOW_HOST_COLORS.idleBg,
        border = SETTINGS_WINDOW_HOST_COLORS.idleBorder,
        text = SETTINGS_WINDOW_HOST_COLORS.idleText,
    }
end

local function getDropdownTemplateButton(dropdown)
    if not dropdown then
        return nil
    end
    if dropdown.Button then
        return dropdown.Button
    end
    local name = dropdown.GetName and dropdown:GetName() or nil
    if type(name) == "string" and name ~= "" then
        return _G[name .. "Button"]
    end
    return nil
end

local function getDropdownTemplateText(dropdown)
    if not dropdown then
        return nil
    end
    if dropdown.Text then
        return dropdown.Text
    end
    local name = dropdown.GetName and dropdown:GetName() or nil
    if type(name) == "string" and name ~= "" then
        return _G[name .. "Text"]
    end
    return nil
end

local function setDropdownTemplateTexturesVisible(dropdown, visible)
    if not dropdown then
        return
    end

    local alpha = visible and 1 or 0
    for _, key in ipairs({
        "Left", "Middle", "Right",
        "LeftHighlight", "MiddleHighlight", "RightHighlight",
        "LeftDisabled", "MiddleDisabled", "RightDisabled",
    }) do
        local tex = dropdown[key]
        if tex and tex.SetAlpha then
            tex:SetAlpha(alpha)
        end
        if tex and tex.SetShown then
            tex:SetShown(visible)
        elseif tex and visible then
            tex:Show()
        elseif tex then
            tex:Hide()
        end
    end

    local button = getDropdownTemplateButton(dropdown)
    if button then
        for _, getterName in ipairs({ "GetNormalTexture", "GetPushedTexture", "GetHighlightTexture", "GetDisabledTexture" }) do
            local getter = button[getterName]
            local tex = getter and getter(button) or nil
            if tex and tex.SetAlpha then
                tex:SetAlpha(alpha)
            end
            if tex and tex.SetShown then
                tex:SetShown(visible)
            elseif tex and visible then
                tex:Show()
            elseif tex then
                tex:Hide()
            end
        end
    end
end

local function ensureSettingsWindowDropdownChrome(dropdown)
    if not dropdown or dropdown._paHostDropdownReady then
        return
    end
    dropdown._paHostDropdownReady = true

    local chrome = CreateFrame("Frame", nil, dropdown, "BackdropTemplate")
    chrome:SetBackdrop(FLAT_SETTINGS_BACKDROP)
    chrome:SetPoint("TOPLEFT", dropdown, "TOPLEFT", 18, -3)
    chrome:SetPoint("BOTTOMRIGHT", dropdown, "BOTTOMRIGHT", -18, 9)
    chrome:SetFrameStrata(dropdown:GetFrameStrata())
    chrome:SetFrameLevel(math.max(1, (dropdown:GetFrameLevel() or 1) - 1))
    dropdown._paHostDropdownChrome = chrome

    local text = getDropdownTemplateText(dropdown)
    if text then
        applyGlobalFontToObject(text, 11)
    end

    local function applyVisual(selfDropdown)
        local button = getDropdownTemplateButton(selfDropdown)
        local hoverSource = button or selfDropdown
        local hovered = hoverSource and hoverSource.IsMouseOver and hoverSource:IsMouseOver() or false
        local enabled = true
        if button and button.IsEnabled then
            enabled = button:IsEnabled()
        end

        local themed = getSettingsWindowSelectVisual(selfDropdown, hovered, false, enabled)
        if not themed then
            chrome:Hide()
            setDropdownTemplateTexturesVisible(selfDropdown, true)
            return
        end

        chrome:Show()
        setDropdownTemplateTexturesVisible(selfDropdown, false)
        setSettingsBackdropColors(chrome, themed.bg, themed.border)
        if text and text.SetTextColor then
            text:SetTextColor(unpackColor(themed.text))
        end
    end

    registerSettingsWindowVisualRefresh(dropdown, applyVisual)
    dropdown:HookScript("OnShow", applyVisual)
    dropdown:HookScript("OnHide", applyVisual)

    local button = getDropdownTemplateButton(dropdown)
    if button then
        button:HookScript("OnEnter", function()
            applyVisual(dropdown)
        end)
        button:HookScript("OnLeave", function()
            applyVisual(dropdown)
        end)
    end

    applyVisual(dropdown)
end

local function applySettingsWindowSelectButtonChrome(button, text, caret, hovered, pressed, enabled, legacyVisual)
    local themed = getSettingsWindowSelectVisual(button, hovered, pressed, enabled)
    if themed then
        setSettingsBackdropColors(button, themed.bg, themed.border)
        if text and text.SetTextColor then
            text:SetTextColor(unpackColor(themed.text))
        end
        if caret and caret.SetTextColor then
            caret:SetTextColor(unpackColor(themed.text))
        end
        return true
    end
    if type(legacyVisual) == "function" then
        legacyVisual()
    end
    return false
end

local function createDropdown(parent, labelText, values, key, onApply)
    local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
    label:SetText(labelText)

    local dropdown = CreateFrame("Frame", nil, parent, "UIDropDownMenuTemplate")
    ensureSettingsWindowDropdownChrome(dropdown)

    UIDropDownMenu_Initialize(dropdown, function(_, level)
        for _, option in ipairs(values) do
            local info = UIDropDownMenu_CreateInfo()
            info.text = option.label
            info.checked = PortalAuthorityDB[key] == option.value
            info.func = function()
                PortalAuthorityDB[key] = option.value
                UIDropDownMenu_SetSelectedValue(dropdown, option.value)
                UIDropDownMenu_SetText(dropdown, option.label)
                if onApply then onApply() end
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)

    local spec = { kind = "dropdown", label = label, control = dropdown }
    spec.Refresh = function()
        local selectedLabel, selectedValue = values[1].label, values[1].value
        for _, option in ipairs(values) do
            if option.value == PortalAuthorityDB[key] then
                selectedLabel, selectedValue = option.label, option.value
                break
            end
        end
        PortalAuthorityDB[key] = selectedValue
        UIDropDownMenu_SetSelectedValue(dropdown, selectedValue)
        UIDropDownMenu_SetText(dropdown, selectedLabel)
    end

    spec.Refresh()
    return settingsSearchRuntime.registerSpec(spec)
end

local function createDynamicDropdown(parent, labelText, optionsProvider, getter, setter, onApply)
    local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
    label:SetText(labelText)

    local dropdown = CreateFrame("Frame", nil, parent, "UIDropDownMenuTemplate")
    ensureSettingsWindowDropdownChrome(dropdown)

    local function getOptions()
        local options = optionsProvider and optionsProvider() or {}
        if #options == 0 then
            options = { { label = "None", value = "" } }
        end
        return options
    end

    local function refreshSelection(options)
        local selectedValue = getter and getter() or ""
        local selectedLabel = nil
        for _, option in ipairs(options) do
            if option.value == selectedValue then
                selectedLabel = option.label
                break
            end
        end

        if not selectedLabel then
            local first = options[1]
            selectedValue = first and first.value or ""
            selectedLabel = first and first.label or ""
            if setter then setter(selectedValue) end
        end

        UIDropDownMenu_SetSelectedValue(dropdown, selectedValue)
        UIDropDownMenu_SetText(dropdown, selectedLabel)
    end

    UIDropDownMenu_Initialize(dropdown, function(_, level)
        local options = getOptions()
        local selectedValue = getter and getter() or ""
        for _, option in ipairs(options) do
            local info = UIDropDownMenu_CreateInfo()
            info.text = option.label
            info.checked = selectedValue == option.value
            info.func = function()
                if setter then setter(option.value) end
                UIDropDownMenu_SetSelectedValue(dropdown, option.value)
                UIDropDownMenu_SetText(dropdown, option.label)
                if onApply then onApply() end
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)

    local spec = { kind = "dropdown", label = label, control = dropdown }
    spec.Refresh = function()
        refreshSelection(getOptions())
    end

    spec.Refresh()
    return settingsSearchRuntime.registerSpec(spec)
end

local function createPremiumSegmentedChoice(parent, labelText, key, choices, onApply, opts)
    opts = type(opts) == "table" and opts or {}
    local semantic = string.lower(trim(tostring(opts.semantic or "")))
    if semantic ~= "toggle" and semantic ~= "selection" then
        semantic = "selection"
    end
    local searchChoiceLabelMode = settingsSearchRuntime.normalizeChoiceLabelMode(opts.searchChoiceLabelMode)
    local selectionVariant = tostring(opts.selectionVariant or "")
    local controlHeight = math.max(16, tonumber(opts.controlHeight) or 22)
    local controlTextSize = math.max(9, tonumber(opts.textSize) or 11)
    local textEllipsis = opts.textEllipsis and true or false
    local controlMinWidth = math.max(0, tonumber(opts.minWidth) or 120)
    local segmentGap = math.max(0, tonumber(opts.segmentGap) or 4)
    local segmentMinWidth = math.max(20, tonumber(opts.segmentMinWidth) or 48)
    local normalizeValue = type(opts.normalizeValue) == "function" and opts.normalizeValue or nil
    local getValue = type(opts.getValue) == "function" and opts.getValue or nil
    local setValue = type(opts.setValue) == "function" and opts.setValue or nil

    local CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A = 0.10, 0.11, 0.14, 0.95
    local CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A = 0.16, 0.17, 0.20, 0.95
    local CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A = 0.24, 0.27, 0.32, 1.0
    local CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A = 0.30, 0.33, 0.38, 1.0
    local OFF_RED_BG_R, OFF_RED_BG_G, OFF_RED_BG_B, OFF_RED_BG_A = 0.23, 0.05, 0.075, 0.93
    local OFF_RED_BORDER_SELECTED_R, OFF_RED_BORDER_SELECTED_G, OFF_RED_BORDER_SELECTED_B, OFF_RED_BORDER_SELECTED_A = 0.22, 0.049, 0.074, 1.0
    local OFF_RED_TEXT_R, OFF_RED_TEXT_G, OFF_RED_TEXT_B, OFF_RED_TEXT_A = 0.90, 0.76, 0.76, 1.0
    local OFF_RED_SELECTED_ALPHA = 0.95
    local OFF_RED_TOPSHEEN_ALPHA = 0.14

    local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
    label:SetText(labelText or "")
    local container = CreateFrame("Frame", nil, parent)
    local buttons = {}
    local updateButtonVisual
    local controlEnabled = true
    local choiceEnabledByValue = {}
    local function useSettingsWindowHostTheme()
        return isUsingCustomSettingsWindowVisualStyle(container)
    end

    local function setSegmentBorderColor(btn, r, g, b, a)
        if not btn or not btn._paBorder then
            return
        end
        local colorKey = string.format("%.4f:%.4f:%.4f:%.4f", tonumber(r) or 0, tonumber(g) or 0, tonumber(b) or 0, tonumber(a) or 0)
        if btn._paBorder._paLastBorderColorKey ~= colorKey then
            btn._paBorder:SetBackdropBorderColor(r, g, b, a)
            btn._paBorder._paLastBorderColorKey = colorKey
        end
        btn._paBorder:SetAlpha(1)
        btn._paBorder:Show()
    end

    local function normalizeSegmentValue(v)
        if normalizeValue then
            return normalizeValue(v)
        end
        return v
    end

    local function ensureFlatSkin(btn)
        if not btn then
            return
        end
        if not btn._paSkinReady then
            btn._paSkinReady = true
            btn._paBg = btn:CreateTexture(nil, "ARTWORK")
            btn._paBg:SetAllPoints(btn)
            btn._paBg:SetTexture("Interface\\Buttons\\WHITE8x8")
            btn._paBorder = CreateFrame("Frame", nil, btn, "BackdropTemplate")
            btn._paBorder:SetPoint("TOPLEFT", btn, "TOPLEFT", -1, 1)
            btn._paBorder:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", 1, -1)
            btn._paBorder:SetBackdrop({
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
            })
            setSegmentBorderColor(btn, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A)
            btn._paTopSheen = btn:CreateTexture(nil, "OVERLAY")
            btn._paTopSheen:SetAllPoints(btn)
            btn._paTopSheen:SetTexture("Interface\\Buttons\\WHITE8x8")
            if btn._paTopSheen.SetGradientAlpha then
                btn._paTopSheen:SetGradientAlpha("VERTICAL", 1, 1, 1, 0.12, 1, 1, 1, 0.0)
            else
                btn._paTopSheen:SetVertexColor(1, 1, 1, 0.1)
            end
            btn._paGlow = btn:CreateTexture(nil, "BORDER")
            btn._paGlow:SetAllPoints(btn)
            btn._paGlow:SetTexture("Interface\\Buttons\\WHITE8x8")
            btn._paGlow:SetBlendMode("ADD")
        end

        local n = btn.GetNormalTexture and btn:GetNormalTexture() or nil
        local p = btn.GetPushedTexture and btn:GetPushedTexture() or nil
        local h = btn.GetHighlightTexture and btn:GetHighlightTexture() or nil
        local d = btn.GetDisabledTexture and btn:GetDisabledTexture() or nil
        if n then n:SetAlpha(0); if n.Hide then n:Hide() end end
        if p then p:SetAlpha(0); if p.Hide then p:Hide() end end
        if h then h:SetAlpha(0); if h.Hide then h:Hide() end end
        if d then d:SetAlpha(0); if d.Hide then d:Hide() end end

        for _, part in ipairs({
            "Left", "Middle", "Right",
            "LeftDisabled", "MiddleDisabled", "RightDisabled",
            "LeftHighlight", "MiddleHighlight", "RightHighlight",
            "LeftPressed", "MiddlePressed", "RightPressed",
        }) do
            local tex = btn[part]
            if tex and tex.SetAlpha then tex:SetAlpha(0) end
            if tex and tex.Hide then tex:Hide() end
        end

        if btn._paBorder then
            local baseLevel = btn:GetFrameLevel() or 0
            btn._paBorder:SetFrameStrata(btn:GetFrameStrata())
            btn._paBorder:SetFrameLevel(baseLevel + 3)
        end
    end

    local function scalePressOffset(btn, value)
        local v = tonumber(value) or 0
        if v == 0 then
            return 0
        end
        if not btn or not btn.GetEffectiveScale then
            return v
        end
        local scale = btn:GetEffectiveScale() or 1
        if scale == 0 then
            return v
        end
        local absV = math.abs(v)
        if absV < 0.5 then
            absV = 0.5
        end
        local sign = (v < 0) and -1 or 1
        return (absV / scale) * sign
    end

    local function setSegmentTextOffset(btn, x, y)
        if not btn or not btn.Text then
            return
        end
        local offsetX = scalePressOffset(btn, x)
        local offsetY = scalePressOffset(btn, y)
        btn.Text:ClearAllPoints()
        btn.Text:SetPoint("CENTER", btn, "CENTER", offsetX, offsetY)
    end

    local function resolvePressTextOffsetX()
        local override = tonumber(opts.pressTextOffsetX)
        if override then
            return override
        end
        if semantic == "selection" and selectionVariant == "lock_meta" then
            return 0.30
        end
        return 0.30
    end

    local function resolvePressTextOffsetY()
        local override = tonumber(opts.pressTextOffsetY)
        if override then
            return override
        end
        if semantic == "selection" and selectionVariant == "lock_meta" then
            return -0.30
        end
        return -0.30
    end

    local PRESS_TEXT_OFFSET_X = resolvePressTextOffsetX()
    local PRESS_TEXT_OFFSET_Y = resolvePressTextOffsetY()

    local function clearSegmentPressState(selfBtn)
        if not selfBtn then
            return
        end
        selfBtn._paPressed = false
        setSegmentTextOffset(selfBtn, 0, 0)
        if useSettingsWindowHostTheme() and selfBtn.SetPushedTextOffset then
            selfBtn:SetPushedTextOffset(0, 0)
        end
    end

    updateButtonVisual = function(btn, selected)
        if not btn then return end
        local hovered = btn._paHovered and true or false
        local toggleState = btn._toggleState or "on"
        local choiceEnabled = (choiceEnabledByValue[btn._value] ~= false)
        local useHostVisuals = useSettingsWindowHostTheme()
        local useHostToggleTheme = useHostVisuals and semantic == "toggle"
        ensureFlatSkin(btn)

        if useHostToggleTheme then
            local bgColor = hovered and SETTINGS_WINDOW_HOST_COLORS.hoverBg or SETTINGS_WINDOW_HOST_COLORS.idleBg
            local borderColor = hovered and SETTINGS_WINDOW_HOST_COLORS.hoverBorder or SETTINGS_WINDOW_HOST_COLORS.idleBorder
            local textColor = hovered and SETTINGS_WINDOW_HOST_COLORS.hoverText or SETTINGS_WINDOW_HOST_COLORS.idleText

            if (not controlEnabled) or (not choiceEnabled) then
                bgColor = SETTINGS_WINDOW_HOST_COLORS.disabledBg
                borderColor = SETTINGS_WINDOW_HOST_COLORS.disabledBorder
                textColor = SETTINGS_WINDOW_HOST_COLORS.disabledText
                clearSegmentPressState(btn)
                if btn._paGlow then
                    btn._paGlow:SetVertexColor(1, 1, 1, 0)
                end
                if btn._paTopSheen then
                    btn._paTopSheen:SetAlpha(0.05)
                end
                btn:SetAlpha(controlEnabled and 0.72 or 0.58)
            elseif selected then
                if toggleState == "off" then
                    bgColor = SETTINGS_WINDOW_HOST_COLORS.offBg
                    borderColor = SETTINGS_WINDOW_HOST_COLORS.offBorder
                    textColor = SETTINGS_WINDOW_HOST_COLORS.offText
                    if btn._paGlow then
                        btn._paGlow:SetVertexColor(unpackColor(SETTINGS_WINDOW_HOST_COLORS.offBorder))
                        btn._paGlow:SetAlpha(hovered and 0.12 or 0.08)
                    end
                else
                    bgColor = SETTINGS_WINDOW_HOST_COLORS.onBg
                    borderColor = SETTINGS_WINDOW_HOST_COLORS.onBorder
                    textColor = SETTINGS_WINDOW_HOST_COLORS.onText
                    if btn._paGlow then
                        btn._paGlow:SetVertexColor(unpackColor(SETTINGS_WINDOW_HOST_COLORS.onBorder))
                        btn._paGlow:SetAlpha(hovered and 0.16 or 0.10)
                    end
                end
                if btn._paTopSheen then
                    btn._paTopSheen:SetAlpha(hovered and 0.18 or 0.12)
                end
                btn:SetAlpha(1)
            else
                if btn._paGlow then
                    btn._paGlow:SetVertexColor(1, 1, 1, 0)
                end
                if btn._paTopSheen then
                    btn._paTopSheen:SetAlpha(hovered and 0.12 or 0.08)
                end
                btn:SetAlpha(0.98)
            end

            btn._paBg:SetVertexColor(unpackColor(bgColor))
            setSegmentBorderColor(btn, unpackColor(borderColor))
            if btn.Text then
                btn.Text:SetTextColor(unpackColor(textColor))
            end
            return
        end

        if not choiceEnabled then
            clearSegmentPressState(btn)
            btn._paBg:SetVertexColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
            if btn._paGlow then
                btn._paGlow:SetVertexColor(1, 1, 1, 0)
            end
            if btn._paTopSheen then
                btn._paTopSheen:SetAlpha(0.04)
            end
            setSegmentBorderColor(btn, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, 0.72)
            if btn.Text then
                btn.Text:SetTextColor(0.50, 0.50, 0.53, 1)
            end
            btn:SetAlpha(controlEnabled and 0.52 or 0.45)
            return
        end

        if semantic == "toggle" then
            if selected then
                if toggleState == "on" then
                    if hovered then
                        btn._paBg:SetVertexColor(0.13, 0.28, 0.15, 0.98)
                    else
                        btn._paBg:SetVertexColor(0.11, 0.23, 0.13, 0.96)
                    end
                    if btn._paGlow then
                        btn._paGlow:SetVertexColor(0.28, 1.0, 0.36, hovered and 0.14 or 0.1)
                    end
                    if btn.Text then
                        btn.Text:SetTextColor(0.72, 1.0, 0.74, 1)
                    end
                    setSegmentBorderColor(btn, 0.18, 0.55, 0.2, hovered and 0.95 or 0.82)
                    if btn._paTopSheen then
                        btn._paTopSheen:SetAlpha(0.22)
                    end
                else
                    btn._paBg:SetVertexColor(OFF_RED_BG_R, OFF_RED_BG_G, OFF_RED_BG_B, OFF_RED_BG_A)
                    if btn._paGlow then
                        btn._paGlow:SetVertexColor(0.95, 0.22, 0.22, 0)
                    end
                    if btn.Text then
                        btn.Text:SetTextColor(OFF_RED_TEXT_R, OFF_RED_TEXT_G, OFF_RED_TEXT_B, OFF_RED_TEXT_A)
                    end
                    setSegmentBorderColor(btn, OFF_RED_BORDER_SELECTED_R, OFF_RED_BORDER_SELECTED_G, OFF_RED_BORDER_SELECTED_B, OFF_RED_BORDER_SELECTED_A)
                    if btn._paTopSheen then
                        btn._paTopSheen:SetAlpha(OFF_RED_TOPSHEEN_ALPHA)
                    end
                end
            else
                if hovered then
                    btn._paBg:SetVertexColor(CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A)
                else
                    btn._paBg:SetVertexColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
                end
                if btn._paGlow then
                    btn._paGlow:SetVertexColor(1, 1, 1, 0)
                end
                if btn.Text then
                    btn.Text:SetTextColor(0.85, 0.85, 0.88, 1)
                end
                if hovered then
                    setSegmentBorderColor(btn, CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A)
                else
                    setSegmentBorderColor(btn, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A)
                end
                if btn._paTopSheen then
                    btn._paTopSheen:SetAlpha(hovered and 0.12 or 0.08)
                end
            end
            if selected and toggleState ~= "on" then
                btn:SetAlpha(OFF_RED_SELECTED_ALPHA)
            else
                btn:SetAlpha(0.98)
            end
        else
            if selected then
                local useLockMetaVariant = (selectionVariant == "lock_meta")
                if useHostVisuals then
                    useLockMetaVariant = false
                end
                if hovered then
                    if useLockMetaVariant then
                        btn._paBg:SetVertexColor(0.28, 0.29, 0.33, 0.98)
                    else
                        btn._paBg:SetVertexColor(0.25, 0.26, 0.30, 0.98)
                    end
                else
                    if useLockMetaVariant then
                        btn._paBg:SetVertexColor(0.25, 0.26, 0.30, 0.96)
                    else
                        btn._paBg:SetVertexColor(0.22, 0.23, 0.27, 0.96)
                    end
                end
                if btn._paGlow then
                    if useLockMetaVariant then
                        btn._paGlow:SetVertexColor(1.0, 0.82, 0.1, 0)
                    else
                        btn._paGlow:SetVertexColor(1.0, 0.82, 0.1, hovered and 0.1 or 0.06)
                    end
                end
                if useLockMetaVariant then
                    if hovered then
                        setSegmentBorderColor(btn, 0.38, 0.41, 0.46, 0.96)
                    else
                        setSegmentBorderColor(btn, 0.34, 0.37, 0.42, 0.90)
                    end
                else
                    setSegmentBorderColor(btn, 0.95, 0.75, 0.2, hovered and 0.95 or 0.82)
                end
                if btn._paTopSheen then
                    if useLockMetaVariant then
                        btn._paTopSheen:SetAlpha(0.28)
                    else
                        btn._paTopSheen:SetAlpha(0.26)
                    end
                end
                btn:SetAlpha(1)
                if btn.Text then
                    if useLockMetaVariant then
                        btn.Text:SetTextColor(0.94, 0.95, 0.97, 1)
                    else
                        btn.Text:SetTextColor(0.99, 0.95, 0.82, 1)
                    end
                end
            else
                if hovered then
                    btn._paBg:SetVertexColor(CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A)
                else
                    btn._paBg:SetVertexColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
                end
                if btn._paGlow then
                    btn._paGlow:SetVertexColor(1.0, 0.82, 0.1, 0)
                end
                if hovered then
                    setSegmentBorderColor(btn, CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A)
                else
                    setSegmentBorderColor(btn, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A)
                end
                if btn._paTopSheen then
                    btn._paTopSheen:SetAlpha(hovered and 0.12 or 0.08)
                end
                btn:SetAlpha(0.96)
                if btn.Text then
                    btn.Text:SetTextColor(0.82, 0.83, 0.86, 1)
                end
            end
        end

        if not controlEnabled then
            clearSegmentPressState(btn)
            btn:SetAlpha(0.55)
            if btn.Text then
                btn.Text:SetTextColor(0.62, 0.62, 0.64, 1)
            end
            if btn._paGlow then
                btn._paGlow:SetVertexColor(1, 1, 1, 0)
            end
        end
    end

    local function applySelectionVisual(value)
        local normalizedValue = normalizeSegmentValue(value)
        for _, btn in ipairs(buttons) do
            local selected = (btn._value == normalizedValue)
            btn._selected = selected and true or false
            updateButtonVisual(btn, selected)
        end
    end

    local function setSelectedVisual(value)
        applySelectionVisual(normalizeSegmentValue(value))
    end

    local function setSelected(value, triggerApply)
        local normalizedValue = normalizeSegmentValue(value)
        if setValue then
            setValue(normalizedValue)
        elseif key ~= nil then
            PortalAuthorityDB[key] = normalizedValue
        end
        setSelectedVisual(normalizedValue)
        if triggerApply and onApply then
            onApply(normalizedValue)
        end
    end

    for i, choice in ipairs(choices or {}) do
        local choiceValue = normalizeSegmentValue(choice.value)
        local choiceLabel = choice.label
        local choiceToggleState = choice.toggleState
        local btn = CreateFrame("Button", nil, container)
        btn:SetSize(72, controlHeight)
        btn.Text = createStyledFontString(btn, "ARTWORK", "GameFontHighlightSmall", controlTextSize)
        settingsSearchRuntime.markSearchTextOrigin(btn.Text, "choice_caption", {
            searchChoiceLabelMode = searchChoiceLabelMode,
        })
        btn.Text:SetPoint("CENTER", btn, "CENTER", 0, 0)
        btn.Text:SetJustifyH("CENTER")
        btn.Text:SetJustifyV("MIDDLE")
        btn.Text:SetWordWrap(false)
        if btn.Text.SetMaxLines then
            btn.Text:SetMaxLines(1)
        end
        btn._baseLabel = tostring(choiceLabel or "")
        btn.Text:SetText(btn._baseLabel)
        applyGlobalFontToObject(btn.Text, controlTextSize)
        btn._value = choiceValue
        btn._toggleState = tostring(choiceToggleState or "on")
        btn._paHovered = false
        btn._selected = false
        btn._paPressed = false
        if choiceEnabledByValue[choiceValue] == nil then
            choiceEnabledByValue[choiceValue] = true
        end
        ensureFlatSkin(btn)
        btn:HookScript("OnShow", function(selfBtn)
            ensureFlatSkin(selfBtn)
            clearSegmentPressState(selfBtn)
            updateButtonVisual(selfBtn, selfBtn._selected and true or false)
        end)
        btn:HookScript("OnHide", function(selfBtn)
            clearSegmentPressState(selfBtn)
        end)
        btn:SetScript("OnEnter", function(selfBtn)
            if not controlEnabled or choiceEnabledByValue[selfBtn._value] == false then
                selfBtn._paHovered = false
                updateButtonVisual(selfBtn, selfBtn._selected and true or false)
                return
            end
            selfBtn._paHovered = true
            updateButtonVisual(selfBtn, selfBtn._selected and true or false)
        end)
        btn:SetScript("OnLeave", function(selfBtn)
            selfBtn._paHovered = false
            clearSegmentPressState(selfBtn)
            updateButtonVisual(selfBtn, selfBtn._selected and true or false)
        end)
        btn:SetScript("OnMouseDown", function(selfBtn)
            if not controlEnabled then
                return
            end
            if choiceEnabledByValue[selfBtn._value] == false then
                return
            end
            if not useSettingsWindowHostTheme() then
                return
            end
            selfBtn._paPressed = true
            setSegmentTextOffset(selfBtn, PRESS_TEXT_OFFSET_X, PRESS_TEXT_OFFSET_Y)
            updateButtonVisual(selfBtn, selfBtn._selected and true or false)
        end)
        btn:SetScript("OnMouseUp", function(selfBtn)
            clearSegmentPressState(selfBtn)
            updateButtonVisual(selfBtn, selfBtn._selected and true or false)
        end)
        btn:SetScript("OnClick", function()
            if not controlEnabled then
                return
            end
            if choiceEnabledByValue[choiceValue] == false then
                return
            end
            if btn._selected then
                return
            end
            setSelected(choiceValue, true)
        end)
        buttons[i] = btn
    end

    local spec = { kind = "segmented", label = label, control = container, buttons = buttons }
    spec.Layout = function(_, width)
        local count = #buttons
        if count <= 0 then
            container:SetSize(width or 0, controlHeight)
            return
        end
        local gap = segmentGap
        local w = math.max(controlMinWidth, tonumber(width) or controlMinWidth)
        local btnW = math.max(segmentMinWidth, (w - ((count - 1) * gap)) / count)
        local x = 0
        container:SetSize(w, controlHeight)
        for _, btn in ipairs(buttons) do
            btn:ClearAllPoints()
            btn:SetPoint("TOPLEFT", container, "TOPLEFT", x, 0)
            btn:SetSize(btnW, controlHeight)
            if btn.Text then
                btn.Text:ClearAllPoints()
                btn.Text:SetPoint("CENTER", btn, "CENTER", 0, 0)
                btn.Text:SetJustifyH("CENTER")
                btn.Text:SetJustifyV("MIDDLE")
                btn.Text:SetWidth(math.max(1, btnW - 8))
                if textEllipsis and type(setSingleLineEllipsis) == "function" then
                    setSingleLineEllipsis(btn.Text, btn._baseLabel or "", math.max(1, btnW - 8))
                else
                    btn.Text:SetText(btn._baseLabel or "")
                end
            end
            updateButtonVisual(btn, btn._selected and true or false)
            x = x + btnW + gap
        end
    end
    spec.Refresh = function()
        local selectedRaw
        if getValue then
            selectedRaw = getValue()
        elseif key ~= nil then
            selectedRaw = PortalAuthorityDB[key]
        end
        local selected = normalizeSegmentValue(selectedRaw)
        local valid = false
        local function isChoiceValue(candidate)
            local normalizedCandidate = normalizeSegmentValue(candidate)
            for _, choice in ipairs(choices or {}) do
                if normalizeSegmentValue(choice.value) == normalizedCandidate then
                    return true
                end
            end
            return false
        end
        for _, choice in ipairs(choices or {}) do
            if normalizeSegmentValue(choice.value) == selected then
                valid = true
                break
            end
        end
        if not valid then
            local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
            local fallback = defaults[key]
            if isChoiceValue(fallback) then
                selected = normalizeSegmentValue(fallback)
            else
                selected = choices and choices[1] and normalizeSegmentValue(choices[1].value) or nil
            end
            if selected ~= nil then
                if setValue then
                    setValue(selected)
                elseif key ~= nil then
                    PortalAuthorityDB[key] = selected
                end
            end
        end
        if selected ~= nil then
            setSelectedVisual(selected)
        end
    end
    spec.SetVisualSelectedValue = function(_, value)
        setSelectedVisual(value)
    end
    spec.GetSelectedValue = function()
        for _, btn in ipairs(buttons) do
            if btn and btn._selected then
                return btn._value
            end
        end
        if getValue then
            return normalizeSegmentValue(getValue())
        end
        if key ~= nil then
            return normalizeSegmentValue(PortalAuthorityDB[key])
        end
        return nil
    end
    spec.SetSelectedValue = function(_, value, triggerApply)
        setSelected(value, triggerApply and true or false)
    end
    spec.SetChoiceEnabled = function(_, value, enabled)
        local normalizedValue = normalizeSegmentValue(value)
        choiceEnabledByValue[normalizedValue] = enabled and true or false
        for _, btn in ipairs(buttons) do
            if btn._value == normalizedValue then
                btn._paHovered = false
                clearSegmentPressState(btn)
            end
            updateButtonVisual(btn, btn._selected and true or false)
        end
    end
    spec.IsChoiceEnabled = function(_, value)
        local normalizedValue = normalizeSegmentValue(value)
        return choiceEnabledByValue[normalizedValue] ~= false
    end
    spec.SetEnabled = function(_, enabled)
        controlEnabled = enabled and true or false
        for _, btn in ipairs(buttons) do
            btn:SetEnabled(controlEnabled)
            clearSegmentPressState(btn)
        end
        local selected = nil
        for _, btn in ipairs(buttons) do
            if btn._selected then
                selected = btn._value
                break
            end
        end
        if selected ~= nil then
            setSelectedVisual(selected)
        else
            spec.Refresh()
        end
        label:SetAlpha(controlEnabled and 1 or 0.65)
    end
    spec.IsEnabled = function()
        return controlEnabled
    end
    spec.RefreshVisual = function()
        for _, btn in ipairs(buttons) do
            updateButtonVisual(btn, btn._selected and true or false)
        end
        label:SetAlpha(controlEnabled and 1 or 0.65)
    end
    registerSettingsWindowVisualRefresh(container, function()
        spec:RefreshVisual()
    end)
    spec.Refresh()
    return settingsSearchRuntime.registerSpec(spec, semantic == "toggle" and "toggle" or spec.kind)
end

ACTIVE_PORTAL_PICKER = nil

local function CreatePicker(parent, options, onSelectCallback, uiConfig)
    uiConfig = type(uiConfig) == "table" and uiConfig or {}
    local preserveOrder = uiConfig.preserveOrder and true or false
    local noSearch = uiConfig.noSearch and true or false
    local hideTitle = uiConfig.hideTitle and true or false
    local hideScrollBar = uiConfig.hideScrollBar and true or false
    local showClearButton = uiConfig.showClearButton ~= false
    local showCloseButton = uiConfig.showCloseButton ~= false
    local footerFlowWithRows = uiConfig.footerFlowWithRows and true or false
    local onOptionRightClick = type(uiConfig.onOptionRightClick) == "function" and uiConfig.onOptionRightClick or nil
    local footerHintText = tostring(uiConfig.footerHint or "")
    local minPickerHeight = math.max(120, math.floor(tonumber(uiConfig.minHeight) or 220))

    local picker = CreateFrame("Frame", nil, parent or UIParent, "BackdropTemplate")
    picker:SetFrameStrata("DIALOG")
    picker:SetToplevel(true)
    picker:SetClampedToScreen(true)
    picker:EnableMouseWheel(true)
    picker:SetSize(
        math.max(260, math.floor(tonumber(uiConfig.width) or 520)),
        math.max(minPickerHeight, math.floor(tonumber(uiConfig.height) or 420))
    )
    picker:Hide()
    picker:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        edgeSize = 12,
        insets = { left = 3, right = 3, top = 3, bottom = 3 },
    })
    picker:SetBackdropColor(0.05, 0.06, 0.08, 0.98)
    picker:SetBackdropBorderColor(0.32, 0.35, 0.4, 1)

    local title = createStyledFontString(picker, "ARTWORK", "GameFontHighlight", 12)
    title:SetText(tostring(uiConfig.title or "Select Destination"))
    title:SetPoint("TOPLEFT", picker, "TOPLEFT", 16, -12)

    local search = CreateFrame("EditBox", nil, picker, "InputBoxTemplate")
    search:SetAutoFocus(false)
    search:SetTextInsets(8, 8, 0, 0)
    search:SetTextColor(1, 1, 1, 1)
    search:SetHighlightColor(1, 1, 1, 0.25)
    search:SetPoint("TOPLEFT", picker, "TOPLEFT", 14, -34)
    search:SetPoint("TOPRIGHT", picker, "TOPRIGHT", -14, -34)
    search:SetHeight(22)
    search:EnableMouseWheel(true)
    applyGlobalFontToObject(search, 12)

    local searchHint = createStyledFontString(picker, "ARTWORK", "GameFontHighlightSmall", 11)
    searchHint:SetText(tostring(uiConfig.searchHint or "Search destinations (name, short, spell ID)"))
    searchHint:SetTextColor(0.72, 0.72, 0.72, 1)
    searchHint:SetPoint("TOPLEFT", search, "BOTTOMLEFT", 2, -4)

    local footerHint = createStyledFontString(picker, "ARTWORK", "GameFontHighlightSmall", 10)
    footerHint:SetJustifyH("LEFT")
    footerHint:SetTextColor(0.72, 0.72, 0.72, 0.92)
    footerHint:SetWordWrap(false)
    if footerHint.SetMaxLines then
        footerHint:SetMaxLines(1)
    end
    footerHint:SetText(footerHintText)
    if footerHintText == "" then
        footerHint:Hide()
    else
        footerHint:Show()
    end

    local scroll = CreateFrame("ScrollFrame", nil, picker, "UIPanelScrollFrameTemplate")
    local scrollTopOffset = -72
    if noSearch and hideTitle then
        scrollTopOffset = -14
    elseif noSearch then
        scrollTopOffset = -34
    end
    local scrollChildRightInset = hideScrollBar and 4 or 20
    local scrollRightInset = hideScrollBar and 14 or 34
    scroll:SetPoint("TOPLEFT", picker, "TOPLEFT", 14, scrollTopOffset)
    scroll:SetPoint("BOTTOMRIGHT", picker, "BOTTOMRIGHT", -scrollRightInset, 48)
    scroll:EnableMouseWheel(true)
    if hideScrollBar and scroll.ScrollBar then
        scroll.ScrollBar:Hide()
        scroll.ScrollBar:SetAlpha(0)
        scroll.ScrollBar:EnableMouse(false)
        scroll.ScrollBar:SetScript("OnShow", function(selfBar)
            selfBar:Hide()
        end)
    end

    local scrollChild = CreateFrame("Frame", nil, scroll)
    scrollChild:SetSize(1, 1)
    scroll:SetScrollChild(scrollChild)
    scroll:SetScript("OnSizeChanged", function(selfScroll, width)
        local childWidth = math.max(1, math.floor((width or 1) - scrollChildRightInset))
        scrollChild:SetWidth(childWidth)
        if picker and picker.RenderRows then
            picker:RenderRows()
        end
    end)
    scrollChild:SetWidth(math.max(1, math.floor((scroll:GetWidth() or 1) - scrollChildRightInset)))

    local clearButton = createActionButton(picker, tostring(uiConfig.clearButtonText or "Clear"), nil, 80)
    clearButton:SetPoint("BOTTOMLEFT", picker, "BOTTOMLEFT", 14, 14)
    clearButton:EnableMouseWheel(true)
    local closeButton = createActionButton(picker, tostring(uiConfig.closeButtonText or "Close"), nil, 80)
    closeButton:SetPoint("BOTTOMRIGHT", picker, "BOTTOMRIGHT", -14, 14)
    closeButton:EnableMouseWheel(true)

    if not showClearButton then
        clearButton:Hide()
    end
    if not showCloseButton then
        closeButton:Hide()
    end

    local function applyPickerFooterButtonStyle(btn)
        if not btn then
            return
        end
        if not btn._paPickerFooterStyled then
            btn._paPickerFooterStyled = true
            btn._paBg = btn:CreateTexture(nil, "ARTWORK")
            btn._paBg:SetAllPoints(btn)
            btn._paBg:SetTexture("Interface\\Buttons\\WHITE8x8")
            btn._paBg:SetVertexColor(0.11, 0.12, 0.15, 0.95)
            btn._paHovered = false
            btn._paPressed = false

            if btn.Text then
                applyGlobalFontToObject(btn.Text, 11)
                btn.Text:SetTextColor(0.92, 0.92, 0.92, 1)
            end
        end

        local function hideTemplateChrome()
            local n = btn.GetNormalTexture and btn:GetNormalTexture() or nil
            local p = btn.GetPushedTexture and btn:GetPushedTexture() or nil
            local h = btn.GetHighlightTexture and btn:GetHighlightTexture() or nil
            local d = btn.GetDisabledTexture and btn:GetDisabledTexture() or nil
            if n then n:SetAlpha(0); if n.Hide then n:Hide() end end
            if p then p:SetAlpha(0); if p.Hide then p:Hide() end end
            if h then h:SetAlpha(0); if h.Hide then h:Hide() end end
            if d then d:SetAlpha(0); if d.Hide then d:Hide() end end

            local skinParts = {
                "Left", "Middle", "Right",
                "LeftDisabled", "MiddleDisabled", "RightDisabled",
                "LeftHighlight", "MiddleHighlight", "RightHighlight",
                "LeftPressed", "MiddlePressed", "RightPressed",
            }
            for _, part in ipairs(skinParts) do
                local tex = btn[part]
                if tex and tex.SetAlpha then tex:SetAlpha(0) end
                if tex and tex.Hide then tex:Hide() end
            end
        end

        local function refreshVisual()
            hideTemplateChrome()
            if not btn:IsEnabled() then
                btn._paBg:SetVertexColor(0.08, 0.09, 0.11, 0.7)
                if btn.Text then
                    btn.Text:SetTextColor(0.55, 0.55, 0.58, 1)
                end
                return
            end

            if btn._paPressed then
                btn._paBg:SetVertexColor(0.08, 0.09, 0.12, 0.98)
                if btn.Text then
                    btn.Text:SetTextColor(1, 0.85, 0.18, 1)
                end
            elseif btn._paHovered then
                btn._paBg:SetVertexColor(0.14, 0.15, 0.19, 0.98)
                if btn.Text then
                    btn.Text:SetTextColor(1, 0.9, 0.35, 1)
                end
            else
                btn._paBg:SetVertexColor(0.11, 0.12, 0.15, 0.95)
                if btn.Text then
                    btn.Text:SetTextColor(0.92, 0.92, 0.92, 1)
                end
            end
        end

        btn:HookScript("OnEnter", function(selfBtn)
            selfBtn._paHovered = true
            refreshVisual()
        end)
        btn:HookScript("OnLeave", function(selfBtn)
            selfBtn._paHovered = false
            selfBtn._paPressed = false
            refreshVisual()
        end)
        btn:HookScript("OnMouseDown", function(selfBtn)
            selfBtn._paPressed = true
            refreshVisual()
        end)
        btn:HookScript("OnMouseUp", function(selfBtn)
            selfBtn._paPressed = false
            refreshVisual()
        end)
        btn:HookScript("OnShow", function()
            refreshVisual()
        end)
        refreshVisual()
    end

    applyPickerFooterButtonStyle(clearButton)
    applyPickerFooterButtonStyle(closeButton)

    picker.search = search
    picker.scroll = scroll
    picker.scrollChild = scrollChild
    picker.title = title
    picker.searchHint = searchHint
    picker.footerHint = footerHint
    picker.clearButton = clearButton
    picker.closeButton = closeButton
    picker._onSelect = onSelectCallback
    picker._allOptions = {}
    picker._filteredOptions = {}
    picker._rows = {}
    picker._selectedValue = nil
    picker._highlightedIndex = 0
    picker._query = ""
    picker._showSecondary = uiConfig.showSecondary ~= false
    picker._useOptionFontPreview = uiConfig.useOptionFontPreview and true or false
    picker._useOptionTexturePreview = uiConfig.useOptionTexturePreview and true or false
    picker._previewFontSize = math.max(8, math.floor(tonumber(uiConfig.previewFontSize) or 12))
    picker._rowHeight = math.max(20, math.floor(tonumber(uiConfig.rowHeight) or (picker._showSecondary and 34 or 26)))
    picker._minHeight = minPickerHeight
    picker._filterToken = 0
    picker._noSearch = noSearch
    picker._onOptionRightClick = onOptionRightClick
    picker._footerPulseActive = false
    picker._footerPulseElapsed = 0
    picker._footerPulseCycles = 2
    picker._footerPulseCycleDuration = 0.65
    picker._footerPulseMinAlpha = 0.78
    picker._footerPulseMaxAlpha = 1.00
    picker._footerHintIdleAlpha = 0.95
    picker._previewFlashDuration = 0.24
    picker._hasPreviewFlash = false
    picker._transientTickerActive = false
    picker._anchorFrame = nil
    picker._anchorHideHookFrames = {}
    picker._showClearButton = showClearButton
    picker._showCloseButton = showCloseButton
    picker._footerFlowWithRows = footerFlowWithRows
    picker._scrollTopOffset = scrollTopOffset
    picker._scrollRightInset = scrollRightInset
    picker._scrollChildRightInset = scrollChildRightInset
    picker._ellipsizeRows = uiConfig.ellipsizeRows and true or false

    if hideTitle then
        title:SetText("")
        title:Hide()
    else
        title:Show()
    end
    if noSearch then
        search:SetText("")
        search:ClearFocus()
        search:Hide()
        searchHint:Hide()
    else
        search:Show()
        searchHint:Show()
    end

    function picker:LayoutChrome(contentHeight)
        local footerVisible = footerHint and footerHint:IsShown()
        local topOffset = self._scrollTopOffset or -72
        local rightInset = self._scrollRightInset or 34
        local footerGap = 8
        local bottomPad = 14
        local footerHeight = footerVisible and math.max(10, footerHint:GetStringHeight() or 0) or 0
        local hasFooterButtons = self._showClearButton or self._showCloseButton

        scroll:ClearAllPoints()
        scroll:SetPoint("TOPLEFT", picker, "TOPLEFT", 14, topOffset)
        scroll:SetPoint("TOPRIGHT", picker, "TOPRIGHT", -rightInset, topOffset)

        if footerVisible then
            footerHint:ClearAllPoints()
        end

        if footerVisible and self._footerFlowWithRows and not hasFooterButtons then
            local pickerHeight = picker:GetHeight() or minPickerHeight
            local topInset = math.abs(topOffset)
            local maxListHeight = math.max(self._rowHeight, pickerHeight - topInset - bottomPad - footerGap - footerHeight)
            local usedListHeight = math.max(self._rowHeight, math.min(contentHeight or maxListHeight, maxListHeight))
            scroll:SetHeight(usedListHeight)
            footerHint:SetPoint("TOPLEFT", picker, "TOPLEFT", 14, topOffset - usedListHeight - footerGap)
            footerHint:SetPoint("TOPRIGHT", picker, "TOPRIGHT", -14, topOffset - usedListHeight - footerGap)
        else
            local bottomOffset = 14
            if hasFooterButtons then
                bottomOffset = 48
            elseif footerVisible then
                bottomOffset = 32
            end
            scroll:SetPoint("BOTTOMRIGHT", picker, "BOTTOMRIGHT", -rightInset, bottomOffset)
            if footerVisible then
                local footerBottom = hasFooterButtons and 39 or 14
                footerHint:SetPoint("BOTTOMLEFT", picker, "BOTTOMLEFT", 14, footerBottom)
                footerHint:SetPoint("BOTTOMRIGHT", picker, "BOTTOMRIGHT", -14, footerBottom)
            end
        end
    end

    local function clearTable(t)
        for k in pairs(t) do
            t[k] = nil
        end
    end

    local function lowerString(text)
        return string.lower(tostring(text or ""))
    end

    local function trimString(text)
        if type(text) ~= "string" then
            return ""
        end
        local cleaned = text:gsub("^%s+", ""):gsub("%s+$", "")
        return cleaned
    end

    local function minScore(current, nextScore)
        if nextScore == nil then
            return current
        end
        if current == nil or nextScore < current then
            return nextScore
        end
        return current
    end

    local function textMatchScore(haystack, needle, prefixScore, substringScore)
        if haystack == nil or haystack == "" or needle == nil or needle == "" then
            return nil
        end
        if haystack:sub(1, #needle) == needle then
            return prefixScore
        end
        if haystack:find(needle, 1, true) then
            return substringScore
        end
        return nil
    end

    local function highlightMatch(text, query)
        text = tostring(text or "")
        query = tostring(query or "")
        if query == "" then
            return text
        end
        local lowerText = lowerString(text)
        local startPos = lowerText:find(query, 1, true)
        if not startPos then
            return text
        end
        local endPos = startPos + #query - 1
        return string.format("%s|cffffd100%s|r%s", text:sub(1, startPos - 1), text:sub(startPos, endPos), text:sub(endPos + 1))
    end

    local function scoreOption(option, query)
        if query == "" then
            return 0
        end
        local best = nil
        best = minScore(best, textMatchScore(option._labelLower, query, 0, 20))
        best = minScore(best, textMatchScore(option._secondaryLower, query, 30, 45))
        for _, alias in ipairs(option._aliasesLower) do
            best = minScore(best, textMatchScore(alias, query, 10, 25))
        end
        return best
    end

    picker.rowPool = CreateFramePool("Button", scrollChild, nil, function(_, row)
        row:Hide()
        row:ClearAllPoints()
        row._index = nil
        row._option = nil
        row._hovered = false
        row._isNoMatch = false
        row._disabled = false
        row._previewFlashUntil = nil
        row:EnableMouse(true)
        row:SetAlpha(1)
        if row.primary then
            row.primary:SetText("")
            row.primary:SetTextColor(1, 1, 1, 1)
            applyGlobalFontToObject(row.primary, picker._previewFontSize)
        end
        if row.secondary then
            row.secondary:SetText("")
            row.secondary:SetTextColor(0.72, 0.72, 0.72, 1)
            if picker._showSecondary then
                row.secondary:Show()
            else
                row.secondary:Hide()
            end
        end
        if row.previewFrame then
            row.previewFrame:Hide()
        end
        if row.bg then
            row.bg:SetVertexColor(1, 1, 1, 0)
        end
    end)

    local function updateRowVisual(row)
        if not row or not row.bg then
            return
        end
        local now = (GetTime and GetTime()) or 0
        if row._previewFlashUntil and now < row._previewFlashUntil then
            local flashDuration = picker._previewFlashDuration or 0.24
            local remaining = math.max(0, row._previewFlashUntil - now)
            local t = (flashDuration > 0) and (remaining / flashDuration) or 0
            local alpha = 0.10 + (0.18 * t)
            row.bg:SetVertexColor(1.00, 0.82, 0.20, alpha)
            return
        elseif row._previewFlashUntil then
            row._previewFlashUntil = nil
        end
        if row._isNoMatch then
            row.bg:SetVertexColor(1, 1, 1, 0)
            return
        end
        if row._disabled then
            if row._hovered then
                row.bg:SetVertexColor(1, 1, 1, 0.06)
            else
                row.bg:SetVertexColor(1, 1, 1, 0)
            end
            return
        end
        local isSelected = row._index == picker._highlightedIndex
        if isSelected then
            row.bg:SetVertexColor(0.18, 0.55, 1, 0.25)
        elseif row._hovered then
            row.bg:SetVertexColor(1, 1, 1, 0.12)
        else
            row.bg:SetVertexColor(1, 1, 1, 0)
        end
    end

    local function refreshAllRowVisuals()
        for _, row in pairs(picker._rows) do
            updateRowVisual(row)
        end
    end

    local function setFooterHintAlpha(alpha)
        if not footerHint or not footerHint:IsShown() then
            return
        end
        footerHint:SetTextColor(0.72, 0.72, 0.72, alpha or 0.92)
    end

    local function stopFooterPulse()
        picker._footerPulseActive = false
        picker._footerPulseElapsed = 0
        setFooterHintAlpha(picker._footerHintIdleAlpha or 0.95)
    end

    local function ensureTransientTicker()
        if picker._transientTickerActive then
            return
        end
        picker._transientTickerActive = true
        picker:SetScript("OnUpdate", function(selfPicker, elapsed)
            local keepTicking = false

            if selfPicker._footerPulseActive then
                local cycleDuration = selfPicker._footerPulseCycleDuration or 0.65
                local totalCycles = selfPicker._footerPulseCycles or 2
                local totalDuration = math.max(0.01, cycleDuration * totalCycles)
                selfPicker._footerPulseElapsed = (selfPicker._footerPulseElapsed or 0) + (elapsed or 0)
                if selfPicker._footerPulseElapsed >= totalDuration then
                    stopFooterPulse()
                else
                    local inCycle = (selfPicker._footerPulseElapsed % cycleDuration) / cycleDuration
                    local wave = 0.5 - (0.5 * math.cos(inCycle * (math.pi * 2)))
                    local minAlpha = selfPicker._footerPulseMinAlpha or 0.78
                    local maxAlpha = selfPicker._footerPulseMaxAlpha or 1.00
                    local alpha = minAlpha + ((maxAlpha - minAlpha) * wave)
                    setFooterHintAlpha(alpha)
                    keepTicking = true
                end
            end

            if selfPicker._hasPreviewFlash then
                local now = (GetTime and GetTime()) or 0
                local anyFlashActive = false
                for _, row in pairs(selfPicker._rows) do
                    if row and row._previewFlashUntil and now < row._previewFlashUntil then
                        anyFlashActive = true
                        break
                    end
                end
                refreshAllRowVisuals()
                if anyFlashActive then
                    keepTicking = true
                else
                    selfPicker._hasPreviewFlash = false
                end
            end

            if not keepTicking then
                selfPicker._transientTickerActive = false
                selfPicker:SetScript("OnUpdate", nil)
            end
        end)
    end

    local function ensureAnchorHideHook(anchorFrame)
        if not anchorFrame or not anchorFrame.HookScript then
            return
        end
        if picker._anchorHideHookFrames[anchorFrame] then
            return
        end
        picker._anchorHideHookFrames[anchorFrame] = true
        anchorFrame:HookScript("OnHide", function(hiddenAnchor)
            if picker._anchorFrame ~= hiddenAnchor then
                return
            end
            if picker and picker.IsShown and picker:IsShown() and picker.Close then
                picker:Close()
            end
        end)
    end

    local PICKER_TEXTURE_PREVIEW_WIDTH = 92
    local PICKER_TEXTURE_PREVIEW_HEIGHT = 12

    local function layoutPickerRowContent(row, hasTexturePreview)
        if not row or not row.primary or not row.secondary then
            return
        end

        row.primary:ClearAllPoints()
        row.secondary:ClearAllPoints()

        if hasTexturePreview and row.previewFrame then
            row.previewFrame:ClearAllPoints()
            row.previewFrame:SetPoint("RIGHT", row, "RIGHT", -8, 0)
            row.previewFrame:SetSize(PICKER_TEXTURE_PREVIEW_WIDTH, PICKER_TEXTURE_PREVIEW_HEIGHT)
            row.previewFrame:Show()
            row.primary:SetPoint("TOPLEFT", row, "TOPLEFT", 8, picker._showSecondary and -4 or -5)
            row.primary:SetPoint("TOPRIGHT", row.previewFrame, "TOPLEFT", -8, picker._showSecondary and -4 or -5)
        else
            if row.previewFrame then
                row.previewFrame:Hide()
            end
            row.primary:SetPoint("TOPLEFT", row, "TOPLEFT", 8, picker._showSecondary and -4 or -5)
            row.primary:SetPoint("TOPRIGHT", row, "TOPRIGHT", -8, picker._showSecondary and -4 or -5)
        end

        row.secondary:SetPoint("TOPLEFT", row.primary, "BOTTOMLEFT", 0, -2)
        if hasTexturePreview and row.previewFrame then
            row.secondary:SetPoint("TOPRIGHT", row.previewFrame, "TOPLEFT", -8, -2)
        else
            row.secondary:SetPoint("TOPRIGHT", row, "TOPRIGHT", -8, -2)
        end
    end

    local function ensureRowWidgets(row)
        if row._paBuilt then
            return
        end
        row._paBuilt = true
        row:SetHeight(picker._rowHeight)

        row.bg = row:CreateTexture(nil, "BACKGROUND")
        row.bg:SetAllPoints()
        row.bg:SetTexture("Interface\\Buttons\\WHITE8x8")
        row.bg:SetVertexColor(1, 1, 1, 0)

        row.primary = createStyledFontString(row, "ARTWORK", "GameFontHighlight", 12)
        row.primary:SetPoint("TOPLEFT", row, "TOPLEFT", 8, picker._showSecondary and -4 or -5)
        row.primary:SetPoint("TOPRIGHT", row, "TOPRIGHT", -8, picker._showSecondary and -4 or -5)
        row.primary:SetJustifyH("LEFT")
        row.primary:SetMaxLines(1)

        row.secondary = createStyledFontString(row, "ARTWORK", "GameFontHighlightSmall", 10)
        row.secondary:SetPoint("TOPLEFT", row.primary, "BOTTOMLEFT", 0, -2)
        row.secondary:SetPoint("TOPRIGHT", row, "TOPRIGHT", -8, -2)
        row.secondary:SetJustifyH("LEFT")
        row.secondary:SetTextColor(0.72, 0.72, 0.72, 1)
        row.secondary:SetMaxLines(1)
        if not picker._showSecondary then
            row.secondary:Hide()
        end

        row.previewFrame = CreateFrame("Frame", nil, row, "BackdropTemplate")
        row.previewFrame:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
            insets = { left = 0, right = 0, top = 0, bottom = 0 },
        })
        row.previewFrame:EnableMouse(false)
        row.previewFrame:SetBackdropColor(0.09, 0.10, 0.12, 0.98)
        row.previewFrame:SetBackdropBorderColor(0.25, 0.28, 0.33, 0.92)
        row.previewFrame:Hide()

        row.previewBar = CreateFrame("StatusBar", nil, row.previewFrame)
        row.previewBar:EnableMouse(false)
        row.previewBar:SetPoint("TOPLEFT", row.previewFrame, "TOPLEFT", 1, -1)
        row.previewBar:SetPoint("BOTTOMRIGHT", row.previewFrame, "BOTTOMRIGHT", -1, 1)
        row.previewBar:SetMinMaxValues(0, 1)
        row.previewBar:SetValue(0.72)
        row.previewBar:SetStatusBarColor(1.00, 0.82, 0.20, 0.95)
        if row.previewBar.SetReverseFill then
            row.previewBar:SetReverseFill(false)
        end

        row.previewBarBg = row.previewBar:CreateTexture(nil, "BACKGROUND")
        row.previewBarBg:SetAllPoints(row.previewBar)
        row.previewBarBg:SetTexture("Interface\\Buttons\\WHITE8x8")
        row.previewBarBg:SetVertexColor(0.16, 0.18, 0.22, 0.92)

        layoutPickerRowContent(row, false)

        row:SetScript("OnEnter", function(selfRow)
            selfRow._hovered = true
            if not selfRow._isNoMatch and not selfRow._disabled then
                picker._highlightedIndex = selfRow._index or picker._highlightedIndex
            end
            refreshAllRowVisuals()
        end)
        row:SetScript("OnLeave", function(selfRow)
            selfRow._hovered = false
            refreshAllRowVisuals()
        end)
        row:RegisterForClicks("LeftButtonUp", "RightButtonUp")
        row:SetScript("OnClick", function(selfRow, mouseButton)
            if selfRow._isNoMatch then
                return
            end
            local option = selfRow._option
            if not option or option.disabled then
                return
            end
            if mouseButton == "RightButton" and picker._onOptionRightClick then
                if picker._onOptionRightClick then
                    picker._onOptionRightClick(option.value, option, selfRow)
                end
                local now = (GetTime and GetTime()) or 0
                selfRow._previewFlashUntil = now + (picker._previewFlashDuration or 0.24)
                picker._hasPreviewFlash = true
                refreshAllRowVisuals()
                ensureTransientTicker()
                return
            end
            if picker._onSelect and option then
                picker._onSelect(option.value, option, false)
            end
            picker:Close()
        end)
    end

    function picker:SetOnSelect(callback)
        self._onSelect = callback
    end

    function picker:SetSelectedValue(value)
        if value == nil then
            self._selectedValue = nil
            self._selectedValueKey = nil
        else
            self._selectedValue = value
            self._selectedValueKey = tostring(value)
        end
    end

    function picker:RenderRows()
        self.rowPool:ReleaseAll()
        clearTable(self._rows)

        local rowHeight = self._rowHeight
        local y = 0
        local query = self._query

        if #self._filteredOptions == 0 then
            local row = self.rowPool:Acquire()
            ensureRowWidgets(row)
            row:SetPoint("TOPLEFT", self.scrollChild, "TOPLEFT", 0, -y)
            row:SetPoint("TOPRIGHT", self.scrollChild, "TOPRIGHT", 0, -y)
            row:SetHeight(rowHeight)
            row._isNoMatch = true
            row._disabled = false
            row._index = 0
            row.primary:SetText("|cff9a9a9aNo matches|r")
            row.secondary:SetText("")
            layoutPickerRowContent(row, false)
            row:EnableMouse(false)
            row:Show()
            self._rows[1] = row
            y = y + rowHeight
        else
            for index, option in ipairs(self._filteredOptions) do
                local row = self.rowPool:Acquire()
                ensureRowWidgets(row)
                row:SetPoint("TOPLEFT", self.scrollChild, "TOPLEFT", 0, -y)
                row:SetPoint("TOPRIGHT", self.scrollChild, "TOPRIGHT", 0, -y)
                row:SetHeight(rowHeight)
                row._isNoMatch = false
                row._disabled = option.disabled and true or false
                row._index = index
                row._option = option
                if picker._showSecondary then
                    row.secondary:SetText(option.secondary or "")
                    row.secondary:Show()
                else
                    row.secondary:SetText("")
                    row.secondary:Hide()
                end
                if picker._useOptionFontPreview then
                    local previewPath = type(option.previewFontPath) == "string" and option.previewFontPath or ""
                    local applied = false
                    if row.primary.SetFont then
                        applied = row.primary:SetFont(previewPath, picker._previewFontSize, "")
                    end
                    if not applied then
                        applyGlobalFontToObject(row.primary, picker._previewFontSize)
                    end
                else
                    applyGlobalFontToObject(row.primary, 12)
                end
                local hasTexturePreview = picker._useOptionTexturePreview
                    and type(option.previewTexturePath) == "string"
                    and option.previewTexturePath ~= ""
                layoutPickerRowContent(row, hasTexturePreview)
                if picker._ellipsizeRows and query == "" and type(setSingleLineEllipsis) == "function" then
                    local previewInset = hasTexturePreview and (PICKER_TEXTURE_PREVIEW_WIDTH + 8) or 0
                    local primaryWidth = math.max(20, (self.scrollChild:GetWidth() or 0) - 16 - previewInset)
                    row.primary:SetWidth(primaryWidth)
                    setSingleLineEllipsis(row.primary, option.label or "", primaryWidth)
                else
                    row.primary:SetText(highlightMatch(option.label, query))
                end
                if hasTexturePreview and row.previewBar and row.previewBarBg then
                    row.previewBar:SetStatusBarTexture(option.previewTexturePath)
                    row.previewBarBg:SetTexture(option.previewTexturePath)
                    row.previewBar:SetMinMaxValues(0, 1)
                    row.previewBar:SetValue(0.72)
                    row.previewBar:SetStatusBarColor(1.00, 0.82, 0.20, 0.95)
                    row.previewBarBg:SetVertexColor(0.16, 0.18, 0.22, 0.92)
                    if row.previewBar.SetReverseFill then
                        row.previewBar:SetReverseFill(false)
                    end
                end
                row:EnableMouse(true)
                if row._disabled then
                    row:SetAlpha(0.72)
                    row.primary:SetTextColor(0.6, 0.6, 0.6, 1)
                    if picker._showSecondary then
                        row.secondary:SetTextColor(0.5, 0.5, 0.5, 1)
                    end
                else
                    row:SetAlpha(1)
                    row.primary:SetTextColor(1, 1, 1, 1)
                    if picker._showSecondary then
                        row.secondary:SetTextColor(0.72, 0.72, 0.72, 1)
                    end
                end
                row:Show()
                self._rows[index] = row
                y = y + rowHeight
            end
        end

        self:LayoutChrome(y)
        self.scrollChild:SetHeight(math.max(self.scroll:GetHeight(), y))

        refreshAllRowVisuals()
    end

    function picker:EnsureVisible(index)
        local count = #self._filteredOptions
        if count == 0 or index < 1 or index > count then
            return
        end
        local rowHeight = self._rowHeight
        local top = (index - 1) * rowHeight
        local bottom = top + rowHeight
        local current = self.scroll:GetVerticalScroll()
        local viewport = self.scroll:GetHeight()
        if top < current then
            self.scroll:SetVerticalScroll(top)
        elseif bottom > current + viewport then
            self.scroll:SetVerticalScroll(bottom - viewport)
        end
    end

    function picker:MoveHighlight(delta)
        local count = #self._filteredOptions
        if count == 0 then
            return
        end
        local index = self._highlightedIndex
        if index < 1 then
            index = (delta > 0) and 0 or (count + 1)
        end

        local newIndex = index
        while true do
            newIndex = newIndex + delta
            if newIndex < 1 or newIndex > count then
                break
            end
            local option = self._filteredOptions[newIndex]
            if option and not option.disabled then
                self._highlightedIndex = newIndex
                self:EnsureVisible(newIndex)
                break
            end
        end
        refreshAllRowVisuals()
    end

    function picker:SelectHighlighted()
        local count = #self._filteredOptions
        if count == 0 then
            return
        end
        local index = self._highlightedIndex
        if index < 1 or index > count then
            index = 1
        end
        local option = self._filteredOptions[index]
        if option and option.disabled then
            option = nil
            for i = 1, count do
                local candidate = self._filteredOptions[i]
                if candidate and not candidate.disabled then
                    option = candidate
                    index = i
                    break
                end
            end
        end
        if option and self._onSelect then
            self._highlightedIndex = index
            self._onSelect(option.value, option, false)
            self:Close()
        end
    end

    function picker:ApplyFilter(opts)
        opts = type(opts) == "table" and opts or {}
        local query = lowerString(trimString(self.search:GetText() or ""))
        self._query = query
        local preserveScroll = opts.preserveScroll and true or false
        local previousScroll = preserveScroll and (tonumber(self.scroll:GetVerticalScroll()) or 0) or nil
        local previousHighlightedValueKey = nil
        if preserveScroll and self._highlightedIndex and self._highlightedIndex > 0 then
            local previousOption = self._filteredOptions and self._filteredOptions[self._highlightedIndex] or nil
            previousHighlightedValueKey = previousOption and previousOption._valueKey or nil
        end

        local filtered = {}
        for _, option in ipairs(self._allOptions) do
            local score = scoreOption(option, query)
            if query == "" or score ~= nil then
                option._score = score or 0
                table.insert(filtered, option)
            end
        end

        if query == "" then
            if preserveOrder then
                table.sort(filtered, function(a, b)
                    return a._order < b._order
                end)
            else
                table.sort(filtered, function(a, b)
                    local av = tonumber(a.value)
                    local bv = tonumber(b.value)
                    if av and bv and av ~= bv then
                        return av < bv
                    end
                    if av and not bv then return true end
                    if bv and not av then return false end
                    if a._labelLower ~= b._labelLower then
                        return a._labelLower < b._labelLower
                    end
                    return a._order < b._order
                end)
            end
        else
            table.sort(filtered, function(a, b)
                if a._score ~= b._score then
                    return a._score < b._score
                end
                if a._labelLower ~= b._labelLower then
                    return a._labelLower < b._labelLower
                end
                return a._order < b._order
            end)
        end

        self._filteredOptions = filtered
        self._highlightedIndex = 0
        if #filtered > 0 then
            if previousHighlightedValueKey ~= nil then
                for index, option in ipairs(filtered) do
                    if option._valueKey == previousHighlightedValueKey and not option.disabled then
                        self._highlightedIndex = index
                        break
                    end
                end
            end
            if self._selectedValueKey ~= nil then
                if self._highlightedIndex == 0 then
                    for index, option in ipairs(filtered) do
                        if option._valueKey == self._selectedValueKey and not option.disabled then
                            self._highlightedIndex = index
                            break
                        end
                    end
                end
            end
            if self._highlightedIndex == 0 then
                for index, option in ipairs(filtered) do
                    if not option.disabled then
                        self._highlightedIndex = index
                        break
                    end
                end
            end
        end

        self:RenderRows()
        if preserveScroll then
            local maxScroll = math.max(0, (self.scrollChild:GetHeight() or 0) - (self.scroll:GetHeight() or 0))
            local clamped = math.max(0, math.min(previousScroll or 0, maxScroll))
            self.scroll:SetVerticalScroll(clamped)
        else
            self:EnsureVisible(self._highlightedIndex)
        end
    end

    function picker:QueueFilter()
        self._filterToken = self._filterToken + 1
        local token = self._filterToken
        if C_Timer and C_Timer.After then
            C_Timer.After(0.08, function()
                if not picker or not picker:IsShown() then
                    return
                end
                if picker._filterToken ~= token then
                    return
                end
                picker:ApplyFilter()
            end)
        else
            self:ApplyFilter()
        end
    end

    function picker:SetOptions(newOptions)
        local source = type(newOptions) == "table" and newOptions or {}
        local normalizedOptions = {}
        for index, option in ipairs(source) do
            local aliases = {}
            if type(option.aliases) == "table" then
                for _, alias in ipairs(option.aliases) do
                    if trimString(alias) ~= "" then
                        table.insert(aliases, trimString(alias))
                    end
                end
            end
            local normalized = {
                value = option.value,
                label = trimString(option.label or ""),
                secondary = trimString(option.secondary or ""),
                buttonLabel = trimString(option.buttonLabel or option.label or ""),
                previewFontPath = trimString(option.previewFontPath or ""),
                previewTexturePath = trimString(option.previewTexturePath or option.path or ""),
                aliases = aliases,
                disabled = option.disabled and true or false,
                _order = index,
                _valueKey = tostring(option.value or ""),
            }
            normalized._labelLower = lowerString(normalized.label)
            normalized._secondaryLower = lowerString(normalized.secondary)
            normalized._aliasesLower = {}
            for _, alias in ipairs(normalized.aliases) do
                table.insert(normalized._aliasesLower, lowerString(alias))
            end
            table.insert(normalizedOptions, normalized)
        end

        local unchanged = (#self._allOptions == #normalizedOptions)
        if unchanged then
            for index = 1, #normalizedOptions do
                local previous = self._allOptions[index]
                local current = normalizedOptions[index]
                if not previous or not current
                    or previous._valueKey ~= current._valueKey
                    or previous.label ~= current.label
                    or previous.secondary ~= current.secondary
                    or previous.buttonLabel ~= current.buttonLabel
                    or previous.previewFontPath ~= current.previewFontPath
                    or previous.previewTexturePath ~= current.previewTexturePath
                    or previous.disabled ~= current.disabled
                    or #previous.aliases ~= #current.aliases then
                    unchanged = false
                    break
                end
                for aliasIndex = 1, #current.aliases do
                    if previous.aliases[aliasIndex] ~= current.aliases[aliasIndex] then
                        unchanged = false
                        break
                    end
                end
                if not unchanged then
                    break
                end
            end
        end

        if unchanged then
            return
        end

        clearTable(self._allOptions)
        for index, option in ipairs(normalizedOptions) do
            self._allOptions[index] = option
        end
        if self:IsShown() then
            self:ApplyFilter({ preserveScroll = true })
        end
    end

    function picker:Open(anchorFrame)
        if InCombatLockdown and InCombatLockdown() then
            self._pendingOpenAnchor = anchorFrame
            if not self._combatWaitFrame then
                self._combatWaitFrame = CreateFrame("Frame")
                self._combatWaitFrame:SetScript("OnEvent", function()
                    self._combatWaitFrame:UnregisterEvent("PLAYER_REGEN_ENABLED")
                    local pending = self._pendingOpenAnchor
                    self._pendingOpenAnchor = nil
                    self:Open(pending)
                end)
            end
            self._combatWaitFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
            return
        end

        -- Premium popover rule: never allow overlapping pickers.
        if ACTIVE_PORTAL_PICKER and ACTIVE_PORTAL_PICKER ~= self and ACTIVE_PORTAL_PICKER.Close then
            ACTIVE_PORTAL_PICKER:Close()
        end

        self._anchorFrame = anchorFrame
        ensureAnchorHideHook(anchorFrame)
        self:ClearAllPoints()
        if anchorFrame and anchorFrame.GetCenter and anchorFrame:GetCenter() then
            self:SetPoint("TOPLEFT", anchorFrame, "BOTTOMLEFT", 0, -4)
        else
            self:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
        end

        self:Show()
        ACTIVE_PORTAL_PICKER = self
        self:LayoutChrome()
        self.search:SetText("")
        if not self._noSearch then
            self.search:SetFocus()
            self.search:SetCursorPosition(0)
        else
            self.search:ClearFocus()
        end
        stopFooterPulse()
        self:ApplyFilter()
    end

    function picker:Close()
        if self._combatWaitFrame then
            self._combatWaitFrame:UnregisterEvent("PLAYER_REGEN_ENABLED")
        end
        self._pendingOpenAnchor = nil
        self._anchorFrame = nil
        if ACTIVE_PORTAL_PICKER == self then
            ACTIVE_PORTAL_PICKER = nil
        end
        stopFooterPulse()
        self._hasPreviewFlash = false
        for _, row in pairs(self._rows) do
            if row then
                row._previewFlashUntil = nil
            end
        end
        if self._transientTickerActive then
            self._transientTickerActive = false
            self:SetScript("OnUpdate", nil)
        end
        self.search:ClearFocus()
        self:Hide()
    end

    picker:SetScript("OnMouseWheel", function() end)
    search:SetScript("OnMouseWheel", function() end)
    clearButton:SetScript("OnMouseWheel", function() end)
    closeButton:SetScript("OnMouseWheel", function() end)

    search:SetScript("OnTextChanged", function(_, userInput)
        if userInput then
            picker:QueueFilter()
        end
    end)
    search:SetScript("OnEnterPressed", function()
        picker:SelectHighlighted()
    end)
    search:SetScript("OnEscapePressed", function()
        picker:Close()
    end)
    search:SetScript("OnKeyDown", function(_, key)
        if key == "UP" then
            picker:MoveHighlight(-1)
        elseif key == "DOWN" then
            picker:MoveHighlight(1)
        elseif key == "ENTER" or key == "NUMPADENTER" then
            picker:SelectHighlighted()
        elseif key == "ESCAPE" then
            picker:Close()
        end
    end)
    if search.SetPropagateKeyboardInput then
        search:SetPropagateKeyboardInput(false)
    end

    scroll:SetScript("OnMouseWheel", function(selfScroll, delta)
        local current = selfScroll:GetVerticalScroll()
        local nextValue = current - (delta * 24)
        if nextValue < 0 then nextValue = 0 end
        local maxScroll = math.max(0, (picker.scrollChild:GetHeight() or 0) - (selfScroll:GetHeight() or 0))
        if nextValue > maxScroll then nextValue = maxScroll end
        selfScroll:SetVerticalScroll(nextValue)
    end)

    clearButton:SetScript("OnClick", function()
        if picker._onSelect then
            picker._onSelect(nil, nil, true)
        end
        picker:Close()
    end)
    closeButton:SetScript("OnClick", function()
        picker:Close()
    end)

    picker:SetOptions(options or {})
    return picker
end

local function createTextPlacement(parent, onApply)
    local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
    local dropdown = CreateFrame("Frame", nil, parent, "UIDropDownMenuTemplate")
    ensureSettingsWindowDropdownChrome(dropdown)

    local function normalizePlacement()
        if PortalAuthorityDB.dockOrientation == "HORIZONTAL" then
            PortalAuthorityDB.dockUseShortNames = true
            if PortalAuthorityDB.dockHorizontalTextPosition ~= "ABOVE" and PortalAuthorityDB.dockHorizontalTextPosition ~= "BELOW" then
                PortalAuthorityDB.dockHorizontalTextPosition = "ABOVE"
            end
        else
            if PortalAuthorityDB.dockVerticalTextSide ~= "LEFT" and PortalAuthorityDB.dockVerticalTextSide ~= "RIGHT" then
                PortalAuthorityDB.dockVerticalTextSide = "LEFT"
            end
        end
    end

    local function getValues()
        if PortalAuthorityDB.dockOrientation == "HORIZONTAL" then
            return { { label = "Above", value = "ABOVE" }, { label = "Below", value = "BELOW" } }
        end
        return { { label = "Left", value = "LEFT" }, { label = "Right", value = "RIGHT" } }
    end

    UIDropDownMenu_Initialize(dropdown, function(_, level)
        normalizePlacement()
        local active = (PortalAuthorityDB.dockOrientation == "HORIZONTAL") and PortalAuthorityDB.dockHorizontalTextPosition or PortalAuthorityDB.dockVerticalTextSide
        for _, option in ipairs(getValues()) do
            local info = UIDropDownMenu_CreateInfo()
            info.text = option.label
            info.checked = active == option.value
            info.func = function()
                if PortalAuthorityDB.dockOrientation == "HORIZONTAL" then
                    PortalAuthorityDB.dockHorizontalTextPosition = option.value
                else
                    PortalAuthorityDB.dockVerticalTextSide = option.value
                end
                UIDropDownMenu_SetSelectedValue(dropdown, option.value)
                UIDropDownMenu_SetText(dropdown, option.label)
                if onApply then onApply() end
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)

    local spec = { kind = "dropdown", label = label, control = dropdown }
    spec.Refresh = function()
        normalizePlacement()
        if PortalAuthorityDB.dockOrientation == "HORIZONTAL" then
            label:SetText("Text placement")
            local value = PortalAuthorityDB.dockHorizontalTextPosition
            UIDropDownMenu_SetSelectedValue(dropdown, value)
            UIDropDownMenu_SetText(dropdown, value == "BELOW" and "Below" or "Above")
        else
            label:SetText("Text side")
            local value = PortalAuthorityDB.dockVerticalTextSide
            UIDropDownMenu_SetSelectedValue(dropdown, value)
            UIDropDownMenu_SetText(dropdown, value == "RIGHT" and "Right" or "Left")
        end
    end

    spec.Refresh()
    return spec
end

function PortalAuthority:CreateSettingsWindowSegmentedControl(parent, choices, onApply, opts)
    opts = type(opts) == "table" and opts or {}
    local spec = createPremiumSegmentedChoice(
        parent,
        tostring(opts.labelText or ""),
        nil,
        choices or {},
        onApply,
        opts
    )
    if spec and spec.label and trim(tostring(opts.labelText or "")) == "" then
        spec.label:SetText("")
        spec.label:Hide()
    end
    return spec
end

local function createScrollableChild(panel)
    local scrollFrame = CreateFrame("ScrollFrame", nil, panel, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", panel, "TOPLEFT", 12, -12)
    scrollFrame:SetPoint("TOPRIGHT", panel, "TOPRIGHT", -30, -12)
    scrollFrame:SetPoint("BOTTOMLEFT", panel, "BOTTOMLEFT", 12, 14)
    scrollFrame:SetPoint("BOTTOMRIGHT", panel, "BOTTOMRIGHT", -30, 14)

    local scrollChild = CreateFrame("Frame", nil, scrollFrame)
    scrollChild:SetPoint("TOPLEFT")
    scrollChild:SetPoint("TOPRIGHT")
    scrollChild:SetHeight(1)
    scrollFrame:SetScrollChild(scrollChild)

    markSettingsWindowVisualOptIn(panel)
    markSettingsWindowVisualOptIn(scrollFrame)
    markSettingsWindowVisualOptIn(scrollChild)
    panel._paSettingsScrollFrame = scrollFrame
    panel._paSettingsScrollChild = scrollChild
    scrollFrame._paCloseFloatingControlsOnUserScroll = true
    scrollFrame._paCloseFloatingControlsPanel = panel
    scrollFrame._paOwnerPanel = panel
    if panel._paSearchSectionKey then
        panel._paSearchScrollFrame = scrollFrame
        panel._paSearchScrollChild = scrollChild
        scrollFrame._paSearchPanel = panel
        scrollChild._paSearchPanel = panel
        panel._paSearchRegistryDirty = true
    end
    registerSettingsWindowVisualRefresh(scrollFrame, function(selfScroll)
        local child = selfScroll.GetScrollChild and selfScroll:GetScrollChild() or scrollChild
        local viewportHeight = tonumber(selfScroll:GetHeight()) or 0
        local contentHeight = child and (tonumber(child:GetHeight()) or 0) or 0
        settingsScrollRuntime.sync(selfScroll, child, viewportHeight, contentHeight)
    end)
    settingsScrollRuntime.sync(scrollFrame, scrollChild, scrollFrame:GetHeight() or 0, scrollChild:GetHeight() or 0)

    return scrollFrame, scrollChild
end

local function updateScrollBehavior(scrollFrame, scrollChild)
    if not scrollFrame or not scrollChild then
        return
    end

    if scrollFrame.UpdateScrollChildRect then
        scrollFrame:UpdateScrollChildRect()
    end

    local viewportHeight = scrollFrame:GetHeight() or 0
    local contentHeight = scrollChild:GetHeight() or 0
    local needsScroll = contentHeight > (viewportHeight + 1)
    local scrollBar = scrollFrame.ScrollBar

    if scrollBar then
        if isUsingCustomSettingsWindowVisualStyle(scrollFrame) then
            scrollBar:Hide()
        else
            scrollBar:SetShown(needsScroll)
        end
    end

    settingsScrollRuntime.sync(scrollFrame, scrollChild, viewportHeight, contentHeight)

    scrollFrame:EnableMouseWheel(needsScroll)
    if needsScroll then
        scrollFrame:SetScript("OnMouseWheel", function(frame, delta)
            if settingsScrollRuntime.closeFloatingControlsForParentScroll(frame) then
                return
            end
            settingsScrollRuntime.noteFrameInteraction(frame)
            local minScroll, maxScroll = 0, math.max(0, (scrollChild:GetHeight() or 0) - (frame:GetHeight() or 0))
            local current = frame:GetVerticalScroll() or 0
            local nextScroll = current - (delta * 40)
            if nextScroll < minScroll then nextScroll = minScroll end
            if nextScroll > maxScroll then nextScroll = maxScroll end
            frame._paSkipNextCustomScrollBarHookSync = true
            frame:SetVerticalScroll(nextScroll)
            settingsScrollRuntime.sync(frame, scrollChild, frame:GetHeight() or 0, scrollChild:GetHeight() or 0)
        end)
    else
        scrollFrame:SetVerticalScroll(0)
        scrollFrame:SetScript("OnMouseWheel", nil)
    end
end

local function lowerSettingsSearchText(value)
    local text = trim(tostring(value or ""))
    if text == "" then
        return ""
    end
    return string.lower(text)
end

settingsSearchRuntime.SEARCH_NOISE_EXACT = {
    ["death knight only"] = true,
    ["demon hunter only"] = true,
    ["druid only"] = true,
    ["evoker only"] = true,
    ["hunter only"] = true,
    ["mage only"] = true,
    ["monk only"] = true,
    ["paladin only"] = true,
    ["priest only"] = true,
    ["rogue only"] = true,
    ["shaman only"] = true,
    ["warlock only"] = true,
    ["warrior only"] = true,
    ["mythic+ only"] = true,
}

settingsSearchRuntime.GENERIC_CHOICE_CAPTION_EXACT = {
    ["enabled"] = true,
    ["disabled"] = true,
    ["enable"] = true,
    ["disable"] = true,
    ["on"] = true,
    ["off"] = true,
    ["show"] = true,
    ["hide"] = true,
    ["yes"] = true,
    ["no"] = true,
}

function settingsSearchRuntime.normalizeWhitespace(text)
    text = tostring(text or "")
    text = text:gsub("[%c\r\n\t]+", " ")
    text = text:gsub("%s+", " ")
    return trim(text)
end

function settingsSearchRuntime.stripFormatting(text)
    text = tostring(text or "")
    text = text:gsub("|c%x%x%x%x%x%x%x%x", "")
    text = text:gsub("|r", "")
    text = text:gsub("|T.-|t", " ")
    text = text:gsub("|A.-|a", " ")
    return settingsSearchRuntime.normalizeWhitespace(text)
end

function settingsSearchRuntime.stripQualifiers(text)
    text = settingsSearchRuntime.stripFormatting(text)
    if text == "" then
        return ""
    end

    text = text:gsub("%s*%[[^%]]-[Oo][Nn][Ll][Yy]%]%s*", " ")
    text = text:gsub("%s*%([^%)]-[Oo][Nn][Ll][Yy]%)%s*", " ")
    return settingsSearchRuntime.normalizeWhitespace(text)
end

function settingsSearchRuntime.isNoiseText(text)
    local normalized = lowerSettingsSearchText(settingsSearchRuntime.stripFormatting(text))
    if normalized == "" then
        return true
    end

    normalized = normalized:gsub("^%[", ""):gsub("%]$", "")
    normalized = normalized:gsub("^%(", ""):gsub("%)$", "")
    normalized = settingsSearchRuntime.normalizeWhitespace(normalized)
    if normalized == "" then
        return true
    end

    return settingsSearchRuntime.SEARCH_NOISE_EXACT[normalized] == true
end

function settingsSearchRuntime.sanitizeVisibleText(text)
    text = settingsSearchRuntime.stripQualifiers(text)
    if text == "" or settingsSearchRuntime.isNoiseText(text) then
        return ""
    end
    return settingsSearchRuntime.normalizeWhitespace(text)
end

function settingsSearchRuntime.normalizeChoiceLabelMode(mode)
    mode = lowerSettingsSearchText(mode)
    if mode == "index_all" then
        return "index_all"
    end
    return "suppress_generic"
end

function settingsSearchRuntime.markSearchTextOrigin(ref, origin, opts)
    if not frameIsAlive(ref) then
        return ref
    end

    origin = lowerSettingsSearchText(origin)
    if origin == "" then
        ref._paSearchTextOrigin = nil
        ref._paSearchChoiceLabelMode = nil
        return ref
    end

    ref._paSearchTextOrigin = origin
    if origin == "choice_caption" then
        opts = type(opts) == "table" and opts or {}
        ref._paSearchChoiceLabelMode = settingsSearchRuntime.normalizeChoiceLabelMode(
            opts.searchChoiceLabelMode or opts.choiceLabelMode
        )
    else
        ref._paSearchChoiceLabelMode = nil
    end
    return ref
end

function settingsSearchRuntime.shouldSuppressSearchTextRef(ref, text)
    if not frameIsAlive(ref) then
        return false
    end
    if lowerSettingsSearchText(ref._paSearchTextOrigin) ~= "choice_caption" then
        return false
    end
    if settingsSearchRuntime.normalizeChoiceLabelMode(ref._paSearchChoiceLabelMode) ~= "suppress_generic" then
        return false
    end

    local normalized = lowerSettingsSearchText(settingsSearchRuntime.stripFormatting(text))
    normalized = settingsSearchRuntime.normalizeWhitespace(normalized)
    return settingsSearchRuntime.GENERIC_CHOICE_CAPTION_EXACT[normalized] == true
end

local function getSettingsSearchPanelByKey(sectionKey)
    local registry = PortalAuthority and PortalAuthority.settingsPanelRegistry or nil
    local entry = registry and registry[sectionKey] or nil
    return entry and entry.panel or nil
end

local function getSettingsSearchTextFromRef(ref)
    if not ref then
        return ""
    end
    if ref.GetText then
        local ok, value = pcall(ref.GetText, ref)
        if ok then
            local sanitized = settingsSearchRuntime.sanitizeVisibleText(value)
            if sanitized ~= "" and settingsSearchRuntime.shouldSuppressSearchTextRef(ref, value) then
                return ""
            end
            return sanitized
        end
    end
    return ""
end

local function safeSettingsSearchMetric(frame, methodName)
    if not frame then
        return nil
    end
    local method = frame[methodName]
    if type(method) ~= "function" then
        return nil
    end
    local ok, value = pcall(method, frame)
    if not ok then
        return nil
    end
    return tonumber(value) or nil
end

function settingsSearchRuntime.resolveScrollY(panel, targetRef)
    if not panel or not targetRef then
        return 0
    end
    local scrollChild = panel._paSearchScrollChild or panel._paSettingsScrollChild or nil
    local rootTop = safeSettingsSearchMetric(scrollChild, "GetTop")
    local targetTop = safeSettingsSearchMetric(targetRef, "GetTop")
    if rootTop and targetTop then
        local offset = rootTop - targetTop
        if offset >= 0 then
            return math.floor(offset + 0.5)
        end
    end
    local targetBottom = safeSettingsSearchMetric(targetRef, "GetBottom")
    if rootTop and targetBottom then
        local offset = rootTop - targetBottom
        if offset >= 0 then
            return math.floor(offset + 0.5)
        end
    end
    return 0
end

function settingsSearchRuntime.buildHaystack(searchRefs)
    local pieces = {}
    local seen = {}

    local function addPiece(raw)
        local normalized = lowerSettingsSearchText(raw)
        if normalized == "" or seen[normalized] then
            return
        end
        seen[normalized] = true
        pieces[#pieces + 1] = normalized
    end

    if type(searchRefs) == "table" then
        for i = 1, #searchRefs do
            addPiece(getSettingsSearchTextFromRef(searchRefs[i]))
        end
    end
    return table.concat(pieces, " ")
end

function settingsSearchRuntime.isControlDescriptorKind(kind)
    kind = lowerSettingsSearchText(kind)
    return kind ~= "" and kind ~= "text" and kind ~= "group_title" and kind ~= "section_name"
end

function settingsSearchRuntime.getRenderableStandaloneKind(panel, descriptor, labelText)
    if not descriptor then
        return nil
    end

    local kind = lowerSettingsSearchText(descriptor.kind)
    if kind == "group_title" or kind == "section_name" then
        return kind
    end
    if kind ~= "" and kind ~= "text" then
        return nil
    end

    local displayRef = descriptor.displayRef
    local controlRef = descriptor.controlRef or descriptor.anchorRef or displayRef
    local size = tonumber(descriptor.fontSize) or 0
    local matchesSectionTitle = lowerSettingsSearchText(labelText) == lowerSettingsSearchText(panel and (panel._paSearchSectionName or panel.name or "") or "")

    if matchesSectionTitle and displayRef == panel._paSearchTopTarget then
        return nil
    end

    if size >= 12 and displayRef == controlRef then
        return "group_title"
    end

    return nil
end

function settingsSearchRuntime.addEntryHaystackPiece(entry, rawText)
    if not entry then
        return
    end
    local normalized = lowerSettingsSearchText(rawText)
    if normalized == "" then
        return
    end
    entry._haystackSeen = entry._haystackSeen or {}
    if entry._haystackSeen[normalized] then
        return
    end
    entry._haystackSeen[normalized] = true
    entry._haystackParts = entry._haystackParts or {}
    entry._haystackParts[#entry._haystackParts + 1] = normalized
end

function settingsSearchRuntime.appendControlEntryHelperRef(entry, ref)
    if not entry or not frameIsAlive(ref) then
        return
    end
    entry._searchHelperRefs = entry._searchHelperRefs or {}
    settingsSearchRuntime.appendUniqueSearchRef(entry._searchHelperRefs, ref)
end

function settingsSearchRuntime.appendControlEntryNaturalCandidate(entry, ref)
    if not entry or not frameIsAlive(ref) then
        return
    end
    entry._searchNaturalRowCandidates = entry._searchNaturalRowCandidates or {}
    settingsSearchRuntime.appendUniqueSearchRef(entry._searchNaturalRowCandidates, ref)
end

function settingsSearchRuntime.setSearchTargetFramePassThrough(frame)
    if not frameIsAlive(frame) then
        return
    end
    if frame.EnableMouse then
        frame:EnableMouse(false)
    end
    if frame.EnableMouseWheel then
        frame:EnableMouseWheel(false)
    end
    if frame.SetMouseClickEnabled then
        frame:SetMouseClickEnabled(false)
    end
    if frame.SetMouseMotionEnabled then
        frame:SetMouseMotionEnabled(false)
    end
end

function settingsSearchRuntime.collectSearchTargetBounds(refs)
    if type(refs) ~= "table" then
        return nil
    end

    local left, right, top, bottom = nil, nil, nil, nil
    for i = 1, #refs do
        local ref = refs[i]
        if frameIsAlive(ref) then
            local refLeft = safeSettingsSearchMetric(ref, "GetLeft")
            local refRight = safeSettingsSearchMetric(ref, "GetRight")
            local refTop = safeSettingsSearchMetric(ref, "GetTop")
            local refBottom = safeSettingsSearchMetric(ref, "GetBottom")
            if refLeft and refRight and refTop and refBottom and refRight > refLeft and refTop > refBottom then
                if not left or refLeft < left then
                    left = refLeft
                end
                if not right or refRight > right then
                    right = refRight
                end
                if not top or refTop > top then
                    top = refTop
                end
                if not bottom or refBottom < bottom then
                    bottom = refBottom
                end
            end
        end
    end

    if left and right and top and bottom and right > left and top > bottom then
        return {
            left = left,
            right = right,
            top = top,
            bottom = bottom,
            width = right - left,
            height = top - bottom,
        }
    end
    return nil
end

function settingsSearchRuntime.buildSearchTargetBoundsNote(targetBounds, visibleBounds)
    if type(targetBounds) ~= "table" or type(visibleBounds) ~= "table" then
        return "missing-bounds"
    end

    local leftExtra = math.floor((visibleBounds.left - targetBounds.left) + 0.5)
    local rightExtra = math.floor((targetBounds.right - visibleBounds.right) + 0.5)
    local topExtra = math.floor((targetBounds.top - visibleBounds.top) + 0.5)
    local bottomExtra = math.floor((visibleBounds.bottom - targetBounds.bottom) + 0.5)
    return string.format(
        "target=%dx%d visible=%dx%d extra(L%d R%d T%d B%d)",
        math.floor(targetBounds.width + 0.5),
        math.floor(targetBounds.height + 0.5),
        math.floor(visibleBounds.width + 0.5),
        math.floor(visibleBounds.height + 0.5),
        leftExtra,
        rightExtra,
        topExtra,
        bottomExtra
    )
end

function settingsSearchRuntime.evaluateSearchTargetBounds(candidateRef, visibleBounds)
    if not frameIsAlive(candidateRef) then
        return false, nil, "invalid-frame"
    end

    local candidateBounds = settingsSearchRuntime.collectSearchTargetBounds({ candidateRef })
    if type(candidateBounds) ~= "table" then
        return false, nil, "missing-bounds"
    end
    if type(visibleBounds) ~= "table" then
        return false, candidateBounds, "missing-visible-bounds"
    end

    local maxExtraHorizontal = math.max(18, (tonumber(visibleBounds.width) or 0) * 0.35)
    local maxExtraVertical = math.max(10, (tonumber(visibleBounds.height) or 0) * 0.65)
    local tolerance = 2

    local leftDelta = visibleBounds.left - candidateBounds.left
    local rightDelta = candidateBounds.right - visibleBounds.right
    local topDelta = candidateBounds.top - visibleBounds.top
    local bottomDelta = visibleBounds.bottom - candidateBounds.bottom

    if leftDelta < -tolerance or rightDelta < -tolerance or topDelta < -tolerance or bottomDelta < -tolerance then
        return false, candidateBounds, settingsSearchRuntime.buildSearchTargetBoundsNote(candidateBounds, visibleBounds)
    end

    if leftDelta > maxExtraHorizontal or rightDelta > maxExtraHorizontal or topDelta > maxExtraVertical or bottomDelta > maxExtraVertical then
        return false, candidateBounds, settingsSearchRuntime.buildSearchTargetBoundsNote(candidateBounds, visibleBounds)
    end

    return true, candidateBounds, settingsSearchRuntime.buildSearchTargetBoundsNote(candidateBounds, visibleBounds)
end

function settingsSearchRuntime.collectControlEntryVisibleRefs(entry)
    local refs = {}
    if type(entry) ~= "table" then
        return refs
    end

    settingsSearchRuntime.appendUniqueSearchRef(refs, entry._searchLabelRef)
    local helperRefs = entry._searchHelperRefs or {}
    for i = 1, #helperRefs do
        settingsSearchRuntime.appendUniqueSearchRef(refs, helperRefs[i])
    end
    settingsSearchRuntime.appendUniqueSearchRef(refs, entry._searchWidgetRef)
    return refs
end

function settingsSearchRuntime.getSearchTargetSingleBounds(ref)
    return settingsSearchRuntime.collectSearchTargetBounds({ ref })
end

function settingsSearchRuntime.collectControlEntryVisibleBounds(panel, entry)
    local refs = settingsSearchRuntime.collectControlEntryVisibleRefs(entry)
    local filteredRefs = {}
    local rejectedCount = 0
    local scrollChild = panel and (panel._paSearchScrollChild or panel._paSettingsScrollChild) or nil
    local scrollChildBounds = settingsSearchRuntime.getSearchTargetSingleBounds(scrollChild)
    local widgetBounds = settingsSearchRuntime.getSearchTargetSingleBounds(type(entry) == "table" and entry._searchWidgetRef or nil)
    local widgetCenterY = widgetBounds and ((widgetBounds.top + widgetBounds.bottom) * 0.5) or nil
    local maxVerticalDistance = widgetBounds and math.max(160, (tonumber(widgetBounds.height) or 0) * 6) or nil

    for i = 1, #refs do
        local ref = refs[i]
        local refBounds = settingsSearchRuntime.getSearchTargetSingleBounds(ref)
        local keep = type(refBounds) == "table"

        if keep and type(scrollChildBounds) == "table" then
            local nearFullWidth = (tonumber(refBounds.width) or 0) >= ((tonumber(scrollChildBounds.width) or 0) * 0.92)
            local nearFullHeight = (tonumber(refBounds.height) or 0) >= math.max(140, (tonumber(scrollChildBounds.height) or 0) * 0.60)
            if nearFullWidth and nearFullHeight then
                keep = false
            end
        end

        if keep and widgetCenterY and maxVerticalDistance and ref ~= entry._searchWidgetRef then
            local refCenterY = ((tonumber(refBounds.top) or 0) + (tonumber(refBounds.bottom) or 0)) * 0.5
            if math.abs(refCenterY - widgetCenterY) > maxVerticalDistance then
                keep = false
            end
        end

        if keep then
            settingsSearchRuntime.appendUniqueSearchRef(filteredRefs, ref)
        else
            rejectedCount = rejectedCount + 1
        end
    end

    if #filteredRefs == 0 and frameIsAlive(entry and entry._searchWidgetRef or nil) then
        settingsSearchRuntime.appendUniqueSearchRef(filteredRefs, entry._searchWidgetRef)
    end

    return filteredRefs, settingsSearchRuntime.collectSearchTargetBounds(filteredRefs), rejectedCount
end

function settingsSearchRuntime.findSearchCommonAncestor(refs, stopRef)
    if type(refs) ~= "table" or #refs <= 0 then
        return nil
    end

    local ancestryOrder = {}
    local ancestrySeen = {}
    local current = refs[1]
    while current do
        ancestryOrder[#ancestryOrder + 1] = current
        ancestrySeen[current] = true
        if current == stopRef then
            break
        end
        current = current.GetParent and current:GetParent() or nil
    end

    for i = 2, #refs do
        local nextSeen = {}
        local probe = refs[i]
        while probe do
            nextSeen[probe] = true
            if probe == stopRef then
                break
            end
            probe = probe.GetParent and probe:GetParent() or nil
        end
        for j = #ancestryOrder, 1, -1 do
            local candidate = ancestryOrder[j]
            if not nextSeen[candidate] then
                ancestrySeen[candidate] = nil
                table.remove(ancestryOrder, j)
            end
        end
    end

    for i = 1, #ancestryOrder do
        local candidate = ancestryOrder[i]
        if candidate ~= stopRef then
            return candidate
        end
    end
    return nil
end

function settingsSearchRuntime.collectControlEntryNaturalCandidates(panel, entry, visibleRefs)
    local refs = {}
    local scrollChild = panel and (panel._paSearchScrollChild or panel._paSettingsScrollChild) or nil
    if type(entry) ~= "table" then
        return refs
    end

    settingsSearchRuntime.appendUniqueSearchRef(refs, entry._searchExplicitRowFrame)

    local commonAncestor = settingsSearchRuntime.findSearchCommonAncestor(visibleRefs, scrollChild)
    settingsSearchRuntime.appendUniqueSearchRef(refs, commonAncestor)

    local widgetParent = frameIsAlive(entry._searchWidgetRef) and entry._searchWidgetRef.GetParent and entry._searchWidgetRef:GetParent() or nil
    local labelParent = frameIsAlive(entry._searchLabelRef) and entry._searchLabelRef.GetParent and entry._searchLabelRef:GetParent() or nil
    settingsSearchRuntime.appendUniqueSearchRef(refs, widgetParent)
    settingsSearchRuntime.appendUniqueSearchRef(refs, labelParent)

    local helperRefs = entry._searchHelperRefs or {}
    for i = 1, #helperRefs do
        local helperParent = helperRefs[i].GetParent and helperRefs[i]:GetParent() or nil
        settingsSearchRuntime.appendUniqueSearchRef(refs, helperParent)
    end

    local explicitCandidates = entry._searchNaturalRowCandidates or {}
    for i = 1, #explicitCandidates do
        settingsSearchRuntime.appendUniqueSearchRef(refs, explicitCandidates[i])
    end

    return refs
end

function settingsSearchRuntime.acquireSyntheticSearchRowFrame(entry, parent)
    if type(entry) ~= "table" or not frameIsAlive(parent) then
        return nil
    end

    local rowFrame = entry._searchSyntheticRowFrame
    if not frameIsAlive(rowFrame) then
        rowFrame = CreateFrame("Frame", nil, parent)
        entry._searchSyntheticRowFrame = rowFrame
    end
    if rowFrame:GetParent() ~= parent then
        rowFrame:SetParent(parent)
    end
    settingsSearchRuntime.setSearchTargetFramePassThrough(rowFrame)
    return rowFrame
end

function settingsSearchRuntime.hideSyntheticSearchRowFrame(entry)
    local rowFrame = type(entry) == "table" and entry._searchSyntheticRowFrame or nil
    if frameIsAlive(rowFrame) then
        rowFrame:Hide()
    end
end

function settingsSearchRuntime.recordControlEntryTargetClass(entry, targetType, phase)
    if type(entry) ~= "table" or type(targetType) ~= "string" or targetType == "" then
        return
    end

    local history = entry._searchTargetHistory or {}
    if history[#history] ~= targetType then
        history[#history + 1] = targetType
    end
    entry._searchTargetHistory = history
    entry._searchTargetHistorySummary = table.concat(history, " -> ")

    if not entry._searchFirstResolvedPhase then
        entry._searchFirstResolvedPhase = phase
    end
    if phase == "hidden" and not entry._searchHiddenResolvedTargetType then
        entry._searchHiddenResolvedTargetType = targetType
    end
    if phase == "real" then
        entry._searchRealResolvedTargetType = targetType
    end
    entry._searchResolvedPhase = phase
end

function settingsSearchRuntime.buildControlRegistryKey(panel, descriptor, labelText, controlRef, fallbackRef, orderIndex)
    local sectionKey = lowerSettingsSearchText(panel and panel._paSearchSectionKey or "")
    local kindKey = lowerSettingsSearchText(descriptor and descriptor.kind or "control")
    local labelKey = lowerSettingsSearchText(labelText or "")
    local orderKey = math.floor(tonumber(orderIndex) or 0)

    if sectionKey ~= "" and (labelKey ~= "" or orderKey > 0) then
        return table.concat({
            "control",
            sectionKey,
            tostring(orderKey),
            kindKey,
            labelKey,
        }, "|")
    end

    return controlRef or fallbackRef or (descriptor and descriptor.displayRef) or tostring(orderKey)
end

function settingsSearchRuntime.resolveControlEntryTarget(panel, entry)
    if not panel or type(entry) ~= "table" or entry.kind ~= "control" then
        return nil
    end

    local scrollChild = panel._paSearchScrollChild or panel._paSettingsScrollChild or nil
    local visibleRefs, visibleBounds, rejectedVisibleRefs = settingsSearchRuntime.collectControlEntryVisibleBounds(panel, entry)
    local isRealLayout = panel._paSearchRealActivationComplete == true
    local resolvedTarget, resolvedType, resolvedBoundsNote = nil, nil, nil

    if not frameIsAlive(resolvedTarget) and type(visibleBounds) ~= "table" and frameIsAlive(entry._searchExplicitRowFrame) then
        resolvedTarget = entry._searchExplicitRowFrame
        resolvedType = "explicit_row"
        resolvedBoundsNote = "explicit row without visible comparison"
    end

    local naturalCandidates = settingsSearchRuntime.collectControlEntryNaturalCandidates(panel, entry, visibleRefs)
    for i = 1, #naturalCandidates do
        local candidate = naturalCandidates[i]
        local candidateType = candidate == entry._searchExplicitRowFrame and "explicit_row" or "natural_row"
        local ok, _, boundsNote = settingsSearchRuntime.evaluateSearchTargetBounds(candidate, visibleBounds)
        if ok then
            resolvedTarget = candidate
            resolvedType = candidateType
            resolvedBoundsNote = boundsNote
            break
        end
    end

    if not frameIsAlive(resolvedTarget) and frameIsAlive(scrollChild) and type(visibleBounds) == "table" then
        local rootLeft = safeSettingsSearchMetric(scrollChild, "GetLeft")
        local rootTop = safeSettingsSearchMetric(scrollChild, "GetTop")
        if rootLeft and rootTop then
            local rowFrame = settingsSearchRuntime.acquireSyntheticSearchRowFrame(entry, scrollChild)
            if frameIsAlive(rowFrame) then
                rowFrame:ClearAllPoints()
                rowFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", visibleBounds.left - rootLeft, visibleBounds.top - rootTop)
                rowFrame:SetPoint("BOTTOMRIGHT", scrollChild, "TOPLEFT", visibleBounds.right - rootLeft, visibleBounds.bottom - rootTop)
                rowFrame:Show()
                resolvedTarget = rowFrame
                resolvedType = "synthetic_row"
                resolvedBoundsNote = settingsSearchRuntime.buildSearchTargetBoundsNote(visibleBounds, visibleBounds)
            end
        end
    else
        settingsSearchRuntime.hideSyntheticSearchRowFrame(entry)
    end

    if not frameIsAlive(resolvedTarget) then
        settingsSearchRuntime.hideSyntheticSearchRowFrame(entry)
        resolvedTarget = frameIsAlive(entry._searchWidgetRef) and entry._searchWidgetRef
            or (frameIsAlive(entry.controlRef) and entry.controlRef or nil)
        resolvedType = "widget_fallback"
        resolvedBoundsNote = type(visibleBounds) == "table"
            and "widget fallback - no broader visible row target validated"
            or "widget fallback - visible row bounds unavailable"
    end

    local provisional = isRealLayout ~= true
    local currentPhase = isRealLayout and "real" or "hidden"
    local previousType = entry._searchTargetType
    local boundsValid = false
    if frameIsAlive(resolvedTarget) then
        if resolvedType == "synthetic_row" and type(visibleBounds) == "table" then
            boundsValid = true
        else
            boundsValid = select(1, settingsSearchRuntime.evaluateSearchTargetBounds(resolvedTarget, visibleBounds)) == true
        end
    end
    entry._searchRegistryTargetRef = resolvedTarget
    entry._searchRegistryAnchorRef = resolvedTarget
    entry._searchScrollSourceRef = resolvedTarget
    entry._searchTargetType = resolvedType
    entry._searchTargetProvisional = provisional and true or false
    entry._searchVisibleBounds = visibleBounds
    entry._searchVisibleRefCount = #visibleRefs
    entry._searchRejectedVisibleRefCount = rejectedVisibleRefs or 0
    entry._searchTargetBounds = settingsSearchRuntime.collectSearchTargetBounds({ resolvedTarget })
    entry._searchTargetBoundsNote = string.format(
        "%s refs=%d rejected=%d",
        tostring(resolvedBoundsNote or "missing-bounds"),
        tonumber(#visibleRefs) or 0,
        tonumber(rejectedVisibleRefs) or 0
    )
    entry._searchTargetBoundsValid = boundsValid and true or false
    entry._searchTargetSameObject = resolvedTarget == entry._searchRegistryTargetRef
    entry._searchWidgetFallbackReason = resolvedType == "widget_fallback" and resolvedBoundsNote or nil
    if previousType and previousType ~= resolvedType then
        entry._searchTargetChanged = true
    end
    settingsSearchRuntime.recordControlEntryTargetClass(entry, resolvedType, currentPhase)

    entry.controlRef = resolvedTarget
    entry.anchorRef = resolvedTarget
    entry.scrollY = settingsSearchRuntime.resolveScrollY(panel, resolvedTarget)
    entry.skipHighlight = not frameIsAlive(resolvedTarget)
    entry._searchRegistryScrollY = entry.scrollY
    entry._searchAlignedTarget = entry.controlRef == entry.anchorRef and entry.controlRef == entry._searchScrollSourceRef
    if provisional then
        panel._paSearchHasProvisionalControlTargets = true
    end
    return resolvedTarget
end

function settingsSearchRuntime.newControlRegistryEntry(panel, descriptor, labelText, controlRef, fallbackRef, orderIndex, sectionName, registryKey)
    if not panel then
        return nil
    end

    registryKey = registryKey or settingsSearchRuntime.buildControlRegistryKey(panel, descriptor, labelText, controlRef, fallbackRef, orderIndex)
    panel._paSearchLiveControlEntries = panel._paSearchLiveControlEntries or {}
    local entry = panel._paSearchLiveControlEntries[registryKey]
    if type(entry) ~= "table" then
        entry = {}
        panel._paSearchLiveControlEntries[registryKey] = entry
    end

    entry.kind = "control"
    entry.sectionKey = panel._paSearchSectionKey
    entry.sectionName = sectionName
    entry.displayLabel = trim(tostring(labelText or ""))
    entry.displayHelper = nil
    entry.labelText = trim(tostring(labelText or ""))
    entry.helperText = nil
    entry.orderIndex = orderIndex
    entry.searchHaystack = ""
    entry.haystack = ""
    entry.dedupeKey = nil
    entry.iconType = descriptor and descriptor.iconType or nil
    entry._haystackParts = {}
    entry._haystackSeen = {}
    entry._searchRegistryKey = registryKey
    entry._searchWidgetRef = frameIsAlive(descriptor and descriptor.searchWidgetRef or nil) and descriptor.searchWidgetRef
        or (frameIsAlive(controlRef) and controlRef or nil)
    entry._searchLabelRef = frameIsAlive(descriptor and descriptor.searchLabelRef or nil) and descriptor.searchLabelRef
        or (frameIsAlive(descriptor and descriptor.displayRef or nil) and descriptor.displayRef or nil)
    entry._searchHelperRefs = {}
    entry._searchNaturalRowCandidates = {}
    entry._searchExplicitRowFrame = frameIsAlive(descriptor and descriptor.searchRowFrame or nil) and descriptor.searchRowFrame or nil
    entry.controlRef = frameIsAlive(entry._searchWidgetRef) and entry._searchWidgetRef
        or (frameIsAlive(fallbackRef) and fallbackRef or nil)
    entry.anchorRef = entry.controlRef
    entry.scrollY = settingsSearchRuntime.resolveScrollY(panel, entry.controlRef)
    entry.skipHighlight = not frameIsAlive(entry.controlRef)
    entry._searchRegistryTargetRef = nil
    entry._searchRegistryAnchorRef = nil
    entry._searchScrollSourceRef = nil
    entry._searchRegistryScrollY = nil
    entry._searchVisibleBounds = nil
    entry._searchTargetBounds = nil
    entry._searchTargetBoundsNote = nil
    entry._searchTargetBoundsValid = false
    entry._searchTargetType = entry._searchTargetType or nil
    entry._searchTargetProvisional = false
    entry._searchAlignedTarget = false
    entry._searchTargetChanged = false
    entry._searchWidgetFallbackReason = nil
    entry._searchTargetHistory = entry._searchTargetHistory or {}
    return entry
end

function settingsSearchRuntime.absorbDescriptorIntoControlEntry(entry, descriptor, labelText)
    if not entry or not descriptor then
        return
    end

    local displayLabel = trim(tostring(labelText or ""))
    if trim(entry.displayLabel or "") == "" and displayLabel ~= "" then
        entry.displayLabel = displayLabel
        entry.labelText = displayLabel
    end
    if not entry.iconType and descriptor.iconType then
        entry.iconType = descriptor.iconType
    end
    if frameIsAlive(descriptor.searchWidgetRef) then
        entry._searchWidgetRef = descriptor.searchWidgetRef
    end
    if frameIsAlive(descriptor.searchLabelRef) then
        entry._searchLabelRef = descriptor.searchLabelRef
    elseif frameIsAlive(descriptor.displayRef) then
        entry._searchLabelRef = descriptor.displayRef
    end
    if frameIsAlive(descriptor.searchRowFrame) then
        entry._searchExplicitRowFrame = descriptor.searchRowFrame
    end
    settingsSearchRuntime.appendControlEntryNaturalCandidate(entry, descriptor.searchRowFrame)
    settingsSearchRuntime.appendControlEntryNaturalCandidate(entry, descriptor.parentRef)

    local searchRefs = descriptor.searchRefs or {}
    for i = 1, #searchRefs do
        local text = getSettingsSearchTextFromRef(searchRefs[i])
        if i == 1 then
            settingsSearchRuntime.addEntryHaystackPiece(entry, text)
        else
            settingsSearchRuntime.attachHelperTextToControlEntry(entry, text)
        end
    end
    local helperRefs = descriptor.searchHelperRefs or {}
    for i = 1, #helperRefs do
        settingsSearchRuntime.appendControlEntryHelperRef(entry, helperRefs[i])
        settingsSearchRuntime.appendControlEntryNaturalCandidate(entry, helperRefs[i].GetParent and helperRefs[i]:GetParent() or nil)
    end
    settingsSearchRuntime.addEntryHaystackPiece(entry, displayLabel)
end

function settingsSearchRuntime.attachHelperTextToControlEntry(entry, helperText)
    if not entry then
        return
    end
    local text = trim(tostring(helperText or ""))
    if text == "" then
        return
    end
    if lowerSettingsSearchText(text) == lowerSettingsSearchText(entry.displayLabel or entry.labelText or "") then
        return
    end
    if trim(entry.displayHelper or "") == "" then
        entry.displayHelper = text
        entry.helperText = text
    end
    settingsSearchRuntime.addEntryHaystackPiece(entry, text)
end

function settingsSearchRuntime.buildTargetIdentity(controlRef, scrollY, orderIndex)
    if controlRef ~= nil then
        return tostring(controlRef)
    end
    return string.format("scroll:%d:%d", math.floor(tonumber(scrollY) or 0), math.floor(tonumber(orderIndex) or 0))
end

function settingsSearchRuntime.getEntryDedupeKey(entry)
    if type(entry) ~= "table" then
        return nil
    end

    local kind = lowerSettingsSearchText(entry.kind)
    local sectionKey = lowerSettingsSearchText(entry.sectionKey)
    local labelKey = lowerSettingsSearchText(entry.displayLabel or entry.labelText or "")
    local targetKey = settingsSearchRuntime.buildTargetIdentity(entry._searchRegistryKey or entry.controlRef, entry.scrollY, entry.orderIndex)

    if kind == "control" then
        return table.concat({ "control", sectionKey, targetKey }, "|")
    end
    if kind == "group_title" then
        return table.concat({ "group_title", sectionKey, labelKey, targetKey }, "|")
    end
    if kind == "section_name" then
        return table.concat({ "section_name", sectionKey, labelKey }, "|")
    end
    return nil
end

function settingsSearchRuntime.finalizeRegistryEntry(entry)
    if type(entry) ~= "table" then
        return nil
    end

    entry.displayLabel = trim(tostring(entry.displayLabel or entry.labelText or ""))
    entry.displayHelper = trim(tostring(entry.displayHelper or entry.helperText or ""))
    local haystackParts = entry._haystackParts
    if type(haystackParts) == "table" and #haystackParts > 0 then
        entry.searchHaystack = table.concat(haystackParts, " ")
    else
        entry.searchHaystack = trim(tostring(entry.searchHaystack or entry.haystack or ""))
    end
    entry.dedupeKey = settingsSearchRuntime.getEntryDedupeKey(entry)
    entry.labelText = entry.displayLabel
    entry.helperText = entry.displayHelper
    entry.haystack = entry.searchHaystack
    entry.skipHighlight = entry.kind == "section_name" or not frameIsAlive(entry.controlRef)
    entry._haystackParts = nil
    entry._haystackSeen = nil
    return entry
end

function settingsSearchRuntime.attachHelperDescriptorToControlEntry(controlEntries, helperDescriptor)
    if type(controlEntries) ~= "table" or type(helperDescriptor) ~= "table" then
        return false
    end

    local helperText = trim(tostring(helperDescriptor.labelText or ""))
    if helperText == "" then
        return false
    end

    local helperY = tonumber(helperDescriptor.scrollY) or 0
    local helperOrderIndex = tonumber(helperDescriptor.orderIndex) or 0
    local bestEntry, bestScore = nil, nil

    for i = 1, #controlEntries do
        local entry = controlEntries[i]
        if entry then
            local entryY = tonumber(entry.scrollY) or 0
            local yDelta = math.abs(entryY - helperY)
            local orderDelta = math.abs((tonumber(entry.orderIndex) or 0) - helperOrderIndex)
            local score = yDelta + (orderDelta * 6)
            if yDelta <= 140 or orderDelta <= 4 then
                if not bestScore or score < bestScore then
                    bestEntry = entry
                    bestScore = score
                end
            end
        end
    end

    if not bestEntry then
        return false
    end

    settingsSearchRuntime.attachHelperTextToControlEntry(bestEntry, helperText)
    settingsSearchRuntime.appendControlEntryHelperRef(bestEntry, helperDescriptor.displayRef)
    settingsSearchRuntime.appendControlEntryNaturalCandidate(bestEntry, helperDescriptor.displayRef and helperDescriptor.displayRef.GetParent and helperDescriptor.displayRef:GetParent() or nil)
    return true
end

function settingsSearchRuntime.rebuildRegistry(panel)
    if not panel then
        return nil, false
    end

    local state = settingsSearchRuntime.ensureDescriptorState(panel)
    panel._paSearchHasProvisionalControlTargets = false
    panel._paSearchLiveControlEntries = panel._paSearchLiveControlEntries or {}
    local registry = {}
    local sectionName = panel._paSearchSectionName or panel.name or ""
    local syntheticControlRef = panel._paSearchTopTarget
    registry[#registry + 1] = {
        kind = "section_name",
        sectionKey = panel._paSearchSectionKey,
        sectionName = sectionName,
        displayLabel = sectionName,
        displayHelper = nil,
        labelText = sectionName,
        helperText = nil,
        controlRef = syntheticControlRef,
        scrollY = syntheticControlRef and settingsSearchRuntime.resolveScrollY(panel, syntheticControlRef) or 0,
        orderIndex = 0,
        searchHaystack = lowerSettingsSearchText(sectionName),
        haystack = lowerSettingsSearchText(sectionName),
        dedupeKey = nil,
        iconType = nil,
        skipHighlight = not frameIsAlive(syntheticControlRef),
    }

    local controlEntriesByRef = {}
    local orderedControlEntries = {}
    local orderedRenderableEntries = {}
    local orphanTextDescriptors = {}
    local ownedTextRefs = {}
    local seenLiveControlKeys = {}

    for i = 1, #(state.descriptors or {}) do
        local descriptor = state.descriptors[i]
        local displayRef = descriptor and descriptor.displayRef or nil
        local labelText = getSettingsSearchTextFromRef(displayRef)
        local controlRef = descriptor and (descriptor.searchWidgetRef or descriptor.controlRef or descriptor.anchorRef or displayRef) or nil
        local orderIndex = descriptor and (descriptor.orderIndex or i) or i
        local isDuplicateSectionHeader = labelText ~= ""
            and lowerSettingsSearchText(labelText) == lowerSettingsSearchText(sectionName)
            and displayRef == panel._paSearchTopTarget
        if descriptor and not isDuplicateSectionHeader and labelText ~= "" then
            if settingsSearchRuntime.isControlDescriptorKind(descriptor.kind) then
                local entryKey = settingsSearchRuntime.buildControlRegistryKey(
                    panel,
                    descriptor,
                    labelText,
                    controlRef,
                    displayRef,
                    orderIndex
                )
                local entry = controlEntriesByRef[entryKey]
                if not entry then
                    entry = settingsSearchRuntime.newControlRegistryEntry(
                        panel,
                        descriptor,
                        labelText,
                        controlRef,
                        displayRef,
                        orderIndex,
                        sectionName,
                        entryKey
                    )
                    controlEntriesByRef[entryKey] = entry
                    orderedControlEntries[#orderedControlEntries + 1] = entry
                    orderedRenderableEntries[#orderedRenderableEntries + 1] = entry
                end
                seenLiveControlKeys[entryKey] = true
                settingsSearchRuntime.absorbDescriptorIntoControlEntry(entry, descriptor, labelText)
                local searchRefs = descriptor.searchRefs or {}
                for j = 1, #searchRefs do
                    local ref = searchRefs[j]
                    if frameIsAlive(ref) then
                        ownedTextRefs[ref] = true
                    end
                end
            else
                local standaloneKind = settingsSearchRuntime.getRenderableStandaloneKind(panel, descriptor, labelText)
                if standaloneKind then
                    orderedRenderableEntries[#orderedRenderableEntries + 1] = {
                        kind = standaloneKind,
                        sectionKey = panel._paSearchSectionKey,
                        sectionName = sectionName,
                        displayLabel = labelText,
                        displayHelper = nil,
                        labelText = labelText,
                        helperText = nil,
                        controlRef = controlRef,
                        scrollY = settingsSearchRuntime.resolveScrollY(panel, controlRef or displayRef),
                        orderIndex = orderIndex,
                        searchHaystack = lowerSettingsSearchText(labelText),
                        haystack = lowerSettingsSearchText(labelText),
                        dedupeKey = nil,
                        iconType = nil,
                        skipHighlight = standaloneKind == "section_name" or not frameIsAlive(controlRef or displayRef),
                    }
                else
                    orphanTextDescriptors[#orphanTextDescriptors + 1] = {
                        displayRef = displayRef,
                        labelText = labelText,
                        scrollY = settingsSearchRuntime.resolveScrollY(panel, displayRef or controlRef),
                        orderIndex = orderIndex,
                    }
                end
            end
        end
    end

    for i = 1, #orphanTextDescriptors do
        local orphan = orphanTextDescriptors[i]
        local displayRef = orphan and orphan.displayRef or nil
        if not ownedTextRefs[displayRef] then
            settingsSearchRuntime.attachHelperDescriptorToControlEntry(orderedControlEntries, orphan)
        end
    end

    for i = 1, #orderedControlEntries do
        settingsSearchRuntime.resolveControlEntryTarget(panel, orderedControlEntries[i])
    end

    for key, liveEntry in pairs(panel._paSearchLiveControlEntries or {}) do
        if not seenLiveControlKeys[key] and type(liveEntry) == "table" then
            settingsSearchRuntime.hideSyntheticSearchRowFrame(liveEntry)
            panel._paSearchLiveControlEntries[key] = nil
        end
    end

    for i = 1, #orderedRenderableEntries do
        local entry = settingsSearchRuntime.finalizeRegistryEntry(orderedRenderableEntries[i])
        if entry and entry.labelText ~= "" and entry.haystack ~= "" then
            registry[#registry + 1] = entry
        end
    end

    local dedupedRegistry = {}
    local seenKeys = {}
    local seenSectionNames = {}
    for i = 1, #registry do
        local entry = settingsSearchRuntime.finalizeRegistryEntry(registry[i])
        if entry and entry.labelText ~= "" and entry.haystack ~= "" then
            local labelKey = lowerSettingsSearchText(entry.displayLabel or entry.labelText or "")
            local sectionLabelKey = table.concat({
                lowerSettingsSearchText(entry.sectionKey),
                labelKey,
            }, "|")

            if entry.kind == "section_name" then
                seenSectionNames[sectionLabelKey] = true
            end

            local shouldSkip = false
            if entry.kind == "group_title" and seenSectionNames[sectionLabelKey] == true then
                shouldSkip = true
            end

            local dedupeKey = entry.dedupeKey
            if not shouldSkip and dedupeKey and seenKeys[dedupeKey] then
                shouldSkip = true
            end

            if not shouldSkip then
                if dedupeKey then
                    seenKeys[dedupeKey] = true
                end
                dedupedRegistry[#dedupedRegistry + 1] = entry
            end
        end
    end

    panel._paSearchRegistry = dedupedRegistry
    panel._paSearchRegistryVersion = (tonumber(panel._paSearchRegistryVersion) or 0) + 1
    panel._paSearchRegistryDirty = false
    return dedupedRegistry, true
end

function settingsSearchRuntime.ensurePanelRegistry(panel)
    if not panel or not panel._paSearchSectionKey then
        return nil, false
    end

    local changed = false
    if not panel._initialized and type(panel.EnsureBuilt) == "function" then
        panel._paSearchHiddenBuildInProgress = true
        local ok, err = pcall(panel.EnsureBuilt, panel)
        panel._paSearchHiddenBuildInProgress = nil
        if not ok then
            error(err, 0)
        end
        panel._paSearchHiddenIndexBuilt = true
        if panel._paSearchRealActivationComplete ~= true then
            panel._paSearchRealActivationPending = true
        end
        changed = true
    end

    local needsProvisionalRefresh = panel._paSearchHasProvisionalControlTargets == true
        and panel._paSearchRealActivationComplete == true
    if panel._paSearchRegistryDirty or type(panel._paSearchRegistry) ~= "table" or needsProvisionalRefresh then
        settingsSearchRuntime.rebuildRegistry(panel)
        changed = true
    end

    return panel._paSearchRegistry or {}, changed
end

function settingsSearchRuntime.refreshResolvedTargets(panel)
    if not panel or type(panel._paSearchRegistry) ~= "table" then
        return nil, false
    end

    local changed = false
    for i = 1, #panel._paSearchRegistry do
        local entry = panel._paSearchRegistry[i]
        if type(entry) == "table" and entry.kind == "control" then
            local previousTarget = entry.controlRef
            local previousType = entry._searchTargetType
            local previousScrollY = tonumber(entry.scrollY) or 0
            settingsSearchRuntime.resolveControlEntryTarget(panel, entry)
            if entry.controlRef ~= previousTarget
                or entry._searchTargetType ~= previousType
                or math.abs((tonumber(entry.scrollY) or 0) - previousScrollY) > 0.5
            then
                changed = true
            end
        end
    end

    if changed then
        panel._paSearchRegistryVersion = (tonumber(panel._paSearchRegistryVersion) or 0) + 1
    end
    return panel._paSearchRegistry, changed
end

if PortalAuthority then
    function PortalAuthority:SettingsSearch_MarkPanelDirty(panelOrKey)
        local panel = panelOrKey
        if type(panelOrKey) == "string" then
            panel = getSettingsSearchPanelByKey(panelOrKey)
        end
        if panel then
            panel._paSearchRegistryDirty = true
        end
    end

    function PortalAuthority:SettingsSearch_MarkAllDirty()
        local registry = self.settingsPanelRegistry or {}
        for key, entry in pairs(registry) do
            local panel = entry and entry.panel or nil
            if panel and panel._paSearchSectionKey and key ~= "root" then
                panel._paSearchRegistryDirty = true
            end
        end
    end

    function PortalAuthority:SettingsSearch_EnsurePanelRegistry(sectionKey)
        if self.IsTemporarilyFrozenSettingsSection and self:IsTemporarilyFrozenSettingsSection(sectionKey) then
            -- PA_V213_FREEZE
            return {}, false
        end
        local panel = getSettingsSearchPanelByKey(sectionKey)
        return settingsSearchRuntime.ensurePanelRegistry(panel)
    end

    function PortalAuthority:SettingsSearch_RefreshResolvedTargets(sectionKey)
        if self.IsTemporarilyFrozenSettingsSection and self:IsTemporarilyFrozenSettingsSection(sectionKey) then
            -- PA_V213_FREEZE
            return {}, false
        end
        local panel = getSettingsSearchPanelByKey(sectionKey)
        return settingsSearchRuntime.refreshResolvedTargets(panel)
    end

    function PortalAuthority:SettingsSearch_GetScrollContext(sectionKey)
        if self.IsTemporarilyFrozenSettingsSection and self:IsTemporarilyFrozenSettingsSection(sectionKey) then
            -- PA_V213_FREEZE
            return nil, nil, nil
        end
        local panel = getSettingsSearchPanelByKey(sectionKey)
        if not panel then
            return nil, nil, nil
        end
        return panel, panel._paSearchScrollFrame or panel._paSettingsScrollFrame, panel._paSearchScrollChild or panel._paSettingsScrollChild
    end

    function PortalAuthority:SettingsWindowRegisterSearchScrollFrame(scrollFrame, scrollChild)
        if not scrollFrame or not scrollChild then
            return
        end
        markSettingsWindowVisualOptIn(scrollFrame)
        markSettingsWindowVisualOptIn(scrollChild)
        registerSettingsWindowVisualRefresh(scrollFrame, function(selfScroll)
            local child = selfScroll.GetScrollChild and selfScroll:GetScrollChild() or scrollChild
            local viewportHeight = tonumber(selfScroll.GetHeight and selfScroll:GetHeight()) or 0
            local contentHeight = child and (tonumber(child.GetHeight and child:GetHeight()) or 0) or 0
            settingsScrollRuntime.sync(selfScroll, child, viewportHeight, contentHeight)
        end)
        settingsScrollRuntime.sync(scrollFrame, scrollChild, scrollFrame:GetHeight() or 0, scrollChild:GetHeight() or 0)
    end

    function PortalAuthority:SettingsWindowApplySearchScroll(scrollFrame, scrollChild, value)
        if not scrollFrame or not scrollChild then
            return 0
        end
        if scrollFrame.UpdateScrollChildRect then
            scrollFrame:UpdateScrollChildRect()
        end
        local viewportHeight = tonumber(scrollFrame:GetHeight()) or 0
        local contentHeight = tonumber(scrollChild:GetHeight()) or 0
        local maxScroll = math.max(0, contentHeight - viewportHeight)
        local nextValue = math.max(0, math.min(maxScroll, tonumber(value) or 0))
        scrollFrame._paSkipNextCustomScrollBarHookSync = true
        scrollFrame:SetVerticalScroll(nextValue)
        settingsScrollRuntime.sync(scrollFrame, scrollChild, viewportHeight, contentHeight)
        return nextValue
    end
end

local function isSettingsControlParkedOffscreen(frame)
    if not frame or not frame.GetNumPoints or not frame.GetPoint then
        return false
    end

    local pointCount = tonumber(frame:GetNumPoints()) or 0
    for i = 1, pointCount do
        local _, _, _, x, y = frame:GetPoint(i)
        if type(x) == "number" and type(y) == "number" then
            if x <= -1000 or y <= -1000 then
                return true
            end
        end
    end

    return false
end

local function measureSettingsVisibleContentExtent(scrollChild, objects)
    if not scrollChild or type(objects) ~= "table" then
        return nil
    end

    local function safeFrameMetric(frame, methodName)
        if not frame then
            return nil
        end
        local method = frame[methodName]
        if type(method) ~= "function" then
            return nil
        end
        local ok, value = pcall(method, frame)
        if not ok then
            return nil
        end
        return tonumber(value) or nil
    end

    local rootTop = safeFrameMetric(scrollChild, "GetTop")
    if not rootTop or rootTop <= 0 then
        return nil
    end

    local maxExtent = nil
    for i = 1, #objects do
        local obj = objects[i]
        if obj and obj.GetBottom and (not obj.IsShown or obj:IsShown()) and not isSettingsControlParkedOffscreen(obj) then
            local objBottom = safeFrameMetric(obj, "GetBottom")
            if objBottom and objBottom > 0 then
                local extent = rootTop - objBottom
                if extent >= 0 and extent < 5000 then
                    if not maxExtent or extent > maxExtent then
                        maxExtent = extent
                    end
                end
            end
        end
    end

    return maxExtent
end

local function PA_PerfBegin(scopeName, explicitState)
    if PortalAuthority and PortalAuthority.PerfBegin then
        return PortalAuthority:PerfBegin(scopeName, explicitState)
    end
    return nil, nil
end

local function PA_PerfEnd(scopeName, startedAt, stateLabel)
    if startedAt ~= nil and PortalAuthority and PortalAuthority.PerfEnd then
        PortalAuthority:PerfEnd(scopeName, startedAt, stateLabel)
    end
end

local MAX_LAYOUT_RETRIES = 10
local function refreshWhenSized(frame, callback, attempt)
    if not frame or not callback then
        return
    end

    attempt = attempt or 0
    local width = frame:GetWidth() or 0
    local height = frame:GetHeight() or 0
    if width > 1 and height > 1 then
        callback()
        return
    end

    if attempt >= MAX_LAYOUT_RETRIES then
        callback()
        return
    end

    C_Timer.After(0, function()
        refreshWhenSized(frame, callback, attempt + 1)
    end)
end

local function withPanelHydration(panel, callback)
    if type(callback) ~= "function" then
        return
    end

    if not panel then
        callback()
        return
    end

    panel._paHydratingControls = (tonumber(panel._paHydratingControls) or 0) + 1
    local ok, err = pcall(callback)
    local remaining = (tonumber(panel._paHydratingControls) or 1) - 1
    if remaining > 0 then
        panel._paHydratingControls = remaining
    else
        panel._paHydratingControls = nil
    end
    if not ok then
        error(err, 0)
    end
end

local function isControlHydrating(frame)
    local current = frame
    while current do
        if (tonumber(current._paHydratingControls) or 0) > 0 then
            return true
        end
        current = current.GetParent and current:GetParent() or nil
    end
    return false
end

local function panelHasSizedViewport(frame)
    if not frame then
        return false
    end
    local width = tonumber(frame:GetWidth()) or 0
    local height = tonumber(frame:GetHeight()) or 0
    return width > 1 and height > 1
end

local function ensureSettingsCanvasPanelAnchored(panel)
    local parent = panel and panel.GetParent and panel:GetParent() or nil
    if not panel or not parent then
        return false
    end
    if panel._paAnchorParent ~= parent or not panel._paAnchored then
        panel:ClearAllPoints()
        panel:SetAllPoints(parent)
        panel._paAnchorParent = parent
    end
    panel._paAnchored = true
    return true
end

local SETTINGS_FIRST_OPEN_SHORT_SETTLE_DELAY = 0.05
local SETTINGS_FIRST_OPEN_VALID_KEYS = {
    root = true,
    announcements = true,
    dock = true,
    timers = true,
    interrupt = true,
    combat = true,
    keystone = true,
    profiles = true,
}
local settingsFirstOpenHost = {
    selectionToken = 0,
    selectedKey = nil,
    selectedPanel = nil,
    selectedGeneration = 0,
}
local function normalizeSettingsFirstOpenKey(key)
    if type(key) == "string" and SETTINGS_FIRST_OPEN_VALID_KEYS[key] then
        return key
    end
    return nil
end

local function setSettingsFirstOpenBootstrapActive(key)
    if PortalAuthority and PortalAuthority.SetSettingsBootstrapActive then
        PortalAuthority:SetSettingsBootstrapActive(normalizeSettingsFirstOpenKey(key) or "none")
    end
end

local function getSettingsFirstOpenGeneration(panel)
    return math.max(0, tonumber(panel and panel._paFirstOpenGeneration) or 0)
end

local function getSettingsFirstOpenState(panel)
    return tostring(panel and panel._paFirstOpenState or "idle")
end

local function isSettingsFirstOpenReady(panel)
    return getSettingsFirstOpenState(panel) == "ready"
end

local function isSettingsFirstOpenSettlePending(panel)
    return getSettingsFirstOpenState(panel) == "pending"
end

local function setSelectedSettingsFirstOpenPanel(panel)
    local key = normalizeSettingsFirstOpenKey(panel and panel._settingsFirstOpenKey)
    settingsFirstOpenHost.selectionToken = (tonumber(settingsFirstOpenHost.selectionToken) or 0) + 1
    settingsFirstOpenHost.selectedPanel = panel
    settingsFirstOpenHost.selectedKey = key
    settingsFirstOpenHost.selectedGeneration = getSettingsFirstOpenGeneration(panel)
    return settingsFirstOpenHost.selectionToken
end

local function clearSelectedSettingsFirstOpenPanel(panel)
    if panel and settingsFirstOpenHost.selectedPanel ~= panel then
        return
    end
    settingsFirstOpenHost.selectionToken = (tonumber(settingsFirstOpenHost.selectionToken) or 0) + 1
    settingsFirstOpenHost.selectedPanel = nil
    settingsFirstOpenHost.selectedKey = nil
    settingsFirstOpenHost.selectedGeneration = 0
    setSettingsFirstOpenBootstrapActive("none")
end

local function resetSettingsFirstOpenPanelState(panel)
    if not panel then
        return 0
    end
    local generation = getSettingsFirstOpenGeneration(panel) + 1
    panel._paFirstOpenGeneration = generation
    panel._paFirstOpenState = "idle"
    panel._paFirstOpenSelectionToken = nil
    panel._paFirstOpenSizeReadyConsumed = nil
    panel._paFirstOpenShortSettleQueued = nil
    panel._paFirstOpenImmediateSizeCheckQueued = nil
    if settingsFirstOpenHost.selectedPanel == panel then
        settingsFirstOpenHost.selectedGeneration = generation
        setSettingsFirstOpenBootstrapActive("none")
    end
    return generation
end

local function shouldBailSettingsFirstOpenSettle(panel, generation, selectionToken)
    if not panel then
        return true
    end
    if getSettingsFirstOpenState(panel) ~= "pending" then
        return true
    end
    if getSettingsFirstOpenGeneration(panel) ~= generation then
        return true
    end
    if panel._paSettingsClosing then
        return true
    end
    if not panel.IsShown or not panel:IsShown() then
        return true
    end
    if settingsFirstOpenHost.selectedPanel ~= panel then
        return true
    end
    if settingsFirstOpenHost.selectedKey ~= normalizeSettingsFirstOpenKey(panel._settingsFirstOpenKey) then
        return true
    end
    if (tonumber(settingsFirstOpenHost.selectionToken) or 0) ~= (tonumber(selectionToken) or 0) then
        return true
    end
    if (tonumber(settingsFirstOpenHost.selectedGeneration) or 0) ~= generation then
        return true
    end
    return false
end

local function evaluateSettingsFirstOpenReady(panel)
    if not panel then
        return false
    end
    local predicate = panel._settingsFirstOpenIsReady
    if type(predicate) == "function" then
        local ok, ready = pcall(predicate, panel)
        return ok and ready == true
    end
    return panelHasSizedViewport(panel._settingsFirstOpenSizeTarget or panel._sizingFrame or panel)
end

local function runSettingsFirstOpenRender(panel, reason)
    if not panel then
        return false
    end
    local render = panel._settingsFirstOpenRender
    if type(render) ~= "function" then
        return false
    end
    withPanelHydration(panel, function()
        render(panel, reason or "on_show")
    end)
    return true
end

local function completeSettingsFirstOpenSettle(panel, generation, ready)
    if not panel then
        return false
    end
    if getSettingsFirstOpenState(panel) ~= "pending" then
        return false
    end
    if getSettingsFirstOpenGeneration(panel) ~= generation then
        return false
    end

    panel._paFirstOpenState = ready and "ready" or "idle"
    panel._paFirstOpenGeneration = generation + 1
    panel._paFirstOpenSelectionToken = nil
    panel._paFirstOpenSizeReadyConsumed = nil
    panel._paFirstOpenShortSettleQueued = nil
    panel._paFirstOpenImmediateSizeCheckQueued = nil
    if settingsFirstOpenHost.selectedPanel == panel then
        settingsFirstOpenHost.selectedGeneration = panel._paFirstOpenGeneration
    end
    setSettingsFirstOpenBootstrapActive("none")
    return true
end

local function queueSettingsFirstOpenShortSettle(panel, generation, selectionToken)
    if not panel or panel._paFirstOpenShortSettleQueued then
        return
    end
    panel._paFirstOpenShortSettleQueued = true

    local function run()
        if panel then
            panel._paFirstOpenShortSettleQueued = nil
        end
        if shouldBailSettingsFirstOpenSettle(panel, generation, selectionToken) then
            return
        end

        if not panel._paFirstOpenSizeReadyConsumed then
            local sizeTarget = panel._settingsFirstOpenSizeTarget or panel._sizingFrame or panel
            if panelHasSizedViewport(sizeTarget) then
                panel._paFirstOpenSizeReadyConsumed = true
                runSettingsFirstOpenRender(panel, "size_changed")
                if evaluateSettingsFirstOpenReady(panel) then
                    completeSettingsFirstOpenSettle(panel, generation, true)
                    return
                end
            else
                completeSettingsFirstOpenSettle(panel, generation, false)
                return
            end
        end

        runSettingsFirstOpenRender(panel, "size_changed")
        if evaluateSettingsFirstOpenReady(panel) then
            completeSettingsFirstOpenSettle(panel, generation, true)
            return
        end
        completeSettingsFirstOpenSettle(panel, generation, false)
    end

    if C_Timer and C_Timer.After then
        C_Timer.After(SETTINGS_FIRST_OPEN_SHORT_SETTLE_DELAY, run)
    else
        run()
    end
end

local function handleSettingsFirstOpenSizeReady(panel, reason)
    if not isSettingsFirstOpenSettlePending(panel) then
        return false
    end

    local generation = getSettingsFirstOpenGeneration(panel)
    local selectionToken = tonumber(panel and panel._paFirstOpenSelectionToken) or 0
    if shouldBailSettingsFirstOpenSettle(panel, generation, selectionToken) then
        return false
    end

    local sizeTarget = panel and (panel._settingsFirstOpenSizeTarget or panel._sizingFrame or panel) or nil
    if not panelHasSizedViewport(sizeTarget) then
        return false
    end
    if panel._paFirstOpenSizeReadyConsumed then
        return true
    end

    panel._paFirstOpenSizeReadyConsumed = true
    runSettingsFirstOpenRender(panel, reason or "size_changed")
    if evaluateSettingsFirstOpenReady(panel) then
        completeSettingsFirstOpenSettle(panel, generation, true)
        return true
    end

    queueSettingsFirstOpenShortSettle(panel, generation, selectionToken)
    return true
end

local function queueSettingsFirstOpenImmediateSizeCheck(panel, generation, selectionToken)
    if not panel or panel._paFirstOpenImmediateSizeCheckQueued then
        return
    end
    panel._paFirstOpenImmediateSizeCheckQueued = true

    local function run()
        if panel then
            panel._paFirstOpenImmediateSizeCheckQueued = nil
        end
        if shouldBailSettingsFirstOpenSettle(panel, generation, selectionToken) then
            return
        end

        local sizeTarget = panel and (panel._settingsFirstOpenSizeTarget or panel._sizingFrame or panel) or nil
        if not panelHasSizedViewport(sizeTarget) then
            return
        end

        if panel._paFirstOpenSizeReadyConsumed then
            runSettingsFirstOpenRender(panel, "size_changed")
            if evaluateSettingsFirstOpenReady(panel) then
                completeSettingsFirstOpenSettle(panel, generation, true)
                return
            end
            queueSettingsFirstOpenShortSettle(panel, generation, selectionToken)
            return
        end

        handleSettingsFirstOpenSizeReady(panel, "size_changed")
    end

    if C_Timer and C_Timer.After then
        C_Timer.After(0, run)
    else
        run()
    end
end

local function startSettingsFirstOpenSettle(panel)
    if not panel or type(panel._settingsFirstOpenRender) ~= "function" then
        return false
    end
    if isSettingsFirstOpenReady(panel) then
        return false
    end

    local generation = getSettingsFirstOpenGeneration(panel) + 1
    panel._paFirstOpenGeneration = generation
    panel._paFirstOpenState = "pending"
    panel._paFirstOpenSelectionToken = nil
    panel._paFirstOpenSizeReadyConsumed = nil
    panel._paFirstOpenShortSettleQueued = nil
    panel._paFirstOpenImmediateSizeCheckQueued = nil
    panel._paSettingsClosing = false

    local selectionToken = setSelectedSettingsFirstOpenPanel(panel)
    panel._paFirstOpenSelectionToken = selectionToken
    setSettingsFirstOpenBootstrapActive(panel._settingsFirstOpenKey)

    runSettingsFirstOpenRender(panel, "on_show")
    if evaluateSettingsFirstOpenReady(panel) then
        completeSettingsFirstOpenSettle(panel, generation, true)
        return true
    end

    queueSettingsFirstOpenImmediateSizeCheck(panel, generation, selectionToken)
    queueSettingsFirstOpenShortSettle(panel, generation, selectionToken)
    return true
end

local function shouldSuppressSettingsFirstOpenExternalRefresh(panel)
    return isSettingsFirstOpenSettlePending(panel)
end

local SETTINGS_WINDOW_CHROME_PARK_X = -5000
local SETTINGS_WINDOW_CHROME_PARK_Y = -5000

local function isPanelUsingCustomSettingsWindowHost(panel)
    if not panel or not PortalAuthority or not PortalAuthority.IsSettingsWindowHostEnabled then
        return false
    end
    if not PortalAuthority:IsSettingsWindowHostEnabled() then
        return false
    end
    if panel._paHostedBySettingsWindow == true then
        return true
    end

    local runtime = PortalAuthority._settingsWindowRuntime
    local body = runtime and runtime.body or nil
    if body and panel.GetParent and panel:GetParent() == body then
        return true
    end

    return false
end

local function setSettingsWindowChromeVisible(widget, visible, anchorParent)
    if not widget then
        return
    end

    if visible then
        if widget.Show then
            widget:Show()
        end
        return
    end

    if widget.Hide then
        widget:Hide()
    end
    if widget.ClearAllPoints then
        widget:ClearAllPoints()
    end
    if anchorParent and widget.SetPoint then
        widget:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", SETTINGS_WINDOW_CHROME_PARK_X, SETTINGS_WINDOW_CHROME_PARK_Y)
    end
end

local function refreshSettingsWindowHeaderAccessoryIfHosted(panel)
    if not panel or not isPanelUsingCustomSettingsWindowHost(panel) then
        return
    end
    if PortalAuthority and PortalAuthority.RefreshSettingsWindowHeaderAccessory then
        PortalAuthority:RefreshSettingsWindowHeaderAccessory()
    end
end

local function handleSettingsFirstOpenPanelShow(panel)
    if not panel then
        return false
    end
    panel._paSettingsClosing = false
    if panel._paSearchSectionKey then
        local hadPendingRealActivation = panel._paSearchRealActivationPending == true
        panel._paSearchRealActivationPending = false
        panel._paSearchRealActivationComplete = true
        if hadPendingRealActivation and (panel._paSearchHiddenIndexBuilt == true or panel._paSearchHasProvisionalControlTargets == true) then
            panel._paSearchRegistryDirty = true
        end
    end
    if isSettingsFirstOpenReady(panel) then
        setSelectedSettingsFirstOpenPanel(panel)
        setSettingsFirstOpenBootstrapActive("none")
        return false
    end
    return startSettingsFirstOpenSettle(panel)
end

local function handleSettingsFirstOpenPanelHide(panel)
    if not panel then
        return
    end
    panel._paSettingsClosing = true
    clearSelectedSettingsFirstOpenPanel(panel)
    if isSettingsFirstOpenSettlePending(panel) then
        resetSettingsFirstOpenPanelState(panel)
    end
end

local function refreshPanel(panel)
    if panel and panel._refresh then
        refreshWhenSized(panel._sizingFrame or panel, function()
            if not panel or not panel:IsShown() then
                return
            end
            withPanelHydration(panel, panel._refresh)
        end)
    end
end

local function createScrollableTextArea(parent)
    local container = CreateFrame("Frame", nil, parent)
    container:SetClipsChildren(true)

    local scrollFrame = CreateFrame("ScrollFrame", nil, container, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", container, "TOPLEFT", 6, -6)
    scrollFrame:SetPoint("BOTTOMRIGHT", container, "BOTTOMRIGHT", -26, 6)

    local editBox = CreateFrame("EditBox", nil, scrollFrame)
    editBox:SetAutoFocus(false)
    editBox:SetMultiLine(true)
    editBox:SetWordWrap(true)
    if editBox.SetNonSpaceWrap then
        editBox:SetNonSpaceWrap(true)
    end
    editBox:SetTextInsets(8, 8, 8, 8)
    editBox:SetJustifyH("LEFT")
    editBox:SetJustifyV("TOP")
    editBox:SetWidth(1)
    editBox:SetHeight(1)
    applyGlobalFontToObject(editBox, 12)

    scrollFrame:SetScrollChild(editBox)
    markSettingsWindowVisualOptIn(container)
    markSettingsWindowVisualOptIn(scrollFrame)
    markSettingsWindowVisualOptIn(editBox)
    registerSettingsWindowVisualRefresh(scrollFrame, function(selfScroll)
        local child = selfScroll.GetScrollChild and selfScroll:GetScrollChild() or editBox
        local viewportHeight = tonumber(selfScroll:GetHeight()) or 0
        local contentHeight = child and (tonumber(child:GetHeight()) or 0) or 0
        settingsScrollRuntime.sync(selfScroll, child, viewportHeight, contentHeight)
    end)

    local function updateTextBounds()
        local width = math.max(1, scrollFrame:GetWidth() - 4)
        editBox:SetWidth(width)
        local contentHeight = math.max(scrollFrame:GetHeight(), editBox:GetStringHeight() + 20)
        editBox:SetHeight(contentHeight)
        settingsScrollRuntime.sync(scrollFrame, editBox, scrollFrame:GetHeight() or 0, contentHeight)
    end

    scrollFrame:SetScript("OnSizeChanged", function()
        updateTextBounds()
    end)

    scrollFrame:EnableMouseWheel(true)
    scrollFrame:SetScript("OnMouseWheel", function(frame, delta)
        settingsScrollRuntime.noteFrameInteraction(frame)
        local minScroll, maxScroll = 0, math.max(0, (editBox:GetHeight() or 0) - (frame:GetHeight() or 0))
        local nextScroll = (frame:GetVerticalScroll() or 0) - (delta * 24)
        if nextScroll < minScroll then nextScroll = minScroll end
        if nextScroll > maxScroll then nextScroll = maxScroll end
        frame._paSkipNextCustomScrollBarHookSync = true
        frame:SetVerticalScroll(nextScroll)
        settingsScrollRuntime.sync(frame, editBox, frame:GetHeight() or 0, editBox:GetHeight() or 0)
    end)

    editBox:SetScript("OnTextChanged", function()
        updateTextBounds()
    end)

    container.ScrollFrame = scrollFrame
    container.EditBox = editBox
    container.UpdateLayout = updateTextBounds

    return container
end

local function escapeValue(text)
    return tostring(text):gsub("%%", "%%25"):gsub("|", "%%7C")
end

local function unescapeValue(text)
    return tostring(text):gsub("%%(%x%x)", function(hex)
        return string.char(tonumber(hex, 16) or 0)
    end)
end

local BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
local BASE64_DECODE_MAP = {}
for i = 1, #BASE64_ALPHABET do
    BASE64_DECODE_MAP[BASE64_ALPHABET:sub(i, i)] = i - 1
end

local function base64Encode(input)
    local bytes = { string.byte(input, 1, #input) }
    local out = {}

    for i = 1, #bytes, 3 do
        local b1 = bytes[i] or 0
        local b2 = bytes[i + 1] or 0
        local b3 = bytes[i + 2] or 0
        local n = b1 * 65536 + b2 * 256 + b3

        local c1 = math.floor(n / 262144) % 64
        local c2 = math.floor(n / 4096) % 64
        local c3 = math.floor(n / 64) % 64
        local c4 = n % 64

        out[#out + 1] = BASE64_ALPHABET:sub(c1 + 1, c1 + 1)
        out[#out + 1] = BASE64_ALPHABET:sub(c2 + 1, c2 + 1)
        out[#out + 1] = (i + 1 <= #bytes) and BASE64_ALPHABET:sub(c3 + 1, c3 + 1) or "="
        out[#out + 1] = (i + 2 <= #bytes) and BASE64_ALPHABET:sub(c4 + 1, c4 + 1) or "="
    end

    return table.concat(out)
end

local function base64Decode(input)
    local clean = trim(input)
    if clean == "" or (#clean % 4 ~= 0) then
        return nil, "invalid base64 length"
    end
    if clean:find("[^A-Za-z0-9%+/%=]") then
        return nil, "invalid base64 characters"
    end
    if clean:find("=[^=]") then
        return nil, "invalid base64 padding"
    end

    local out = {}
    for i = 1, #clean, 4 do
        local c1 = clean:sub(i, i)
        local c2 = clean:sub(i + 1, i + 1)
        local c3 = clean:sub(i + 2, i + 2)
        local c4 = clean:sub(i + 3, i + 3)

        local v1 = BASE64_DECODE_MAP[c1]
        local v2 = BASE64_DECODE_MAP[c2]
        local v3 = (c3 == "=") and 0 or BASE64_DECODE_MAP[c3]
        local v4 = (c4 == "=") and 0 or BASE64_DECODE_MAP[c4]
        if v1 == nil or v2 == nil or v3 == nil or v4 == nil then
            return nil, "invalid base64 sequence"
        end

        local n = v1 * 262144 + v2 * 4096 + v3 * 64 + v4
        local b1 = math.floor(n / 65536) % 256
        local b2 = math.floor(n / 256) % 256
        local b3 = n % 256

        out[#out + 1] = string.char(b1)
        if c3 ~= "=" then
            out[#out + 1] = string.char(b2)
        end
        if c4 ~= "=" then
            out[#out + 1] = string.char(b3)
        end
    end

    return table.concat(out)
end

local DOCK_IMPORT_PREFIX = "PA1:"
local DOCK_IMPORT_NUMERIC_LIMITS = {
    dockX = { min = -3000, max = 3000 },
    dockY = { min = -3000, max = 3000 },
    dockIconWidth = { min = 16, max = 128 },
    dockIconHeight = { min = 16, max = 128 },
    dockRowSpacing = { min = 0, max = 40 },
    dockTextIconSpacing = { min = 0, max = 40 },
    dockFontSize = { min = 8, max = 48 },
    dockShadowOffsetX = { min = -10, max = 10 },
    dockShadowOffsetY = { min = -10, max = 10 },
}

local DOCK_IMPORT_STRING_ENUMS = {
    dockOrientation = { VERTICAL = true, HORIZONTAL = true },
    dockVerticalTextSide = { LEFT = true, RIGHT = true },
    dockHorizontalTextPosition = { ABOVE = true, BELOW = true },
    dockTextOutline = { [""] = true, OUTLINE = true, THICKOUTLINE = true },
}

local function getDockSettingValue(key)
    local db = PortalAuthorityDB or {}
    local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
    local value = db[key]
    if value == nil then
        value = defaults[key]
    end
    return value
end

local function encodeDockValue(entry)
    local value = getDockSettingValue(entry.key)
    if entry.type == "boolean" then
        return value and "1" or "0"
    elseif entry.type == "number" then
        return tostring(math.floor(tonumber(value) or 0))
    elseif entry.type == "color" then
        local c = type(value) == "table" and value or { r = 1, g = 0.82, b = 0, a = 1 }
        return string.format("%.3f,%.3f,%.3f,%.3f", c.r or 1, c.g or 0.82, c.b or 0, c.a or 1)
    end
    return escapeValue(value or "")
end

local function decodeDockValue(entry, raw)
    if entry.type == "boolean" then
        if raw == "1" then return true end
        if raw == "0" then return false end
        return nil, "expected boolean"
    elseif entry.type == "number" then
        local n = tonumber(raw)
        if not n then
            return nil, "expected number"
        end
        return math.floor(n)
    elseif entry.type == "color" then
        local r, g, b, a = raw:match("^([^,]+),([^,]+),([^,]+),([^,]+)$")
        r, g, b, a = tonumber(r), tonumber(g), tonumber(b), tonumber(a)
        if not r or not g or not b or not a then
            return nil, "expected color"
        end
        return {
            r = math.max(0, math.min(1, r)),
            g = math.max(0, math.min(1, g)),
            b = math.max(0, math.min(1, b)),
            a = math.max(0, math.min(1, a)),
        }
    end
    return unescapeValue(raw)
end

local function validateDockValue(entry, value)
    if entry.type == "number" then
        local limits = DOCK_IMPORT_NUMERIC_LIMITS[entry.key]
        if limits and (value < limits.min or value > limits.max) then
            return nil, string.format("%s must be between %d and %d.", entry.key, limits.min, limits.max)
        end
    elseif entry.type == "string" then
        local enumSet = DOCK_IMPORT_STRING_ENUMS[entry.key]
        if enumSet and not enumSet[value] then
            return nil, string.format("%s has an unsupported value.", entry.key)
        end
    end
    return value
end

local function serializeDockSettings()
    local parts = {}
    for _, entry in ipairs(DOCK_IMPORT_EXPORT_KEYS) do
        parts[#parts + 1] = string.format("%s=%s", entry.key, encodeDockValue(entry))
    end
    return DOCK_IMPORT_PREFIX .. base64Encode(table.concat(parts, "|"))
end

local function parseDockSettings(text)
    local payload = trim(text)
    if payload == "" then
        return nil, "Import string is empty."
    end

    if payload:sub(1, #DOCK_IMPORT_PREFIX) ~= DOCK_IMPORT_PREFIX then
        return nil, "Missing PA1 prefix."
    end

    local decodedPayload, decodeErr = base64Decode(payload:sub(#DOCK_IMPORT_PREFIX + 1))
    if not decodedPayload then
        return nil, "Invalid encoded payload (" .. decodeErr .. ")."
    end

    local rawMap = {}
    for segment in decodedPayload:gmatch("([^|]+)") do
        local key, raw = segment:match("^([^=]+)=(.*)$")
        if key and DOCK_IMPORT_EXPORT_KEYSET[key] then
            rawMap[key] = raw
        end
    end

    local values = {}
    for _, entry in ipairs(DOCK_IMPORT_EXPORT_KEYS) do
        local raw = rawMap[entry.key]
        local parsedValue

        if raw == nil then
            parsedValue = getDockSettingValue(entry.key)
        else
            local decoded, err = decodeDockValue(entry, raw)
            if err then
                return nil, string.format("Invalid value for %s (%s).", entry.key, err)
            end
            parsedValue = decoded
        end

        local _, err = validateDockValue(entry, parsedValue)
        if err then
            return nil, err
        end

        values[entry.key] = parsedValue
    end

    return values
end

local function applyDockImport(values)
    for _, entry in ipairs(DOCK_IMPORT_EXPORT_KEYS) do
        PortalAuthorityDB[entry.key] = values[entry.key]
    end

    if PortalAuthority.EnsureDB then
        PortalAuthority:EnsureDB()
    end
    if PortalAuthority.UpdateDockMovableState then
        PortalAuthority:UpdateDockMovableState()
    end
    if PortalAuthority.RebuildDock then
        PortalAuthority:RebuildDock()
    end
    if PortalAuthority.ApplyDockPosition then
        PortalAuthority:ApplyDockPosition()
    end
    if InCombatLockdown() then
        if PortalAuthority.QueueDockVisibilityRefresh then
            PortalAuthority:QueueDockVisibilityRefresh()
        end
        return
    end

    if PortalAuthority.UpdateDockVisibility then
        PortalAuthority:UpdateDockVisibility(true)
    elseif PortalAuthority.RefreshDockVisibility then
        PortalAuthority:RefreshDockVisibility(true)
    end
end

local function isRefreshOwnerVisible(owner)
    return owner and owner.IsShown and owner:IsShown() and true or false
end

local refreshCallbacks = {}
local function registerRefreshCallback(fn, owner)
    if type(fn) ~= "function" then
        return
    end
    refreshCallbacks[#refreshCallbacks + 1] = {
        fn = fn,
        owner = owner,
    }
end

local function refreshAllPanels()
    local perfStart, perfState = PA_PerfBegin("options_refresh_all")
    for _, entry in ipairs(refreshCallbacks) do
        local fn = entry and entry.fn or nil
        local owner = entry and entry.owner or nil
        if fn and (not owner or isRefreshOwnerVisible(owner)) then
            fn()
        end
    end
    PA_PerfEnd("options_refresh_all", perfStart, perfState)
end

if PortalAuthority then
    function PortalAuthority:RefreshOptionsPanels()
        refreshAllPanels()
    end
end

local function ensureDatabase()
    if PortalAuthority and PortalAuthority.EnsureDB then
        PortalAuthority:EnsureDB()
    end
end

local function setSettingsControlEnabled(target, enabled)
    if not target then
        return
    end

    local allow = enabled and true or false
    local control = target.control or target

    if target.SetEnabled then
        target:SetEnabled(allow)
    elseif control and control.SetEnabled then
        control:SetEnabled(allow)
    elseif allow and control and control.Enable then
        control:Enable()
    elseif (not allow) and control and control.Disable then
        control:Disable()
    elseif control and control.EnableMouse then
        control:EnableMouse(allow)
    end

    if target.label and target.label.SetAlpha then
        target.label:SetAlpha(allow and 1 or 0.55)
    end
    if control and control.SetAlpha then
        control:SetAlpha(allow and 1 or 0.55)
    end
    if control and control.Text and control.Text.SetAlpha then
        control.Text:SetAlpha(allow and 1 or 0.7)
    end
end

local function setSettingsTextEnabled(fontString, enabled)
    if fontString and fontString.SetAlpha then
        fontString:SetAlpha((enabled and true or false) and 1 or 0.55)
    end
end

local SETTINGS_SECTION_DESCRIPTOR_FLOOR = 11
local SETTINGS_SECTION_DESCRIPTOR_BOTTOM_GAP = 10

local function createSettingsSectionDescriptor(parent, text)
    local fs = createStyledFontString(parent, "ARTWORK", "GameFontHighlightSmall", 11)
    fs:SetText(tostring(text or ""))
    fs:SetTextColor(0.62, 0.64, 0.68, 0.92)
    fs:SetJustifyH("LEFT")
    fs:SetJustifyV("TOP")
    fs:SetWordWrap(true)
    return fs
end

local function layoutSettingsSectionDescriptor(descriptor, parent, left, topY, width)
    if not descriptor then
        return topY
    end
    local measuredWidth = math.max(1, math.floor(tonumber(width) or 0))
    descriptor:ClearAllPoints()
    descriptor:SetPoint("TOPLEFT", parent, "TOPLEFT", left, topY)
    descriptor:SetWidth(measuredWidth)
    local descriptorH = math.max(
        SETTINGS_SECTION_DESCRIPTOR_FLOOR,
        math.ceil(tonumber((descriptor.GetStringHeight and descriptor:GetStringHeight()) or 0) or 0)
    )
    return topY - descriptorH - SETTINGS_SECTION_DESCRIPTOR_BOTTOM_GAP
end

local function createAnnouncementsPanelLegacy()
    local panel = CreateFrame("Frame")
    panel.name = "Announcements"
    debugSettingsLog("create frame:", panel.name)

    panel.EnsureBuilt = function(self)
        debugSettingsLog("EnsureBuilt:", self.name, "initialized=", self._initialized and "true" or "false")
        if self._initialized then
            return
        end
        self._initialized = true
        ensureDatabase()

        local scrollFrame, scrollChild = createScrollableChild(self)
        self._sizingFrame = scrollFrame
        local widgets = {}

        local function helper(text, r, g, b)
            local fs = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
            fs:SetText(text)
            fs:SetJustifyH("LEFT")
            fs:SetTextColor(r or 0.8, g or 0.8, b or 0.8)
            return fs
        end

        local function sectionHeader(text)
            local fs = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormalLarge", 14)
            fs:SetText(string.format("|cffffd100%s|r", text))
            return fs
        end

        widgets.playerHeader = createTopRightHeader(self, -PAGE.PLAYER_HEADER_PAD)
        widgets.header = sectionHeader("Announcements")
        widgets.sectionDescriptor = createSettingsSectionDescriptor(scrollChild, "Customize your utility alerts.")
        widgets.routingHint = helper("Routing: RAID in raids, PARTY in parties.")

        local function createMessageBlock(titleText, enabledKey, textKey, defaultText, showDestinationHelper)
            local block = {}
            block.title = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormal", 12)
            block.title:SetText(titleText)
            block.enabled = createCheckbox(scrollChild, "Enable", enabledKey)
            block.messageLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
            block.messageLabel:SetText("Message")
            block.edit = CreateFrame("EditBox", nil, scrollChild, "InputBoxTemplate")
            block.edit:SetAutoFocus(false)
            block.edit:SetTextInsets(8, 8, 0, 0)
            block.edit:SetText(PortalAuthorityDB[textKey])
            applyGlobalFontToObject(block.edit, 12)

            local function save(box)
                local text = trim(box:GetText())
                if text == "" then text = defaultText end
                PortalAuthorityDB[textKey] = text
                box:SetText(text)
            end
            block.edit:SetScript("OnEnterPressed", function(box) save(box); box:ClearFocus() end)
            block.edit:SetScript("OnEditFocusLost", save)

            if showDestinationHelper then
                block.destinationHint = helper("Use [destination] in your message to insert the destination name.", 1, 0.35, 0.35)
            end

            return block
        end

        local function registerAnnouncementToggleBlockSearch(block)
            if type(block) ~= "table" or not frameIsAlive(block.title) or not frameIsAlive(block.enabled) then
                return nil
            end

            if frameIsAlive(block.enabled.text) then
                settingsSearchRuntime.markSearchTextOrigin(block.enabled.text, "choice_caption", {
                    searchChoiceLabelMode = "suppress_generic",
                })
            end

            local extraRefs = {}
            local function addExtraRef(ref)
                if frameIsAlive(ref) then
                    extraRefs[#extraRefs + 1] = ref
                end
            end

            addExtraRef(block.description)
            addExtraRef(block.destinationHint)
            return settingsSearchRuntime.registerControlText(block.title, block.enabled, "checkbox", extraRefs)
        end

        local function createSummonRequestsBlock()
            local block = {}
            block.title = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormal", 12)
            local warlockOnlyLabel = string.format("|c%sWarlock only|r", getClassHex("WARLOCK"))
            block.title:SetText(string.format("Summon Requests (%s)", warlockOnlyLabel))
            block.enabled = createCheckbox(scrollChild, "Enable", "summonRequestsEnabled")
            block.description = helper("Popup alert for Party, Raid, Whisper, and Battle.net summon asks (e.g., '1', 'sum', 'summon', '123 plz'). It is flexible in understanding intent.", 0.72, 0.72, 0.72)
            block.soundChannel = createDropdown(scrollChild, "Channel |cff7f7f7f(recommended: Master)|r", SUMMON_SOUND_CHANNEL_CHOICES, "summonRequestSoundChannel")
            block.sound = createDynamicDropdown(
                scrollChild,
                "Alert sound |cff7f7f7f(select NONE for visual only)|r",
                function()
                    return getSummonSoundChoices(PortalAuthorityDB and PortalAuthorityDB.summonRequestSound or "")
                end,
                function()
                    return normalizeSoundChoiceValue(PortalAuthorityDB and PortalAuthorityDB.summonRequestSound or "")
                end,
                function(value)
                    PortalAuthorityDB.summonRequestSound = value
                end
            )
            return block
        end

        local function createSummonStoneRequestsBlock()
            local block = {}
            block.title = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormal", 12)
            local warlockOnlyLabel = string.format("|c%sWarlock only|r", getClassHex("WARLOCK"))
            block.title:SetText(string.format("Summon Stone Requests (%s)", warlockOnlyLabel))
            block.enabled = createCheckbox(scrollChild, "Enable", "summonStoneRequestsEnabled")
            block.description = helper("Popup alert for Party, Raid, Whisper, and Battle.net closet requests stone (e.g., 'closet','stone plz').", 0.72, 0.72, 0.72)
            block.soundChannel = createDropdown(scrollChild, "Channel |cff7f7f7f(recommended: Master)|r", SUMMON_SOUND_CHANNEL_CHOICES, "summonStoneRequestSoundChannel")
            block.sound = createDynamicDropdown(
                scrollChild,
                "Alert sound |cff7f7f7f(select NONE for visual only)|r",
                function()
                    return getSummonSoundChoices(PortalAuthorityDB and PortalAuthorityDB.summonStoneRequestSound or "")
                end,
                function()
                    return normalizeSoundChoiceValue(PortalAuthorityDB and PortalAuthorityDB.summonStoneRequestSound or "")
                end,
                function(value)
                    PortalAuthorityDB.summonStoneRequestSound = value
                end
            )
            return block
        end

        widgets.portals = createMessageBlock("Portals", "portalsEnabled", "portalsText", PortalAuthority.defaults.portalsText, true)
        widgets.teleports = createMessageBlock("Teleports", "teleportsEnabled", "teleportsText", PortalAuthority.defaults.teleportsText, true)
        widgets.mplus = createMessageBlock("Mythic+ Teleports", "mplusEnabled", "mplusText", PortalAuthority.defaults.mplusText, true)
        widgets.warlockSummoning = createMessageBlock("Summoning Stone", "warlockSummoningEnabled", "warlockSummoningText", PortalAuthority.defaults.warlockSummoningText)
        if widgets.warlockSummoning and widgets.warlockSummoning.messageLabel then
            widgets.warlockSummoning.messageLabel:SetText("Message")
        end
        widgets.summonRequests = createSummonRequestsBlock()
        widgets.summonStoneRequests = createSummonStoneRequestsBlock()
        registerAnnouncementToggleBlockSearch(widgets.portals)
        registerAnnouncementToggleBlockSearch(widgets.teleports)
        registerAnnouncementToggleBlockSearch(widgets.mplus)
        registerAnnouncementToggleBlockSearch(widgets.warlockSummoning)
        registerAnnouncementToggleBlockSearch(widgets.summonRequests)
        registerAnnouncementToggleBlockSearch(widgets.summonStoneRequests)

        local function layoutCheckboxRow(check, y, checkX, labelX)
            check:ClearAllPoints()
            check:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", checkX, y)
            check.text:ClearAllPoints()
            check.text:SetPoint("LEFT", check, "RIGHT", 10, 0)
            check.text:SetJustifyH("LEFT")
        end

        local function layoutMessageBlock(block, y, contentW, left, right, checkX, labelX, controlX)
            block.title:ClearAllPoints()
            block.title:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", left, y)
            y = y - 18

            layoutCheckboxRow(block.enabled, y, checkX, labelX)

            block.messageLabel:ClearAllPoints()
            block.messageLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", controlX, y)

            y = y - 16
            block.edit:ClearAllPoints()
            block.edit:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", controlX, y)
            block.edit:SetSize(contentW - right - controlX, 22)

            y = y - 27
            if block.destinationHint then
                block.destinationHint:ClearAllPoints()
                block.destinationHint:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", controlX, y)
                block.destinationHint:SetWidth(contentW - right - controlX)
                y = y - 18
            end

            return y - 4
        end

        local function layoutInlineDropdown(spec, x, y, width)
            spec.label:ClearAllPoints()
            spec.label:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", x, y)
            spec.control:ClearAllPoints()
            spec.control:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", x - 20, y - 14)
            UIDropDownMenu_SetWidth(spec.control, width)
        end

        local function layoutSummonRequestsBlock(block, y, contentW, left, right, checkX, labelX, controlX)
            block.title:ClearAllPoints()
            block.title:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", left, y)
            y = y - 18

            layoutCheckboxRow(block.enabled, y, checkX, labelX)

            block.description:ClearAllPoints()
            block.description:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", controlX, y - 2)
            block.description:SetWidth(contentW - controlX - right)
            block.description:SetWordWrap(true)

            y = y - 30
            local gap = 20
            local dropdownWidth = math.max(120, math.floor((contentW - controlX - right - gap) / 2))
            layoutInlineDropdown(block.soundChannel, controlX, y, dropdownWidth)
            layoutInlineDropdown(block.sound, controlX + dropdownWidth + gap, y, dropdownWidth)

            return y - 54
        end

        local function relayout()
            local contentW = math.max(320, scrollFrame:GetWidth() - 24)
            local left, right = 16, 16
            local CHECK_X = left
            local CHECKBOX_WIDTH = 24
            local LABEL_X = CHECK_X + CHECKBOX_WIDTH + 10
            local CONTROL_X = LABEL_X + 88

            scrollChild:SetWidth(contentW)

            widgets.playerHeader:ClearAllPoints()
            widgets.playerHeader:SetPoint("TOPRIGHT", self, "TOPRIGHT", -20, -20)

            local y = -8
            widgets.header:ClearAllPoints(); widgets.header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", left, y)
            y = y - 24
            y = layoutSettingsSectionDescriptor(widgets.sectionDescriptor, scrollChild, left, y, contentW - left - right)

            widgets.routingHint:ClearAllPoints(); widgets.routingHint:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", left, y)
            widgets.routingHint:SetWidth(contentW - left - right)
            y = y - 20
            y = y - 14

            y = layoutMessageBlock(widgets.portals, y, contentW, left, right, CHECK_X, LABEL_X, CONTROL_X)
            y = layoutMessageBlock(widgets.teleports, y, contentW, left, right, CHECK_X, LABEL_X, CONTROL_X)
            y = layoutMessageBlock(widgets.mplus, y, contentW, left, right, CHECK_X, LABEL_X, CONTROL_X)
            y = layoutMessageBlock(widgets.warlockSummoning, y, contentW, left, right, CHECK_X, LABEL_X, CONTROL_X)
            y = layoutSummonRequestsBlock(widgets.summonRequests, y, contentW, left, right, CHECK_X, LABEL_X, CONTROL_X)
            y = layoutSummonRequestsBlock(widgets.summonStoneRequests, y, contentW, left, right, CHECK_X, LABEL_X, CONTROL_X)

            scrollChild:SetHeight(math.max(scrollFrame:GetHeight(), -y + 20))
            updateScrollBehavior(scrollFrame, scrollChild)
        end

        self._refresh = function()
            widgets.portals.enabled:SetChecked(PortalAuthorityDB.portalsEnabled)
            widgets.teleports.enabled:SetChecked(PortalAuthorityDB.teleportsEnabled)
            widgets.mplus.enabled:SetChecked(PortalAuthorityDB.mplusEnabled)
            widgets.warlockSummoning.enabled:SetChecked(PortalAuthorityDB.warlockSummoningEnabled)
            widgets.summonRequests.enabled:SetChecked(PortalAuthorityDB.summonRequestsEnabled)
            widgets.summonRequests.soundChannel.Refresh()
            widgets.summonRequests.sound.Refresh()
            widgets.summonStoneRequests.enabled:SetChecked(PortalAuthorityDB.summonStoneRequestsEnabled)
            widgets.summonStoneRequests.soundChannel.Refresh()
            widgets.summonStoneRequests.sound.Refresh()
            relayout()
        end

        registerRefreshCallback(self._refresh, self)
        scrollFrame:SetScript("OnSizeChanged", relayout)
    end

    panel:SetScript("OnShow", function(self)
        debugSettingsLog("OnShow:", self.name)
        self:EnsureBuilt()
        refreshPanel(self)
    end)

    return panel
end

local function createAnnouncementsPanel()
    local panel = CreateFrame("Frame")
    panel.name = "Announcements"
    panel._paSearchSectionKey = "announcements"
    panel._paSearchSectionName = panel.name
    debugSettingsLog("create frame:", panel.name)
    ensureDatabase()

    panel.EnsureBuilt = function(self)
        debugSettingsLog("EnsureBuilt:", self.name, "initialized=", self._initialized and "true" or "false")
        if self._initialized then
            return
        end
        self._initialized = true
        resetSettingsFirstOpenPanelState(self)
        local panelOwner = self
        settingsSearchRuntime.beginDescriptorCapture(self)

        local scrollFrame, scrollChild = createScrollableChild(self)
        if not scrollFrame or not scrollChild then
            settingsSearchRuntime.endDescriptorCapture(self)
            return
        end
        self._sizingFrame = scrollFrame

        local st = {
            panel = self,
            scrollFrame = scrollFrame,
            scrollChild = scrollChild,
            rows = {},
            rowsById = {},
            cards = {},
            templateRows = {},
            pickerSpecs = {},
            expandedRowId = nil,
        }
        self._annState = st

        local function buildAnnouncementsLayoutTokens()
            return {
                HEADER_LEFT = 16,
                LEFT = 20,
                RIGHT = 20,
                CARD_TO_CARD_GAP = 12,
                CARD_PAD = 10,
                CARD_HEADER_H = 18,
                CARD_HEADER_TO_ROWS_GAP = 8,
                CARD_TITLE_TO_QUALIFIER_GAP = 8,
                CARD_BOTTOM_PAD = 10,
                ROW_GAP = 6,
                ROW_PAD_TOP = 8,
                ROW_PAD_BOTTOM = 8,
                ROW_HEADER_H = 22,
                ROW_HEADER_TO_PREVIEW_GAP = 4,
                ROW_PREVIEW_LINE_H = 12,
                ROW_BODY_TOP_GAP = 8,
                ENABLE_SEGMENT_W = 136,
                CHEVRON_LANE_W = 16,
                CHEVRON_GAP = 8,
                PREVIEW_TO_CHEVRON_GAP = 8,
                PREVIEW_TEST_W = 20,
                PREVIEW_TEST_GAP = 6,
                ACCENT_GUTTER_W = 3,
                TOKEN_CHIP_H = 19,
                TOKEN_CHIP_PAD_X = 6,
                TOKEN_CHIP_TEXT_SLACK = 8,
                TOKEN_CHIP_GAP = 5,
                MESSAGE_EDIT_H = 22,
                TEST_BUTTON_W = 62,
                SOUND_PICKER_MIN_W = 164,
                SUBGROUP_LABEL_H = 13,
                SUBGROUP_TO_CONTENT_GAP = 5,
                SUBGROUP_DIVIDER_GAP_TOP = 8,
                SUBGROUP_DIVIDER_GAP_BOTTOM = 8,
                ROW_TITLE_TO_RIGHT_CLUSTER_GAP = 8,
                INLINE_BODY_CONTROL_GAP = 8,
                SECTION_HEADER_TO_FIRST_CARD_GAP = 6,
                PREVIEW_PREFIX_TO_VALUE_GAP = 4,
                ROW_CONTENT_AFTER_ACCENT_GAP = 6,
                ROW_TITLE_TOP_NUDGE = 2,
                ROW_PREVIEW_TOP_NUDGE = 1,
                ROW_PREVIEW_TEST_TOP_NUDGE = 2,
                ROW_CHEVRON_TOP_NUDGE = 2,
                ROW_HEADER_BAND_EXTRA = 6,
                ROW_EXPANDED_INFO_TOP_GAP = 4,
                FIELD_LABEL_H = 14,
                LABEL_TO_CONTROL_GAP = 3,
                CONTROL_H = 22,
                CONTROL_TO_HINT_GAP = 5,
                HELPER_LINE_H = 12,
                HELPER_TO_CHIP_GAP = 4,
                CHIP_TO_RESET_GAP = 6,
                UNAVAILABLE_HINT_TOP_GAP = 2,
                UNAVAILABLE_HINT_BLOCK_H = 16,
                SECTION_TOP = 20,
                SECTION_HEADER_H = 28,
                SECTION_BOTTOM_PAD = 20,
                MIN_CONTENT_W = 560,
                SCROLL_WIDTH_FUDGE = 8,
                MIN_ROW_W = 120,
                MIN_TITLE_W = 80,
                MIN_BODY_W = 80,
                MIN_PREVIEW_PREFIX_W = 40,
                MAX_PREVIEW_PREFIX_W = 92,
                MIN_PREVIEW_VALUE_W = 20,
                PREVIEW_PREFIX_MEASURE_FALLBACK_W = 42,
                PREVIEW_PREFIX_MEASURE_PAD = 2,
                TOKEN_CHIP_MIN_W = 56,
                DIVIDER_H = 1,
                MIN_CARD_H = 80,
            }
        end

        local T = buildAnnouncementsLayoutTokens()
        local C = T
        local function getCurrentPlayerClass()
            local classFile = nil
            if UnitClass then
                _, classFile = UnitClass("player")
            end
            return tostring(classFile or "")
        end

        local function isCurrentClass(classFile)
            return getCurrentPlayerClass() == tostring(classFile or "")
        end

        local function helperTone(fs)
            if not fs then
                return
            end
            fs:SetTextColor(0.58, 0.58, 0.58, 0.92)
        end

        local function contextualHelperTone(fs)
            if not fs then
                return
            end
            fs:SetTextColor(0.52, 0.52, 0.54, 0.88)
        end

        local function elevateInteractiveFrame(frame, parent, extraLevel)
            if not frame or not parent or not frame.SetFrameLevel or not parent.GetFrameLevel then
                return
            end
            frame:SetFrameLevel((parent:GetFrameLevel() or 0) + (extraLevel or 5))
        end

        local function setSingleLineEllipsis(fs, fullText, maxWidth)
            if not fs then
                return
            end
            local text = tostring(fullText or "")
            local width = math.max(1, math.floor(tonumber(maxWidth) or 0))
            fs:SetWordWrap(false)
            if fs.SetMaxLines then
                fs:SetMaxLines(1)
            end
            fs:SetWidth(width)
            fs:SetText(text)
            if fs:GetStringWidth() <= width then
                return
            end
            local cut = string.len(text)
            while cut > 0 do
                local candidate = string.sub(text, 1, cut) .. "..."
                fs:SetText(candidate)
                if fs:GetStringWidth() <= width then
                    return
                end
                cut = cut - 1
            end
            fs:SetText("...")
        end

        local announcementsMeasureStrings = {}
        local function getAnnouncementsMeasureString(template, size)
            local key = string.format("%s:%s", tostring(template or ""), tostring(size or ""))
            local fs = announcementsMeasureStrings[key]
            if fs then
                return fs
            end
            fs = scrollChild:CreateFontString(nil, "ARTWORK", template)
            applyGlobalFontToObject(fs, size)
            fs:SetWordWrap(false)
            if fs.SetMaxLines then
                fs:SetMaxLines(1)
            end
            fs:Hide()
            announcementsMeasureStrings[key] = fs
            return fs
        end

        local function measureAnnouncementsSingleLineWidth(text, template, size, floor)
            local fs = getAnnouncementsMeasureString(template, size)
            fs:SetText(tostring(text or ""))
            local measured = math.ceil(tonumber((fs.GetStringWidth and fs:GetStringWidth()) or 0) or 0)
            return math.max(math.floor(tonumber(floor) or 0), measured)
        end

        local function getAnnouncementsEffectiveTextHeight(fs, floor)
            local minimum = math.max(0, math.floor(tonumber(floor) or 0))
            if not fs or not fs.GetStringHeight then
                return minimum
            end
            local measured = math.ceil(tonumber(fs:GetStringHeight() or 0) or 0)
            return math.max(minimum, measured)
        end

        local function getAnnouncementsEffectiveControlHeight(control, floor)
            local minimum = math.max(0, math.floor(tonumber(floor) or 0))
            local measured = 0
            if control and control.GetHeight then
                measured = math.ceil(tonumber(control:GetHeight() or 0) or 0)
            end
            local label = control and control.Text or nil
            if label and label.GetStringHeight then
                measured = math.max(measured, math.ceil(tonumber(label:GetStringHeight() or 0) or 0) + 8)
            end
            return math.max(minimum, measured)
        end

        local function layoutAnnouncementsContainedText(fs, fullText, width, floor)
            if not fs then
                return math.max(0, math.floor(tonumber(floor) or 0))
            end
            setSingleLineEllipsis(fs, fullText, width)
            return getAnnouncementsEffectiveTextHeight(fs, floor)
        end

        local function layoutAnnouncementsContainedButtonText(button, fullText, insetX, floor)
            if not button or not button.Text then
                return getAnnouncementsEffectiveControlHeight(button, floor)
            end
            local padding = math.max(0, math.floor(tonumber(insetX) or 8))
            local textW = math.max(1, math.floor((button:GetWidth() or 0) - (padding * 2)))
            setSingleLineEllipsis(button.Text, fullText, textW)
            return getAnnouncementsEffectiveControlHeight(button, floor)
        end

        local function setAnnouncementsSingleLineWidth(fs, width)
            if not fs then
                return
            end
            fs:SetWordWrap(false)
            if fs.SetMaxLines then
                fs:SetMaxLines(1)
            end
            fs:SetWidth(math.max(1, math.floor(tonumber(width) or 0)))
        end

        local function getAnnouncementsSegmentedHeight(spec, floor)
            local measured = getAnnouncementsEffectiveControlHeight(spec and spec.control or nil, floor)
            for _, btn in ipairs((spec and spec.buttons) or {}) do
                local btnHeight = getAnnouncementsEffectiveControlHeight(btn, floor)
                measured = math.max(measured, btnHeight)
            end
            return math.max(math.floor(tonumber(floor) or 0), measured)
        end

        local function setAnnouncementsSegmentedHeight(spec, height)
            local targetH = math.max(1, math.floor(tonumber(height) or 0))
            if not spec or not spec.control then
                return
            end
            spec.control:SetHeight(targetH)
            for _, btn in ipairs(spec.buttons or {}) do
                btn:SetHeight(targetH)
            end
        end

        local function createSubtleCard(parent)
            local card = CreateFrame("Frame", nil, parent, "BackdropTemplate")
            card:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            card:SetBackdropColor(0.06, 0.07, 0.09, 0.42)
            card:SetBackdropBorderColor(0.20, 0.23, 0.29, 0.50)
            return card
        end

        local function createInterruptCardBody(card)
            local body = CreateFrame("Frame", nil, card)
            body:SetAllPoints(card)
            body:SetFrameStrata(card:GetFrameStrata())
            body:SetFrameLevel((card:GetFrameLevel() or 0) + 1)
            return body
        end

        local function syncInterruptCardBody(card, body)
            if not card or not body then
                return
            end
            body:ClearAllPoints()
            body:SetAllPoints(card)
            body:SetFrameStrata(card:GetFrameStrata())
            body:SetFrameLevel((card:GetFrameLevel() or 0) + 1)
        end

        local function styleMicroChip(button)
            styleSecondaryActionButtonShared(button, {
                baseBg = { 0.09, 0.10, 0.12, 0.90 },
                hoverBg = { 0.12, 0.13, 0.16, 0.94 },
                pressedBg = { 0.07, 0.08, 0.10, 0.95 },
                baseBorder = { 0.20, 0.23, 0.28, 0.56 },
                hoverBorder = { 0.26, 0.29, 0.34, 0.65 },
                pressedBorder = { 0.23, 0.26, 0.31, 0.62 },
                textColor = { 0.74, 0.76, 0.80, 0.96 },
            })
            button:SetHeight(C.TOKEN_CHIP_H)
            if button.Text then
                applyGlobalFontToObject(button.Text, 10)
            end
        end

        local function getTemplateStoredValue(row)
            local value = trim((PortalAuthorityDB and PortalAuthorityDB[row.textKey]) or "")
            if value == "" then
                value = trim(row.defaultText or "")
            end
            return value
        end

        local function normalizeTemplateInput(text)
            local normalized = trim(tostring(text or ""))
            if normalized == "" then
                return nil
            end
            return normalized
        end

        local function resolveSummonSoundLabel(value)
            local selected = normalizeSoundChoiceValue(value)
            for _, option in ipairs(getSummonSoundChoices(value) or {}) do
                if tostring(option.value or "") == tostring(selected or "") then
                    return tostring(option.label or selected)
                end
            end
            if selected == "" or selected == nil then
                return "None"
            end
            return tostring(selected)
        end

        local function previewSummonSoundValue(value)
            if value == nil or value == "" then
                return
            end
            local soundFile = value
            if PortalAuthority and PortalAuthority.GetDeathAlertSoundFile then
                soundFile = PortalAuthority:GetDeathAlertSoundFile(value) or value
            end
            if not soundFile or soundFile == "" then
                return
            end
            if type(soundFile) == "number" and PlaySound then
                PlaySound(soundFile, "Master")
            elseif PlaySoundFile then
                PlaySoundFile(soundFile, "Master")
            end
        end

        local function playCurrentSummonPreview(row)
            if not row or not row.soundKey then
                return
            end
            previewSummonSoundValue(PortalAuthorityDB and PortalAuthorityDB[row.soundKey] or "")
        end

        local function makeEnableSegment(parent, row)
            row._enabledVisualValue = PA_SafeBool((PortalAuthorityDB and PortalAuthorityDB[row.enabledKey]) or false)
            local segmented = createPremiumSegmentedChoice(parent, "", nil, {
                { label = "Disabled", value = false, toggleState = "off" },
                { label = "Enabled", value = true, toggleState = "on" },
            }, function(v)
                local newValue = PA_SafeBool(v)
                row._enabledVisualValue = newValue
                if PortalAuthorityDB then
                    PortalAuthorityDB[row.enabledKey] = newValue
                end
                if row.kind == "template" then
                    st:ClearTemplateBatchFeedback()
                end
                if st.panel and st.panel._refresh then
                    st.panel._refresh()
                end
            end, {
                semantic = "toggle",
                textEllipsis = true,
                normalizeValue = function(v)
                    return PA_SafeBool(v)
                end,
                getValue = function()
                    return PA_SafeBool(row._enabledVisualValue)
                end,
                setValue = function(v)
                    row._enabledVisualValue = PA_SafeBool(v)
                end,
            })
            if segmented and segmented.label then
                segmented.label:SetText("")
                segmented.label:Hide()
            end
            return segmented
        end

        local function registerAnnouncementRowSearch(row, extraRefs)
            if type(row) ~= "table" or not frameIsAlive(row.title) then
                return nil
            end

            local controlRef = row.enabledControl
                or (row.enabled and row.enabled.control)
                or row.container
            local refs = {}
            if type(extraRefs) == "table" then
                for i = 1, #extraRefs do
                    if frameIsAlive(extraRefs[i]) then
                        refs[#refs + 1] = extraRefs[i]
                    end
                end
            end
            return settingsSearchRuntime.registerControlText(
                row.title,
                controlRef,
                "toggle",
                refs,
                row.container
            )
        end

        local function createPickerButton(parent, cfg)
            cfg = type(cfg) == "table" and cfg or {}
            local button = CreateFrame("Button", nil, parent, "BackdropTemplate")
            button:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
            button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
            button:SetHeight(22)
            button:SetWidth(math.max(C.SOUND_PICKER_MIN_W, math.floor(tonumber(cfg.width) or 200)))

            local text = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 11)
            button.Text = text
            text:SetPoint("LEFT", button, "LEFT", 8, 0)
            text:SetPoint("RIGHT", button, "RIGHT", -18, 0)
            text:SetJustifyH("LEFT")
            text:SetTextColor(0.92, 0.92, 0.92, 1)
            text:SetWordWrap(false)
            if text.SetMaxLines then
                text:SetMaxLines(1)
            end

            local caret = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 10)
            caret:SetPoint("RIGHT", button, "RIGHT", -7, 0)
            caret:SetText("v")
            caret:SetTextColor(0.76, 0.76, 0.78, 1)
            button._paSelectEnabled = true

            local picker = CreatePicker(UIParent, {}, function(value)
                if cfg.setter then
                    cfg.setter(value)
                end
                if cfg.onApply then
                    cfg.onApply()
                end
            end, {
                title = tostring(cfg.title or "Select Option"),
                searchHint = tostring(cfg.searchHint or "Search"),
                width = tonumber(cfg.pickerWidth) or 430,
                height = tonumber(cfg.pickerHeight) or 360,
                minHeight = tonumber(cfg.minHeight),
                showSecondary = false,
                useOptionTexturePreview = cfg.useOptionTexturePreview and true or false,
                showClearButton = false,
                noSearch = cfg.noSearch and true or false,
                hideTitle = cfg.hideTitle and true or false,
                hideScrollBar = cfg.hideScrollBar and true or false,
                onOptionRightClick = type(cfg.onOptionRightClick) == "function" and cfg.onOptionRightClick or nil,
            })

            local currentLabel = ""
            local function setLabel(labelText)
                currentLabel = tostring(labelText or "")
                setSingleLineEllipsis(text, currentLabel, math.max(20, (button:GetWidth() or 0) - 26))
            end

            local function applyVisual(hovered)
                applySettingsWindowSelectButtonChrome(
                    button,
                    text,
                    caret,
                    hovered,
                    false,
                    button._paSelectEnabled ~= false,
                    function()
                        if hovered then
                            button:SetBackdropColor(0.16, 0.17, 0.20, 0.95)
                            button:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                            caret:SetTextColor(0.88, 0.88, 0.90, 1)
                        else
                            button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
                            button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                            caret:SetTextColor(0.76, 0.76, 0.78, 1)
                        end
                    end
                )
            end

            local function buildOptions()
                local built = {}
                for _, option in ipairs(cfg.optionsProvider and cfg.optionsProvider() or {}) do
                    local value = option.value
                    if value == nil then
                        value = ""
                    end
                    built[#built + 1] = {
                        value = value,
                        label = tostring(option.label or value),
                        buttonLabel = tostring(option.buttonLabel or option.label or value),
                        secondary = tostring(option.secondary or ""),
                        previewTexturePath = option.previewTexturePath or option.path,
                    }
                end
                if #built == 0 then
                    built[1] = { value = "", label = "None", buttonLabel = "None", secondary = "" }
                end
                return built
            end

            local function resolveSelected(options)
                local selected = tostring(cfg.getter and cfg.getter() or "")
                local labelText = nil
                for _, option in ipairs(options or {}) do
                    if tostring(option.value or "") == selected then
                        labelText = tostring(option.buttonLabel or option.label or selected)
                        break
                    end
                end
                if not labelText then
                    for _, option in ipairs(options or {}) do
                        if tostring(option.value or "") == "" then
                            labelText = tostring(option.buttonLabel or option.label or "None")
                            break
                        end
                    end
                end
                if not labelText then
                    local first = options and options[1] or nil
                    labelText = first and tostring(first.buttonLabel or first.label or "None") or "None"
                end
                return selected, labelText
            end

            local spec = { control = button, picker = picker }
            spec.SetWidth = function(_, width)
                button:SetWidth(math.max(C.SOUND_PICKER_MIN_W, math.floor(tonumber(width) or C.SOUND_PICKER_MIN_W)))
                setLabel(currentLabel)
            end
            spec.SetEnabled = function(_, enabled)
                local allow = enabled and true or false
                button._paSelectEnabled = allow
                button:EnableMouse(allow)
                button:SetAlpha(allow and 1 or 0.55)
                text:SetAlpha(allow and 1 or 0.65)
                caret:SetAlpha(allow and 1 or 0.65)
                applyVisual(false)
            end
            spec.ClosePicker = function()
                if picker and picker.IsShown and picker:IsShown() then
                    picker:Close()
                end
            end
            spec.Refresh = function()
                local options = buildOptions()
                picker:SetOptions(options)
                local selected, selectedLabel = resolveSelected(options)
                picker:SetSelectedValue(selected)
                setLabel(selectedLabel)
            end

            button:SetScript("OnEnter", function()
                applyVisual(true)
            end)
            button:SetScript("OnLeave", function()
                applyVisual(false)
            end)
            button:SetScript("OnClick", function()
                if picker and picker.IsShown and picker:IsShown() then
                    picker:Close()
                    return
                end
                spec:Refresh()
                picker:Open(button)
            end)
            button:HookScript("OnSizeChanged", function()
                setLabel(currentLabel)
            end)
            registerSettingsWindowVisualRefresh(button, function()
                applyVisual(button.IsMouseOver and button:IsMouseOver() or false)
            end)

            spec:Refresh()
            st.pickerSpecs[#st.pickerSpecs + 1] = spec
            return spec
        end

        local function createMessageEdit(parent)
            local edit = CreateFrame("EditBox", nil, parent, "InputBoxTemplate")
            edit:SetAutoFocus(false)
            edit:SetTextInsets(8, 8, 0, 0)
            applyGlobalFontToObject(edit, 12)
            if not edit._paPremiumBg then
                edit._paPremiumBg = edit:CreateTexture(nil, "BACKGROUND")
                edit._paPremiumBg:SetAllPoints(edit)
                edit._paPremiumBg:SetTexture("Interface\\Buttons\\WHITE8x8")
                edit._paPremiumBorder = CreateFrame("Frame", nil, edit, "BackdropTemplate")
                edit._paPremiumBorder:SetPoint("TOPLEFT", edit, "TOPLEFT", -1, 1)
                edit._paPremiumBorder:SetPoint("BOTTOMRIGHT", edit, "BOTTOMRIGHT", 1, -1)
                edit._paPremiumBorder:SetBackdrop({ edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1 })
            end

            local function refreshVisual()
                if edit.Left then edit.Left:SetAlpha(0) end
                if edit.Middle then edit.Middle:SetAlpha(0) end
                if edit.Right then edit.Right:SetAlpha(0) end
                if edit:HasFocus() then
                    edit._paPremiumBg:SetVertexColor(0.12, 0.13, 0.17, 0.95)
                    edit._paPremiumBorder:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                else
                    edit._paPremiumBg:SetVertexColor(0.10, 0.11, 0.14, 0.95)
                    edit._paPremiumBorder:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                end
            end
            edit:HookScript("OnShow", refreshVisual)
            edit:HookScript("OnEditFocusGained", refreshVisual)
            edit:HookScript("OnEditFocusLost", refreshVisual)
            refreshVisual()
            return edit
        end

        local header = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormalLarge", 14)
        header:SetText("|cffffd100Announcements|r")
        header:SetJustifyH("LEFT")
        header:SetWordWrap(false)
        if header.SetMaxLines then
            header:SetMaxLines(1)
        end
        st.header = header
        st.sectionDescriptor = createSettingsSectionDescriptor(scrollChild, "Customize your utility alerts.")
        st.playerHeader = createTopRightHeader(self, -20)

        local function createCard(titleText)
            local card = {}
            card.frame = createSubtleCard(scrollChild)
            settingsSearchRuntime.markTextContainer(card.frame)
            card.titleBase = titleText or ""
            card.titleColorCode = nil
            card.title = createStyledFontString(card.frame, "ARTWORK", "GameFontHighlight", 12)
            card.title:SetText(card.titleBase)
            card.title:SetTextColor(1, 0.82, 0, 1)
            card.title:SetJustifyH("LEFT")
            card.title:SetWordWrap(false)
            if card.title.SetMaxLines then
                card.title:SetMaxLines(1)
            end
            card.titleText = card.titleBase
            card.titleQualifierText = ""
            card.titleQualifier = createStyledFontString(card.frame, "ARTWORK", "GameFontHighlight", 12)
            card.titleQualifier:SetText("")
            card.titleQualifier:SetJustifyH("LEFT")
            card.titleQualifier:SetWordWrap(false)
            if card.titleQualifier.SetMaxLines then
                card.titleQualifier:SetMaxLines(1)
            end
            helperTone(card.titleQualifier)
            card.titleQualifier:Hide()
            card.unavailableHint = createStyledFontString(card.frame, "ARTWORK", "GameFontHighlightSmall", 10)
            card.unavailableHintText = "Unavailable on this character."
            card.unavailableHint:SetText(card.unavailableHintText)
            card.unavailableHint:SetJustifyH("CENTER")
            card.unavailableHint:SetWordWrap(false)
            if card.unavailableHint.SetMaxLines then
                card.unavailableHint:SetMaxLines(1)
            end
            helperTone(card.unavailableHint)
            card.unavailableHint:SetAlpha(0.84)
            card.rows = {}
            st.cards[#st.cards + 1] = card
            return card
        end

        local function createRowBase(parent, kind, id, titleText, enabledKey, classLock)
            local row = {
                kind = kind,
                id = id,
                titleText = titleText,
                enabledKey = enabledKey,
                classLock = classLock,
                available = true,
                isExpanded = false,
            }
            row.container = CreateFrame("Frame", nil, parent)
            row.container:SetSize(1, 1)
            row.bg = row.container:CreateTexture(nil, "BACKGROUND")
            row.bg:SetAllPoints(row.container)
            row.bg:SetTexture("Interface\\Buttons\\WHITE8x8")
            row.bg:SetVertexColor(1, 1, 1, 0.02)
            row.border = CreateFrame("Frame", nil, row.container, "BackdropTemplate")
            row.border:SetPoint("TOPLEFT", row.container, "TOPLEFT", 0, 0)
            row.border:SetPoint("BOTTOMRIGHT", row.container, "BOTTOMRIGHT", 0, 0)
            row.border:SetBackdrop({
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
            })
            row.border:SetBackdropBorderColor(0.20, 0.23, 0.29, 0.65)
            row.accent = row.container:CreateTexture(nil, "BORDER")
            row.accent:SetTexture("Interface\\Buttons\\WHITE8x8")
            row.accent:SetPoint("TOPLEFT", row.container, "TOPLEFT", 0, -1)
            row.accent:SetPoint("BOTTOMLEFT", row.container, "BOTTOMLEFT", 0, 1)
            row.accent:SetWidth(C.ACCENT_GUTTER_W)
            if classLock == "MAGE" then
                row._accentColor = { 0.41, 0.80, 0.94 }
            elseif classLock == "WARLOCK" then
                row._accentColor = { 0.58, 0.51, 0.79 }
            else
                row._accentColor = nil
            end
            row.accent:SetVertexColor(1, 1, 1, 0)
            row.headerBandBg = row.container:CreateTexture(nil, "ARTWORK")
            row.headerBandBg:SetTexture("Interface\\Buttons\\WHITE8x8")
            row.headerBandBg:SetVertexColor(0.12, 0.13, 0.16, 0)
            row.headerBandBg:Hide()
            row.headerDivider = row.container:CreateTexture(nil, "ARTWORK")
            row.headerDivider:SetTexture("Interface\\Buttons\\WHITE8x8")
            row.headerDivider:SetVertexColor(0.22, 0.25, 0.30, 0)
            row.headerDivider:Hide()
            row.title = createStyledFontString(row.container, "ARTWORK", "GameFontHighlight", 12)
            row.title:SetJustifyH("LEFT")
            row.title:SetWordWrap(false)
            if row.title.SetMaxLines then
                row.title:SetMaxLines(1)
            end
            row.previewPrefix = createStyledFontString(row.container, "ARTWORK", "GameFontHighlightSmall", 10)
            row.previewPrefix:SetJustifyH("LEFT")
            row.previewPrefix:SetWordWrap(false)
            if row.previewPrefix.SetMaxLines then
                row.previewPrefix:SetMaxLines(1)
            end
            helperTone(row.previewPrefix)
            row.previewValue = createStyledFontString(row.container, "ARTWORK", "GameFontHighlightSmall", 10)
            row.previewValue:SetJustifyH("LEFT")
            row.previewValue:SetWordWrap(false)
            if row.previewValue.SetMaxLines then
                row.previewValue:SetMaxLines(1)
            end
            row.previewValue:SetTextColor(0.72, 0.72, 0.74, 0.94)
            row.collapsedClickCatcher = CreateFrame("Button", nil, row.container)
            row.collapsedClickCatcher:RegisterForClicks("LeftButtonUp")
            row.collapsedClickCatcher:SetFrameLevel((row.container:GetFrameLevel() or 0) + 1)
            row.expandedHeaderClickCatcher = CreateFrame("Button", nil, row.container)
            row.expandedHeaderClickCatcher:RegisterForClicks("LeftButtonUp")
            row.expandedHeaderClickCatcher:SetFrameLevel((row.container:GetFrameLevel() or 0) + 1)
            row.chevron = createStyledFontString(row.container, "ARTWORK", "GameFontHighlightSmall", 12)
            row.chevron:SetText(">")
            row.chevron:SetJustifyH("CENTER")
            row.chevron:SetWordWrap(false)
            row.enabled = makeEnableSegment(row.container, row)
            if row.enabled and row.enabled.Layout then
                row.enabled:Layout(C.ENABLE_SEGMENT_W)
            end
            row.enabledControl = row.enabled and row.enabled.control or nil
            elevateInteractiveFrame(row.enabledControl, row.container)
            row._hoverCount = 0
            row._hovered = false
            row._lastExpanded = false
            row._lastAvailable = true
            row._syncChrome = nil
            local function setRowHover(entering)
                local delta = entering and 1 or -1
                row._hoverCount = math.max(0, (row._hoverCount or 0) + delta)
                row._hovered = row._hoverCount > 0
                if row._syncChrome then
                    row._syncChrome(row)
                end
            end
            row.collapsedClickCatcher:SetScript("OnEnter", function()
                setRowHover(true)
            end)
            row.collapsedClickCatcher:SetScript("OnLeave", function()
                setRowHover(false)
            end)
            row.expandedHeaderClickCatcher:SetScript("OnEnter", function()
                setRowHover(true)
            end)
            row.expandedHeaderClickCatcher:SetScript("OnLeave", function()
                setRowHover(false)
            end)
            st.rows[#st.rows + 1] = row
            st.rowsById[id] = row
            return row
        end

        local function createTemplateRow(parent, cfg)
            local row = createRowBase(parent, "template", cfg.id, cfg.title, cfg.enabledKey, cfg.classLock)
            row.textKey = cfg.textKey
            row.defaultText = cfg.defaultText
            row.showDestinationToken = cfg.showDestinationToken and true or false
            row.previewPrefixText = "Message:"
            row.routingHintText = tostring(cfg.routingHintText or "")
            row.expandedInfoText = tostring(cfg.expandedInfoText or "")
            row.title:SetText(cfg.title or "")
            row.messageLabelText = tostring(cfg.messageLabel or "Message")
            row.messageLabel = createStyledFontString(row.container, "ARTWORK", "GameFontHighlight", 12)
            row.messageLabel:SetText(row.messageLabelText)
            row.messageLabel:SetJustifyH("LEFT")
            row.messageLabel:SetWordWrap(false)
            if row.messageLabel.SetMaxLines then
                row.messageLabel:SetMaxLines(1)
            end
            row.expandedInfo = createStyledFontString(row.container, "ARTWORK", "GameFontHighlightSmall", 10)
            row.expandedInfo:SetText(row.expandedInfoText)
            row.expandedInfo:SetJustifyH("LEFT")
            row.expandedInfo:SetWordWrap(false)
            if row.expandedInfo.SetMaxLines then
                row.expandedInfo:SetMaxLines(1)
            end
            contextualHelperTone(row.expandedInfo)
            row.messageEdit = createMessageEdit(row.container)
            row.messageEdit:SetHeight(C.MESSAGE_EDIT_H)
            elevateInteractiveFrame(row.messageEdit, row.container)
            row.resetButton = createActionButton(row.container, "Reset", nil, 74)
            styleSecondaryActionButtonShared(row.resetButton)
            elevateInteractiveFrame(row.resetButton, row.container)
            row.routingHint = createStyledFontString(row.container, "ARTWORK", "GameFontHighlightSmall", 10)
            row.routingHint:SetJustifyH("LEFT")
            row.routingHint:SetWordWrap(false)
            if row.routingHint.SetMaxLines then
                row.routingHint:SetMaxLines(1)
            end
            helperTone(row.routingHint)
            row.destinationHelper = createStyledFontString(row.container, "ARTWORK", "GameFontHighlightSmall", 10)
            row.destinationHelperText = tostring(cfg.destinationHelperText or "")
            row.destinationHelper:SetText(row.destinationHelperText)
            row.destinationHelper:SetJustifyH("LEFT")
            row.destinationHelper:SetWordWrap(false)
            if row.destinationHelper.SetMaxLines then
                row.destinationHelper:SetMaxLines(1)
            end
            helperTone(row.destinationHelper)
            row.destinationChipText = "[destination]"
            row.destinationChip = createActionButton(row.container, "[destination]", nil, 92)
            styleMicroChip(row.destinationChip)
            elevateInteractiveFrame(row.destinationChip, row.container)
            registerAnnouncementRowSearch(row, {
                row.expandedInfo,
                row.routingHint,
                row.destinationHelper,
            })
            st.templateRows[#st.templateRows + 1] = row
            return row
        end

        local function createSummonRow(parent, cfg)
            local row = createRowBase(parent, "summon", cfg.id, cfg.title, cfg.enabledKey, cfg.classLock)
            row.soundKey = cfg.soundKey
            row.previewPrefixText = "Sound:"
            row.title:SetText(cfg.title or "")
            row.soundLabelText = "Alert Sound"
            row.soundLabel = createStyledFontString(row.container, "ARTWORK", "GameFontHighlight", 12)
            row.soundLabel:SetText(row.soundLabelText)
            row.soundLabel:SetJustifyH("LEFT")
            row.soundLabel:SetWordWrap(false)
            if row.soundLabel.SetMaxLines then
                row.soundLabel:SetMaxLines(1)
            end
            row.soundPicker = createPickerButton(row.container, {
                title = "Select Alert Sound",
                searchHint = "Search sounds",
                width = 220,
                pickerWidth = 470,
                pickerHeight = 390,
                getter = function()
                    return normalizeSoundChoiceValue(PortalAuthorityDB and PortalAuthorityDB[row.soundKey] or "")
                end,
                setter = function(value)
                    if PortalAuthorityDB then
                        PortalAuthorityDB[row.soundKey] = value
                    end
                end,
                optionsProvider = function()
                    return getSummonSoundChoices(PortalAuthorityDB and PortalAuthorityDB[row.soundKey] or "")
                end,
                onOptionRightClick = function(value)
                    previewSummonSoundValue(value)
                end,
                onApply = function()
                    if st.panel and st.panel._refresh then
                        st.panel._refresh()
                    end
                end,
            })
            row.previewTestButton = createActionButton(row.container, "|>", nil, C.PREVIEW_TEST_W)
            styleSecondaryActionButtonShared(row.previewTestButton)
            row.previewTestButton:SetHeight(18)
            elevateInteractiveFrame(row.previewTestButton, row.container)
            row.previewTestButton:SetScript("OnEnter", function(selfBtn)
                GameTooltip:SetOwner(selfBtn, "ANCHOR_RIGHT")
                GameTooltip:SetText("Play test sound", 1, 1, 1)
                GameTooltip:Show()
            end)
            row.previewTestButton:SetScript("OnLeave", function()
                GameTooltip:Hide()
            end)
            row.testButton = createActionButton(row.container, "Test", nil, C.TEST_BUTTON_W)
            styleSecondaryActionButtonShared(row.testButton)
            elevateInteractiveFrame(row.testButton, row.container)
            elevateInteractiveFrame(row.soundPicker and row.soundPicker.control or nil, row.container)
            row.masterHintText = "Audio Channel: Master (locked)"
            row.masterHint = createStyledFontString(row.container, "ARTWORK", "GameFontHighlightSmall", 10)
            row.masterHint:SetText(row.masterHintText)
            row.masterHint:SetJustifyH("LEFT")
            row.masterHint:SetWordWrap(false)
            if row.masterHint.SetMaxLines then
                row.masterHint:SetMaxLines(1)
            end
            helperTone(row.masterHint)
            row.testPlay = cfg.testPlay
            registerAnnouncementRowSearch(row, {
                row.soundLabel,
                row.masterHint,
            })
            return row
        end

        local cardA = createCard("Mythic+ Teleports")
        cardA.titleColorCode = "D9D7D0C4"
        local cardB = createCard("Mage Travel")
        cardB.titleColorCode = "D969CCF0"
        local cardC = createCard("Warlock Summoning")
        cardC.titleColorCode = "D99482C9"
        st.cardA = cardA
        st.cardB = cardB
        st.cardC = cardC
        cardC.subgroupAnnouncements = createStyledFontString(cardC.frame, "ARTWORK", "GameFontHighlightSmall", 10)
        cardC.subgroupAnnouncementsText = "Announcements"
        cardC.subgroupAnnouncements:SetText(cardC.subgroupAnnouncementsText)
        cardC.subgroupAnnouncements:SetJustifyH("LEFT")
        cardC.subgroupAnnouncements:SetWordWrap(false)
        if cardC.subgroupAnnouncements.SetMaxLines then
            cardC.subgroupAnnouncements:SetMaxLines(1)
        end
        cardC.subgroupIncoming = createStyledFontString(cardC.frame, "ARTWORK", "GameFontHighlightSmall", 10)
        cardC.subgroupIncomingText = "Incoming Alerts"
        cardC.subgroupIncoming:SetText(cardC.subgroupIncomingText)
        cardC.subgroupIncoming:SetJustifyH("LEFT")
        cardC.subgroupIncoming:SetWordWrap(false)
        if cardC.subgroupIncoming.SetMaxLines then
            cardC.subgroupIncoming:SetMaxLines(1)
        end
        cardC.subgroupDivider = cardC.frame:CreateTexture(nil, "ARTWORK")
        cardC.subgroupDivider:SetTexture("Interface\\Buttons\\WHITE8x8")
        cardC.subgroupDivider:SetVertexColor(0.20, 0.23, 0.29, 0.56)

        cardA.rows[#cardA.rows + 1] = createTemplateRow(cardA.frame, {
            id = "mplus",
            title = "Mythic+ Teleports",
            enabledKey = "mplusEnabled",
            textKey = "mplusText",
            defaultText = (PortalAuthority.defaults and PortalAuthority.defaults.mplusText) or "Taking M+ teleport to [destination].",
            showDestinationToken = true,
            expandedInfoText = "Uses the teleports enabled in Mythic+ Dock.",
            routingHintText = "Channel: /raid in raids, /party in parties",
        })

        cardB.rows[#cardB.rows + 1] = createTemplateRow(cardB.frame, {
            id = "portals",
            title = "Portals",
            enabledKey = "portalsEnabled",
            textKey = "portalsText",
            defaultText = (PortalAuthority.defaults and PortalAuthority.defaults.portalsText) or "Porting to [destination] - click my portal!",
            showDestinationToken = true,
            routingHintText = "Channel: /raid in raids, /party in parties",
            classLock = "MAGE",
        })
        cardB.rows[#cardB.rows + 1] = createTemplateRow(cardB.frame, {
            id = "teleports",
            title = "Teleports",
            enabledKey = "teleportsEnabled",
            textKey = "teleportsText",
            defaultText = (PortalAuthority.defaults and PortalAuthority.defaults.teleportsText) or "Teleporting to [destination].",
            showDestinationToken = true,
            routingHintText = "Channel: /raid in raids, /party in parties",
            classLock = "MAGE",
        })

        cardC.rows[#cardC.rows + 1] = createTemplateRow(cardC.frame, {
            id = "warlockSummoning",
            title = "Summoning Stone",
            enabledKey = "warlockSummoningEnabled",
            textKey = "warlockSummoningText",
            defaultText = (PortalAuthority.defaults and PortalAuthority.defaults.warlockSummoningText) or "Summoning stone is up - please click.",
            showDestinationToken = false,
            routingHintText = "Channel: /say",
            classLock = "WARLOCK",
            messageLabel = "Message",
        })
        cardC.rows[#cardC.rows + 1] = createSummonRow(cardC.frame, {
            id = "summonRequests",
            title = "Summon Requests",
            enabledKey = "summonRequestsEnabled",
            soundKey = "summonRequestSound",
            classLock = "WARLOCK",
            testPlay = function()
                if PortalAuthority and PortalAuthority.PlaySummonRequestSound then
                    PortalAuthority:PlaySummonRequestSound()
                end
            end,
        })
        cardC.rows[#cardC.rows + 1] = createSummonRow(cardC.frame, {
            id = "summonStoneRequests",
            title = "Summon Stone Requests",
            enabledKey = "summonStoneRequestsEnabled",
            soundKey = "summonStoneRequestSound",
            classLock = "WARLOCK",
            testPlay = function()
                if PortalAuthority and PortalAuthority.PlaySummonStoneRequestSound then
                    PortalAuthority:PlaySummonStoneRequestSound()
                end
            end,
        })

        local function isRowAvailable(row)
            if not row or not row.classLock then
                return true
            end
            if row.classLock == "MAGE" then
                return isCurrentClass("MAGE")
            end
            if row.classLock == "WARLOCK" then
                return isCurrentClass("WARLOCK")
            end
            return true
        end

        st.ClearTemplateBatchFeedback = function()
            -- Batch template actions removed by design.
        end

        local function commitTemplateEdit(row)
            if not row or row.kind ~= "template" then
                return false
            end
            local stored = getTemplateStoredValue(row)
            local candidate = normalizeTemplateInput(row.messageEdit and row.messageEdit:GetText() or "")
            if not candidate then
                if row.messageEdit then
                    row.messageEdit:SetText(stored)
                end
                return false
            end
            if candidate ~= stored then
                if PortalAuthorityDB then
                    PortalAuthorityDB[row.textKey] = candidate
                end
                if row.messageEdit then
                    row.messageEdit:SetText(candidate)
                end
                return true
            end
            if row.messageEdit then
                row.messageEdit:SetText(stored)
            end
            return false
        end

        local function applyExpandedRowState(targetRowId)
            local resolved = nil
            if targetRowId then
                local targetRow = st.rowsById and st.rowsById[targetRowId] or nil
                if targetRow and targetRow.available then
                    resolved = targetRow.id
                end
            end
            st.expandedRowId = resolved
            for _, entry in ipairs(st.rows or {}) do
                entry.isExpanded = (resolved ~= nil and entry.id == resolved) and true or false
            end
        end

        local function commitFocusedExpandedTemplate()
            local row = st.expandedRowId and st.rowsById[st.expandedRowId] or nil
            if not row or row.kind ~= "template" or not row.messageEdit then
                return
            end
            if row.messageEdit.HasFocus and row.messageEdit:HasFocus() then
                st:ClearTemplateBatchFeedback()
                commitTemplateEdit(row)
                row.messageEdit:ClearFocus()
            end
        end

        st.SetExpandedRow = function(targetRowId)
            local nextRowId = targetRowId
            if st.expandedRowId == targetRowId then
                nextRowId = nil
            end
            commitFocusedExpandedTemplate()
            applyExpandedRowState(nextRowId)
            if st.panel and st.panel._refresh then
                st.panel._refresh()
            end
        end
        local function onRowHeaderClick(row)
            if not row or not row.available then
                return
            end
            local willExpand = st.expandedRowId ~= row.id
            if row.kind == "template" then
                st:ClearTemplateBatchFeedback()
                st.pendingFocusRowId = willExpand and row.id or nil
            else
                st.pendingFocusRowId = nil
            end
            st.SetExpandedRow(row.id)
        end

        local function applyRowChrome(row)
            if not row then
                return
            end
            local available = row.available and true or false
            local expanded = row.isExpanded and available
            local hovered = row._hovered and available
            local disabledByUser = available and (not row._enabledVisualValue)
            local rowBgAlpha = 0.02
            local borderR, borderG, borderB, borderA = 0.20, 0.23, 0.29, 0.60
            local accentA = 0
            local headerBandA = 0
            local headerDividerA = 0

            if not available then
                rowBgAlpha = 0.015
                borderA = 0.34
            elseif disabledByUser then
                rowBgAlpha = hovered and 0.028 or 0.018
                borderA = hovered and 0.68 or 0.52
                accentA = hovered and 0.60 or 0.30
            elseif expanded then
                rowBgAlpha = 0.048
                borderR, borderG, borderB, borderA = 0.95, 0.78, 0.24, 0.78
                accentA = 0.95
            elseif hovered then
                rowBgAlpha = 0.034
                borderR, borderG, borderB, borderA = 0.30, 0.33, 0.39, 0.78
                accentA = 0.46
            end

            if expanded then
                if disabledByUser then
                    headerBandA = hovered and 0.07 or 0.055
                    headerDividerA = hovered and 0.38 or 0.30
                else
                    headerBandA = hovered and 0.10 or 0.08
                    headerDividerA = hovered and 0.46 or 0.36
                end
            end

            row.bg:SetVertexColor(1, 1, 1, rowBgAlpha)
            if row.border and row.border.SetBackdropBorderColor then
                row.border:SetBackdropBorderColor(borderR, borderG, borderB, borderA)
            end
            if row.accent then
                if row._accentColor then
                    row.accent:SetVertexColor(row._accentColor[1], row._accentColor[2], row._accentColor[3], accentA)
                else
                    row.accent:SetVertexColor(1, 1, 1, 0)
                end
            end
            if row.headerBandBg then
                row.headerBandBg:SetShown(expanded)
                row.headerBandBg:SetVertexColor(0.12, 0.13, 0.16, headerBandA)
            end
            if row.headerDivider then
                row.headerDivider:SetShown(expanded)
                row.headerDivider:SetVertexColor(0.22, 0.25, 0.30, headerDividerA)
            end
            if row.title then
                if not available then
                    row.title:SetAlpha(0.52)
                elseif disabledByUser then
                    row.title:SetAlpha(hovered and 0.66 or 0.54)
                else
                    row.title:SetAlpha(0.96)
                end
            end
            if row.previewPrefix then
                if not available then
                    row.previewPrefix:SetAlpha(0.50)
                elseif disabledByUser then
                    row.previewPrefix:SetAlpha(hovered and 0.58 or 0.48)
                else
                    row.previewPrefix:SetAlpha(hovered and 0.94 or 0.88)
                end
            end
            if row.previewValue then
                if not available then
                    row.previewValue:SetAlpha(0.56)
                elseif disabledByUser then
                    row.previewValue:SetAlpha(hovered and 0.66 or 0.56)
                else
                    row.previewValue:SetAlpha(hovered and 0.88 or 0.78)
                end
            end
            if row.chevron then
                if not available then
                    row.chevron:SetAlpha(0)
                elseif disabledByUser then
                    row.chevron:SetAlpha(hovered and 0.60 or 0.35)
                else
                    row.chevron:SetAlpha(hovered and 1.0 or 0.55)
                end
            end
            if row.previewTestButton then
                if not available then
                    row.previewTestButton:SetAlpha(0.45)
                else
                    row.previewTestButton:SetAlpha(hovered and 0.96 or 0.86)
                end
            end
        end

        for _, row in ipairs(st.rows or {}) do
            row._syncChrome = applyRowChrome
            row.collapsedClickCatcher:SetScript("OnClick", function()
                onRowHeaderClick(row)
            end)
            row.expandedHeaderClickCatcher:SetScript("OnClick", function()
                onRowHeaderClick(row)
            end)
            if row.kind == "template" then
                row.messageEdit:SetScript("OnEnterPressed", function(box)
                    st:ClearTemplateBatchFeedback()
                    commitTemplateEdit(row)
                    box:ClearFocus()
                    if st.panel and st.panel._refresh then
                        st.panel._refresh()
                    end
                end)
                row.messageEdit:SetScript("OnEditFocusLost", function()
                    st:ClearTemplateBatchFeedback()
                    if commitTemplateEdit(row) and st.panel and st.panel._refresh then
                        st.panel._refresh()
                    end
                end)
                row.resetButton:SetScript("OnClick", function()
                    st:ClearTemplateBatchFeedback()
                    local fallback = trim(row.defaultText or "")
                    if fallback == "" then
                        fallback = getTemplateStoredValue(row)
                    end
                    row.messageEdit:SetText(fallback)
                    if PortalAuthorityDB and fallback ~= getTemplateStoredValue(row) then
                        PortalAuthorityDB[row.textKey] = fallback
                    end
                    if st.panel and st.panel._refresh then
                        st.panel._refresh()
                    end
                end)
                row.destinationChip:SetScript("OnClick", function()
                    st:ClearTemplateBatchFeedback()
                    local token = "[destination]"
                    local current = tostring(row.messageEdit:GetText() or "")
                    local left = row.messageEdit:GetCursorPosition() or string.len(current)
                    left = math.max(0, math.min(left, string.len(current)))
                    local newValue = string.sub(current, 1, left) .. token .. string.sub(current, left + 1)
                    row.messageEdit:SetText(newValue)
                    row.messageEdit:SetCursorPosition(left + string.len(token))
                    row.messageEdit:SetFocus()
                end)
            else
                row.previewTestButton:SetScript("OnClick", function()
                    if row.available then
                        playCurrentSummonPreview(row)
                    end
                end)
                row.testButton:SetScript("OnClick", function()
                    if row.available then
                        playCurrentSummonPreview(row)
                    end
                end)
            end
        end

        local function refreshCardState(card, available, suffixText)
            card.available = available and true or false
            local baseText = tostring(card.titleBase or "")
            if card.titleColorCode then
                baseText = string.format("|c%s%s|r", tostring(card.titleColorCode), baseText)
            end
            local qualifierText = ""
            if (not card.available) and tostring(suffixText or "") ~= "" then
                qualifierText = tostring(suffixText or "")
            end
            card.titleText = baseText
            card.titleQualifierText = qualifierText
            card.title:SetText(baseText)
            if card.titleQualifier then
                card.titleQualifier:SetText(qualifierText)
                card.titleQualifier:SetShown(qualifierText ~= "")
            end
            for _, row in ipairs(card.rows or {}) do
                row.available = card.available and isRowAvailable(row)
            end
        end

        local function refreshAllCardStates()
            local isMage = isCurrentClass("MAGE")
            local isWarlock = isCurrentClass("WARLOCK")
            refreshCardState(cardA, true, "")
            refreshCardState(cardB, isMage, "Mage only")
            refreshCardState(cardC, isWarlock, "Warlock only")
            applyExpandedRowState(st.expandedRowId)
        end

        local function syncAnnouncementsVisualState()
            for _, row in ipairs(st.rows or {}) do
                row._enabledVisualValue = PA_SafeBool((PortalAuthorityDB and PortalAuthorityDB[row.enabledKey]) or false)
                if row.enabled and row.enabled.Refresh then
                    row.enabled:Refresh()
                end
                if row.enabled and row.enabled.SetEnabled then
                    row.enabled:SetEnabled(row.available)
                end

                local previewValueText
                if row.kind == "template" then
                    previewValueText = getTemplateStoredValue(row)
                    if row.messageEdit and not (row.messageEdit.HasFocus and row.messageEdit:HasFocus()) then
                        row.messageEdit:SetText(previewValueText)
                    end
                else
                    previewValueText = resolveSummonSoundLabel((PortalAuthorityDB and PortalAuthorityDB[row.soundKey]) or "")
                    if row.soundPicker and row.soundPicker.Refresh then
                        row.soundPicker:Refresh()
                    end
                end

                row._previewRawText = previewValueText
                row._previewPrefixRawText = tostring(row.previewPrefixText or "Message:")
                if row.previewPrefix then
                    row.previewPrefix:SetText(row._previewPrefixRawText)
                end
                if row.previewValue then
                    row.previewValue:SetText(previewValueText or "")
                end

                row.container:SetAlpha(row.available and 1 or 0.82)
                if (row._lastExpanded ~= row.isExpanded) or (row._lastAvailable ~= row.available) then
                    row._hoverCount = 0
                    row._hovered = false
                end
                row._lastExpanded = row.isExpanded
                row._lastAvailable = row.available

                if row.collapsedClickCatcher then
                    local collapsedActive = row.available and (not row.isExpanded)
                    row.collapsedClickCatcher:SetShown(collapsedActive)
                    row.collapsedClickCatcher:EnableMouse(collapsedActive)
                end
                if row.expandedHeaderClickCatcher then
                    local expandedActive = row.available and row.isExpanded
                    row.expandedHeaderClickCatcher:SetShown(expandedActive)
                    row.expandedHeaderClickCatcher:EnableMouse(expandedActive)
                end
                if row.chevron then
                    row.chevron:SetText(row.isExpanded and "v" or ">")
                    row.chevron:SetShown(row.available)
                end
                if row.previewTestButton then
                    row.previewTestButton:SetEnabled(row.available and (not row.isExpanded))
                end
                if row.testButton then
                    row.testButton:SetEnabled(row.available and row.isExpanded)
                end
                applyRowChrome(row)
            end
        end

        local function applyPendingAnnouncementsFocus()
            local targetRowId = st.pendingFocusRowId
            if not targetRowId then
                return
            end
            local row = st.rowsById and st.rowsById[targetRowId] or nil
            if not row or row.kind ~= "template" or not row.available or not row.isExpanded then
                st.pendingFocusRowId = nil
                return
            end
            if not row.messageEdit or not row.messageEdit.IsShown or not row.messageEdit:IsShown() then
                return
            end
            st.pendingFocusRowId = nil
        end

        self._refresh = function()
            refreshAllCardStates()
            syncAnnouncementsVisualState()
            if panelOwner and panelOwner._layout then
                panelOwner._layout()
            end
            applyPendingAnnouncementsFocus()
        end

        local function computeAnnouncementsGeometry(contentW)
            local cardW = math.max(0, (contentW - T.RIGHT) - T.LEFT)
            local rowW = math.max(T.MIN_ROW_W, cardW - (T.CARD_PAD * 2))
            local rowContentLeft = T.CARD_PAD + T.ACCENT_GUTTER_W + T.ROW_CONTENT_AFTER_ACCENT_GAP
            local rowContentRight = T.CARD_PAD
            local rowEnableX = rowW - rowContentRight - T.ENABLE_SEGMENT_W
            local rowChevronX = rowEnableX - T.CHEVRON_GAP - T.CHEVRON_LANE_W
            return {
                contentLeft = T.LEFT,
                contentRight = T.RIGHT,
                contentSpan = cardW,
                sectionHeaderX = T.HEADER_LEFT,
                sectionHeaderY = -T.SECTION_TOP,
                sectionHeaderW = math.max(T.MIN_TITLE_W, contentW - T.HEADER_LEFT - T.RIGHT),
                cardX = T.LEFT,
                cardW = cardW,
                cardTitleW = math.max(T.MIN_TITLE_W, cardW - (T.CARD_PAD * 2)),
                cardContentLeft = rowContentLeft,
                cardContentRight = rowContentRight,
                cardContentW = math.max(T.MIN_BODY_W, cardW - rowContentLeft - rowContentRight),
                rowX = T.CARD_PAD,
                rowW = rowW,
                rowContentLeft = rowContentLeft,
                rowContentRight = rowContentRight,
                rowEnableX = rowEnableX,
                rowChevronX = rowChevronX,
                rowBodyLeft = rowContentLeft,
                rowBodyRight = rowContentRight,
                rowBodyW = math.max(T.MIN_BODY_W, rowW - rowContentLeft - rowContentRight),
            }
        end

        local function computeAnnouncementCardHeaderGeometry(card, G)
            local titleRowX = T.CARD_PAD
            local titleRowW = math.max(1, G.cardTitleW)
            local qualifierText = tostring(card.titleQualifierText or "")
            local qualifierVisible = qualifierText ~= ""
            local qualifierMeasuredW = 0
            if qualifierVisible then
                qualifierMeasuredW = measureAnnouncementsSingleLineWidth(qualifierText, "GameFontHighlight", 12, 0)
            end
            local qualifierW = qualifierVisible and math.min(qualifierMeasuredW, math.max(0, titleRowW - 1)) or 0
            local qualifierGap = 0
            if qualifierVisible and qualifierW > 0 and qualifierW < titleRowW then
                qualifierGap = math.min(T.CARD_TITLE_TO_QUALIFIER_GAP, math.max(0, titleRowW - qualifierW - 1))
            end
            local titleW = qualifierVisible and math.max(1, titleRowW - qualifierGap - qualifierW) or titleRowW
            local titleMeasuredW = measureAnnouncementsSingleLineWidth(tostring(card.titleBase or ""), "GameFontHighlight", 12, 0)
            local titleDisplayW = math.min(titleW, math.max(0, titleMeasuredW))
            local qualifierX = titleRowX + titleW
            if qualifierVisible then
                qualifierX = titleRowX + titleDisplayW + qualifierGap
            end
            return {
                titleX = titleRowX,
                titleW = titleW,
                qualifierX = qualifierX,
                qualifierW = qualifierW,
                qualifierVisible = qualifierVisible and qualifierW > 0,
            }
        end

        local function computeAnnouncementRowGeometry(row, G)
            local prefixText = row._previewPrefixRawText or tostring(row.previewPrefixText or "Message:")
            local prefixMeasure = measureAnnouncementsSingleLineWidth(prefixText, "GameFontHighlightSmall", 10, T.PREVIEW_PREFIX_MEASURE_FALLBACK_W)
            local prefixW = math.max(T.MIN_PREVIEW_PREFIX_W, math.min(T.MAX_PREVIEW_PREFIX_W, math.floor(prefixMeasure + T.PREVIEW_PREFIX_MEASURE_PAD)))
            local previewTestX = nil
            if row.kind == "summon" then
                previewTestX = G.rowChevronX - T.PREVIEW_TEST_GAP - T.PREVIEW_TEST_W
            end
            local previewRight = (previewTestX or G.rowChevronX) - T.PREVIEW_TO_CHEVRON_GAP
            local previewValueX = G.rowContentLeft + prefixW + T.PREVIEW_PREFIX_TO_VALUE_GAP
            local soundPickerW = math.max(T.SOUND_PICKER_MIN_W, G.rowBodyW - T.TEST_BUTTON_W - T.INLINE_BODY_CONTROL_GAP)
            return {
                rowTitleX = G.rowContentLeft,
                rowTitleW = math.max(T.MIN_TITLE_W, G.rowChevronX - G.rowContentLeft - T.ROW_TITLE_TO_RIGHT_CLUSTER_GAP),
                rowPreviewPrefixX = G.rowContentLeft,
                rowPreviewPrefixW = prefixW,
                rowPreviewValueX = previewValueX,
                rowPreviewValueW = math.max(T.MIN_PREVIEW_VALUE_W, previewRight - previewValueX),
                rowPreviewTestX = previewTestX,
                soundPickerX = G.rowBodyLeft,
                soundPickerW = soundPickerW,
                testButtonX = G.rowBodyLeft + soundPickerW + T.INLINE_BODY_CONTROL_GAP,
            }
        end

        local function layoutAnnouncementRow(row, y, G)
            local rowG = computeAnnouncementRowGeometry(row, G)

            row.container:ClearAllPoints()
            row.container:SetPoint("TOPLEFT", row.container:GetParent(), "TOPLEFT", G.rowX, y)
            row.container:SetWidth(G.rowW)

            row.title:ClearAllPoints()
            row.title:SetPoint("TOPLEFT", row.container, "TOPLEFT", rowG.rowTitleX, -T.ROW_PAD_TOP - T.ROW_TITLE_TOP_NUDGE)
            local titleH = layoutAnnouncementsContainedText(row.title, row.titleText or "", rowG.rowTitleW, T.ROW_HEADER_H)

            local enableH = T.ROW_HEADER_H
            if row.enabled and row.enabled.Layout then
                row.enabled:Layout(T.ENABLE_SEGMENT_W)
                enableH = getAnnouncementsSegmentedHeight(row.enabled, T.ROW_HEADER_H)
                setAnnouncementsSegmentedHeight(row.enabled, enableH)
            end
            if row.enabledControl then
                row.enabledControl:ClearAllPoints()
                row.enabledControl:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowEnableX, -T.ROW_PAD_TOP)
            else
                enableH = T.ROW_HEADER_H
            end

            row.chevron:ClearAllPoints()
            row.chevron:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowChevronX, -T.ROW_PAD_TOP + T.ROW_CHEVRON_TOP_NUDGE)
            row.chevron:SetWidth(T.CHEVRON_LANE_W)
            local chevronH = getAnnouncementsEffectiveTextHeight(row.chevron, T.ROW_HEADER_H)
            local headerLineH = math.max(T.ROW_HEADER_H, titleH, enableH, chevronH)
            local previewY = T.ROW_PAD_TOP + headerLineH + T.ROW_HEADER_TO_PREVIEW_GAP + T.ROW_PREVIEW_TOP_NUDGE

            row.previewPrefix:ClearAllPoints()
            row.previewPrefix:SetPoint("TOPLEFT", row.container, "TOPLEFT", rowG.rowPreviewPrefixX, -previewY)
            local previewPrefixH = layoutAnnouncementsContainedText(row.previewPrefix, row._previewPrefixRawText or tostring(row.previewPrefixText or "Message:"), rowG.rowPreviewPrefixW, T.ROW_PREVIEW_LINE_H)

            row.previewValue:ClearAllPoints()
            row.previewValue:SetPoint("TOPLEFT", row.container, "TOPLEFT", rowG.rowPreviewValueX, -previewY)
            local previewValueH = layoutAnnouncementsContainedText(row.previewValue, row._previewRawText or "", rowG.rowPreviewValueW, T.ROW_PREVIEW_LINE_H)
            local previewTextLaneH = math.max(T.ROW_PREVIEW_LINE_H, previewPrefixH, previewValueH)
            local previewLineH = previewTextLaneH

            if row.kind == "summon" and row.previewTestButton then
                local previewTestH = getAnnouncementsEffectiveControlHeight(row.previewTestButton, math.max(18, T.ROW_PREVIEW_LINE_H))
                row.previewTestButton:SetHeight(previewTestH)
                previewTestH = layoutAnnouncementsContainedButtonText(row.previewTestButton, "|>", 4, previewTestH)
                if row.isExpanded then
                    row.previewTestButton:Hide()
                else
                    previewLineH = math.max(previewLineH, previewTestH)
                    local previewTestTopY = -(previewY + math.floor((previewTextLaneH - previewTestH) * 0.5))
                    row.previewTestButton:Show()
                    row.previewTestButton:ClearAllPoints()
                    row.previewTestButton:SetPoint("TOPLEFT", row.container, "TOPLEFT", rowG.rowPreviewTestX, previewTestTopY)
                end
            end

            local collapsedH = T.ROW_PAD_TOP + headerLineH + T.ROW_HEADER_TO_PREVIEW_GAP + previewLineH + T.ROW_PAD_BOTTOM
            local headerBandH = T.ROW_PAD_TOP + headerLineH + T.ROW_HEADER_TO_PREVIEW_GAP + previewLineH + T.ROW_HEADER_BAND_EXTRA
            local bodyStartY = T.ROW_PAD_TOP + headerLineH + T.ROW_HEADER_TO_PREVIEW_GAP + previewLineH + T.ROW_BODY_TOP_GAP
            local rowH = collapsedH

            if row.isExpanded and row.available then
                local cursorY = bodyStartY
                if row.kind == "template" then
                    local expandedInfoText = tostring(row.expandedInfoText or "")
                    if expandedInfoText ~= "" and row.expandedInfo then
                        cursorY = cursorY + T.ROW_EXPANDED_INFO_TOP_GAP
                        row.expandedInfo:Show()
                        row.expandedInfo:ClearAllPoints()
                        row.expandedInfo:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowBodyLeft, -cursorY)
                        local expandedInfoH = layoutAnnouncementsContainedText(row.expandedInfo, expandedInfoText, G.rowBodyW, T.HELPER_LINE_H)
                        cursorY = cursorY + expandedInfoH + T.CONTROL_TO_HINT_GAP
                    elseif row.expandedInfo then
                        row.expandedInfo:Hide()
                    end
                    row.messageLabel:Show()
                    row.messageEdit:Show()
                    row.resetButton:Show()
                    row.messageLabel:ClearAllPoints()
                    row.messageLabel:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowBodyLeft, -cursorY)
                    local messageLabelH = layoutAnnouncementsContainedText(row.messageLabel, row.messageLabelText or "", G.rowBodyW, T.FIELD_LABEL_H)
                    cursorY = cursorY + messageLabelH + T.LABEL_TO_CONTROL_GAP

                    local messageEditH = getAnnouncementsEffectiveControlHeight(row.messageEdit, T.MESSAGE_EDIT_H)
                    row.messageEdit:ClearAllPoints()
                    row.messageEdit:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowBodyLeft, -cursorY)
                    row.messageEdit:SetSize(G.rowBodyW, messageEditH)
                    cursorY = cursorY + messageEditH

                    local routingHintText = tostring(row.routingHintText or "")
                    if routingHintText ~= "" then
                        row.routingHint:Show()
                        cursorY = cursorY + T.CONTROL_TO_HINT_GAP
                        row.routingHint:ClearAllPoints()
                        row.routingHint:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowBodyLeft, -cursorY)
                        local routingHintH = layoutAnnouncementsContainedText(row.routingHint, routingHintText, G.rowBodyW, T.HELPER_LINE_H)
                        cursorY = cursorY + routingHintH
                    else
                        row.routingHint:Hide()
                    end

                    if row.showDestinationToken then
                        local destinationHelperText = tostring(row.destinationHelperText or "")
                        local showDestinationHelper = destinationHelperText ~= ""
                        if showDestinationHelper then
                            row.destinationHelper:Show()
                        else
                            row.destinationHelper:Hide()
                        end
                        row.destinationChip:Show()
                        if showDestinationHelper then
                            cursorY = cursorY + T.CONTROL_TO_HINT_GAP
                            row.destinationHelper:ClearAllPoints()
                            row.destinationHelper:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowBodyLeft, -cursorY)
                            local destinationHelperH = layoutAnnouncementsContainedText(row.destinationHelper, destinationHelperText, G.rowBodyW, T.HELPER_LINE_H)
                            cursorY = cursorY + destinationHelperH + T.HELPER_TO_CHIP_GAP
                        else
                            cursorY = cursorY + T.CONTROL_TO_HINT_GAP
                        end

                        local chipTextW = measureAnnouncementsSingleLineWidth(row.destinationChipText or "[destination]", "GameFontHighlightSmall", 10, 0)
                        local chipW = math.max(T.TOKEN_CHIP_MIN_W, math.floor(chipTextW + (T.TOKEN_CHIP_PAD_X * 2) + T.TOKEN_CHIP_TEXT_SLACK))
                        local chipH = getAnnouncementsEffectiveControlHeight(row.destinationChip, T.TOKEN_CHIP_H)
                        row.destinationChip:SetWidth(chipW)
                        row.destinationChip:SetHeight(chipH)
                        chipH = layoutAnnouncementsContainedButtonText(row.destinationChip, row.destinationChipText or "[destination]", T.TOKEN_CHIP_PAD_X, chipH)
                        row.destinationChip:ClearAllPoints()
                        row.destinationChip:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowBodyLeft, -cursorY)
                        cursorY = cursorY + chipH
                    else
                        row.destinationHelper:Hide()
                        row.destinationChip:Hide()
                    end

                    cursorY = cursorY + T.CHIP_TO_RESET_GAP
                    local resetButtonH = getAnnouncementsEffectiveControlHeight(row.resetButton, T.CONTROL_H)
                    row.resetButton:SetHeight(resetButtonH)
                    resetButtonH = layoutAnnouncementsContainedButtonText(row.resetButton, "Reset", 8, resetButtonH)
                    row.resetButton:ClearAllPoints()
                    row.resetButton:SetPoint("TOPRIGHT", row.container, "TOPRIGHT", -G.rowContentRight, -cursorY)
                    cursorY = cursorY + resetButtonH
                    rowH = math.max(collapsedH, cursorY + T.ROW_PAD_BOTTOM)
                else
                    row.soundLabel:Show()
                    if row.soundPicker and row.soundPicker.control then
                        row.soundPicker.control:Show()
                    end
                    row.testButton:Show()
                    row.masterHint:Show()
                    row.soundLabel:ClearAllPoints()
                    row.soundLabel:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowBodyLeft, -cursorY)
                    local soundLabelH = layoutAnnouncementsContainedText(row.soundLabel, row.soundLabelText or "", G.rowBodyW, T.FIELD_LABEL_H)
                    cursorY = cursorY + soundLabelH + T.LABEL_TO_CONTROL_GAP

                    local soundPickerControl = row.soundPicker and row.soundPicker.control or nil
                    local soundPickerH = getAnnouncementsEffectiveControlHeight(soundPickerControl, T.CONTROL_H)
                    local testButtonH = getAnnouncementsEffectiveControlHeight(row.testButton, T.CONTROL_H)
                    row.testButton:SetHeight(testButtonH)
                    testButtonH = layoutAnnouncementsContainedButtonText(row.testButton, "Test", 8, testButtonH)
                    local inlineControlH = math.max(T.CONTROL_H, soundPickerH, testButtonH)
                    if row.soundPicker and row.soundPicker.SetWidth then
                        row.soundPicker:SetWidth(rowG.soundPickerW)
                    end
                    if soundPickerControl then
                        soundPickerControl:SetHeight(inlineControlH)
                        soundPickerControl:ClearAllPoints()
                        soundPickerControl:SetPoint("TOPLEFT", row.container, "TOPLEFT", rowG.soundPickerX, -cursorY)
                    end
                    row.testButton:SetHeight(inlineControlH)
                    layoutAnnouncementsContainedButtonText(row.testButton, "Test", 8, inlineControlH)
                    row.testButton:ClearAllPoints()
                    if soundPickerControl then
                        row.testButton:SetPoint("LEFT", soundPickerControl, "RIGHT", T.INLINE_BODY_CONTROL_GAP, 0)
                    else
                        row.testButton:SetPoint("TOPLEFT", row.container, "TOPLEFT", rowG.testButtonX, -cursorY)
                    end
                    cursorY = cursorY + inlineControlH + T.CONTROL_TO_HINT_GAP

                    row.masterHint:ClearAllPoints()
                    row.masterHint:SetPoint("TOPLEFT", row.container, "TOPLEFT", G.rowBodyLeft, -cursorY)
                    local masterHintH = layoutAnnouncementsContainedText(row.masterHint, row.masterHintText or "", G.rowBodyW, T.HELPER_LINE_H)
                    cursorY = cursorY + masterHintH
                    rowH = math.max(collapsedH, cursorY + T.ROW_PAD_BOTTOM)
                end
            else
                if row.kind == "template" then
                    if row.expandedInfo then
                        row.expandedInfo:Hide()
                    end
                    row.messageLabel:Hide()
                    row.messageEdit:Hide()
                    row.resetButton:Hide()
                    row.routingHint:Hide()
                    row.destinationHelper:Hide()
                    row.destinationChip:Hide()
                else
                    row.soundLabel:Hide()
                    if row.soundPicker and row.soundPicker.control then
                        row.soundPicker.control:Hide()
                    end
                    row.testButton:Hide()
                    row.masterHint:Hide()
                end
            end

            row.container:SetHeight(rowH)
            row.headerBandBg:ClearAllPoints()
            row.headerBandBg:SetPoint("TOPLEFT", row.container, "TOPLEFT", 0, 0)
            row.headerBandBg:SetPoint("TOPRIGHT", row.container, "TOPRIGHT", 0, 0)
            row.headerBandBg:SetHeight(headerBandH)
            row.headerDivider:ClearAllPoints()
            row.headerDivider:SetPoint("TOPLEFT", row.container, "TOPLEFT", 0, -headerBandH)
            row.headerDivider:SetPoint("TOPRIGHT", row.container, "TOPRIGHT", 0, -headerBandH)
            row.headerDivider:SetHeight(T.DIVIDER_H)
            row.collapsedClickCatcher:ClearAllPoints()
            row.collapsedClickCatcher:SetPoint("TOPLEFT", row.container, "TOPLEFT", 0, 0)
            row.collapsedClickCatcher:SetPoint("BOTTOMRIGHT", row.container, "BOTTOMRIGHT", 0, 0)
            row.expandedHeaderClickCatcher:ClearAllPoints()
            row.expandedHeaderClickCatcher:SetPoint("TOPLEFT", row.container, "TOPLEFT", 0, 0)
            row.expandedHeaderClickCatcher:SetPoint("TOPRIGHT", row.container, "TOPRIGHT", 0, 0)
            row.expandedHeaderClickCatcher:SetHeight(headerBandH)
            return y - rowH - T.ROW_GAP
        end

        local function layoutAnnouncementCard(card, y, G)
            card.frame:ClearAllPoints()
            card.frame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", G.cardX, y)
            card.frame:SetWidth(G.cardW)

            local headerG = computeAnnouncementCardHeaderGeometry(card, G)
            card.title:ClearAllPoints()
            card.title:SetPoint("TOPLEFT", card.frame, "TOPLEFT", headerG.titleX, -T.CARD_PAD)
            setAnnouncementsSingleLineWidth(card.title, headerG.titleW)
            card.title:SetText(card.titleText or tostring(card.titleBase or ""))
            local cardTitleH = getAnnouncementsEffectiveTextHeight(card.title, T.CARD_HEADER_H)

            local qualifierH = 0
            if card.titleQualifier then
                card.titleQualifier:ClearAllPoints()
                card.titleQualifier:SetPoint("TOPLEFT", card.frame, "TOPLEFT", headerG.qualifierX, -T.CARD_PAD)
                if headerG.qualifierVisible then
                    qualifierH = layoutAnnouncementsContainedText(card.titleQualifier, card.titleQualifierText or "", headerG.qualifierW, T.CARD_HEADER_H)
                else
                    setAnnouncementsSingleLineWidth(card.titleQualifier, 1)
                end
            end
            local titleRowH = math.max(T.CARD_HEADER_H, cardTitleH, qualifierH)

            local rowY = -(T.CARD_PAD + titleRowH + T.CARD_HEADER_TO_ROWS_GAP)
            if card.available then
                card.unavailableHint:Hide()
            else
                card.unavailableHint:Show()
                card.unavailableHint:ClearAllPoints()
                card.unavailableHint:SetPoint("TOPLEFT", card.frame, "TOPLEFT", T.CARD_PAD, -(T.CARD_PAD + titleRowH + T.UNAVAILABLE_HINT_TOP_GAP))
                local unavailableHintH = layoutAnnouncementsContainedText(card.unavailableHint, card.unavailableHintText or "", G.cardTitleW, T.HELPER_LINE_H)
                local unavailableBlockH = math.max(T.UNAVAILABLE_HINT_BLOCK_H, T.UNAVAILABLE_HINT_TOP_GAP + unavailableHintH)
                rowY = rowY - unavailableBlockH
            end
            local subgroupW = math.max(T.MIN_TITLE_W, G.cardW - G.cardContentLeft - T.CARD_PAD)
            if card == cardC then
                if card.subgroupAnnouncements then
                    card.subgroupAnnouncements:Show()
                    card.subgroupAnnouncements:SetTextColor(0.58, 0.51, 0.79, 0.70)
                    card.subgroupAnnouncements:ClearAllPoints()
                    card.subgroupAnnouncements:SetPoint("TOPLEFT", card.frame, "TOPLEFT", G.cardContentLeft, rowY)
                    local subgroupAnnouncementsH = layoutAnnouncementsContainedText(card.subgroupAnnouncements, card.subgroupAnnouncementsText or "", subgroupW, T.SUBGROUP_LABEL_H)
                    rowY = rowY - subgroupAnnouncementsH - T.SUBGROUP_TO_CONTENT_GAP
                end

                local templateRow = card.rows and card.rows[1] or nil
                local summonRow1 = card.rows and card.rows[2] or nil
                local summonRow2 = card.rows and card.rows[3] or nil
                if templateRow then
                    rowY = layoutAnnouncementRow(templateRow, rowY, G)
                end

                rowY = rowY - T.SUBGROUP_DIVIDER_GAP_TOP
                if card.subgroupDivider then
                    card.subgroupDivider:Show()
                    card.subgroupDivider:ClearAllPoints()
                    card.subgroupDivider:SetPoint("TOPLEFT", card.frame, "TOPLEFT", G.cardContentLeft, rowY)
                    card.subgroupDivider:SetPoint("TOPRIGHT", card.frame, "TOPRIGHT", -T.CARD_PAD, rowY)
                    card.subgroupDivider:SetHeight(T.DIVIDER_H)
                end
                rowY = rowY - T.DIVIDER_H - T.SUBGROUP_DIVIDER_GAP_BOTTOM

                if card.subgroupIncoming then
                    card.subgroupIncoming:Show()
                    card.subgroupIncoming:SetTextColor(0.58, 0.51, 0.79, 0.70)
                    card.subgroupIncoming:ClearAllPoints()
                    card.subgroupIncoming:SetPoint("TOPLEFT", card.frame, "TOPLEFT", G.cardContentLeft, rowY)
                    local subgroupIncomingH = layoutAnnouncementsContainedText(card.subgroupIncoming, card.subgroupIncomingText or "", subgroupW, T.SUBGROUP_LABEL_H)
                    rowY = rowY - subgroupIncomingH - T.SUBGROUP_TO_CONTENT_GAP
                end

                if summonRow1 then
                    rowY = layoutAnnouncementRow(summonRow1, rowY, G)
                end
                if summonRow2 then
                    rowY = layoutAnnouncementRow(summonRow2, rowY, G)
                end
            else
                if card.subgroupAnnouncements then card.subgroupAnnouncements:Hide() end
                if card.subgroupIncoming then card.subgroupIncoming:Hide() end
                if card.subgroupDivider then card.subgroupDivider:Hide() end
                for _, row in ipairs(card.rows or {}) do
                    rowY = layoutAnnouncementRow(row, rowY, G)
                end
            end

            local cardH = math.max(T.MIN_CARD_H, -rowY + T.CARD_BOTTOM_PAD)
            card.frame:SetHeight(cardH)
            return y - cardH - T.CARD_TO_CARD_GAP
        end

        local function layoutAnnouncements()
            if not scrollFrame or not scrollChild then
                return
            end
            local contentW = math.max((scrollFrame:GetWidth() or 0) - T.SCROLL_WIDTH_FUDGE, T.MIN_CONTENT_W)
            scrollChild:SetWidth(contentW)
            local G = computeAnnouncementsGeometry(contentW)
            local useHostedChrome = isPanelUsingCustomSettingsWindowHost(panelOwner)

            st.playerHeader:ClearAllPoints()
            st.playerHeader:SetPoint("TOPRIGHT", panelOwner, "TOPRIGHT", -20, -20)

            local y = -T.SECTION_TOP
            if useHostedChrome then
                y = y - SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE
            end
            if useHostedChrome then
                setSettingsWindowChromeVisible(header, false, scrollChild)
                setSettingsWindowChromeVisible(st.sectionDescriptor, false, scrollChild)
            else
                setSettingsWindowChromeVisible(header, true)
                setSettingsWindowChromeVisible(st.sectionDescriptor, true, scrollChild)
                header:ClearAllPoints()
                header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", G.sectionHeaderX, G.sectionHeaderY)
                setAnnouncementsSingleLineWidth(header, G.sectionHeaderW)
                local sectionHeaderH = getAnnouncementsEffectiveTextHeight(header, T.SECTION_HEADER_H)
                y = y - sectionHeaderH - T.SECTION_HEADER_TO_FIRST_CARD_GAP
                y = layoutSettingsSectionDescriptor(st.sectionDescriptor, scrollChild, G.sectionHeaderX, y, G.sectionHeaderW)
            end
            y = layoutAnnouncementCard(cardA, y, G)
            y = layoutAnnouncementCard(cardB, y, G)
            y = layoutAnnouncementCard(cardC, y, G)

            scrollChild:SetHeight(math.max(scrollFrame:GetHeight(), -y + T.SECTION_BOTTOM_PAD))
            updateScrollBehavior(scrollFrame, scrollChild)
        end

        self._layout = layoutAnnouncements

        registerRefreshCallback(function()
            if shouldSuppressSettingsFirstOpenExternalRefresh(panelOwner) then
                return
            end
            if panelOwner and panelOwner._refresh then
                panelOwner._refresh()
            end
        end, panelOwner)
        scrollFrame:SetScript("OnSizeChanged", function()
            if handleSettingsFirstOpenSizeReady(panelOwner, "size_changed") then
                return
            end
            if shouldSuppressSettingsFirstOpenExternalRefresh(panelOwner) then
                return
            end
            if panelOwner and panelOwner._layout then
                panelOwner._layout()
            end
        end)

        self._settingsFirstOpenKey = "announcements"
        self._settingsFirstOpenSizeTarget = scrollFrame
        self._settingsFirstOpenRender = function(panel)
            if panel and panel._layout then
                panel._layout()
            end
            if panel and panel._refresh then
                panel._refresh()
            end
        end
        self._settingsFirstOpenIsReady = function(panel)
            local state = panel and panel._annState or nil
            local scroll = panel and panel._sizingFrame or nil
            local child = state and state.scrollChild or nil
            local firstRow = state and state.cardA and state.cardA.rows and state.cardA.rows[1] or nil
            local useHostedChrome = isPanelUsingCustomSettingsWindowHost(panel)
            return panelHasSizedViewport(scroll)
                and state ~= nil
                and state.header ~= nil
                and (useHostedChrome or state.header:IsShown())
                and state.cardA ~= nil and state.cardA.frame ~= nil and state.cardA.frame:IsShown()
                and state.cardB ~= nil and state.cardB.frame ~= nil and state.cardB.frame:IsShown()
                and state.cardC ~= nil and state.cardC.frame ~= nil and state.cardC.frame:IsShown()
                and firstRow ~= nil and firstRow.container ~= nil and firstRow.container:IsShown()
                and child ~= nil
                and (tonumber(child:GetHeight()) or 0) >= math.max(tonumber(scroll and scroll:GetHeight()) or 0, 1)
        end
        settingsSearchRuntime.endDescriptorCapture(self)
    end
    panel:SetScript("OnShow", function(selfPanel)
        debugSettingsLog("OnShow:", selfPanel.name)
        ensureSettingsCanvasPanelAnchored(selfPanel)
        selfPanel:EnsureBuilt()
        if not handleSettingsFirstOpenPanelShow(selfPanel) then
            withPanelHydration(selfPanel, function()
                if selfPanel._layout then
                    selfPanel._layout()
                end
                if selfPanel._refresh then
                    selfPanel._refresh()
                end
            end)
        end
    end)

    panel:SetScript("OnHide", function(selfPanel)
        handleSettingsFirstOpenPanelHide(selfPanel)
        local st = selfPanel and selfPanel._annState
        if not st then
            return
        end
        for _, spec in ipairs(st.pickerSpecs or {}) do
            if spec and spec.ClosePicker then
                spec:ClosePicker()
            end
        end
    end)

    return panel
end

local function createDockPanel()
    local panel = CreateFrame("Frame")
    panel.name = "Mythic+ Dock"
    panel._paSearchSectionKey = "dock"
    panel._paSearchSectionName = panel.name
    local DEBUG_XY = false
    local ensureDockPanelAnchored
    local renderDockPanel
    debugSettingsLog("create frame:", panel.name)

    panel.EnsureBuilt = function(self)
        debugSettingsLog("EnsureBuilt:", self.name, "initialized=", self._initialized and "true" or "false")
        if self._initialized and self._layout and self._refresh then
            return
        end
        resetSettingsFirstOpenPanelState(self)
        ensureDatabase()
        settingsSearchRuntime.beginDescriptorCapture(self)

        local scrollFrame, scrollChild = createScrollableChild(self)
        if not scrollFrame or not scrollChild then
            settingsSearchRuntime.endDescriptorCapture(self)
            return
        end
        self._sizingFrame = scrollFrame
        local panelFrame = self
        local widgets, relayout = {}, nil
        local slotRows = {}

        local function safeDockMetric(object, methodName)
            if not object then
                return nil
            end
            local method = object[methodName]
            if type(method) ~= "function" then
                return nil
            end
            local ok, value = pcall(method, object)
            if not ok then
                return nil
            end
            return tonumber(value) or nil
        end

        local function dockNumbersDiffer(a, b)
            a = tonumber(a)
            b = tonumber(b)
            if a == nil or b == nil then
                return a ~= b
            end
            return math.abs(a - b) > 0.5
        end

        local function isDockInteractionVisible()
            return panelFrame
                and panelFrame.IsShown and panelFrame:IsShown()
                and scrollFrame
                and scrollFrame.IsShown and scrollFrame:IsShown()
        end

        local function getDockObservedScrollMax()
            local observed = 0

            local function absorbRange(owner)
                if not owner or type(owner.GetMinMaxValues) ~= "function" then
                    return
                end
                local ok, _, maxValue = pcall(owner.GetMinMaxValues, owner)
                if ok and type(maxValue) == "number" then
                    observed = math.max(observed, maxValue)
                end
            end

            local nativeRange = safeDockMetric(scrollFrame, "GetVerticalScrollRange")
            if nativeRange ~= nil then
                observed = math.max(observed, nativeRange)
            end

            absorbRange(scrollFrame and scrollFrame.ScrollBar or nil)
            absorbRange(scrollFrame and scrollFrame._paCustomScrollBar or nil)
            return observed
        end

        local function getDockFallbackScrollMax()
            local childHeight = safeDockMetric(scrollChild, "GetHeight") or 0
            local frameHeight = safeDockMetric(scrollFrame, "GetHeight") or 0
            return math.max(0, childHeight - frameHeight)
        end

        local function getDockNativeScrollMax()
            if not isDockInteractionVisible() then
                return nil
            end
            local nativeRange = safeDockMetric(scrollFrame, "GetVerticalScrollRange")
            if nativeRange == nil then
                return nil
            end
            nativeRange = math.max(0, nativeRange)
            if nativeRange <= 0 and getDockFallbackScrollMax() > 1 then
                return nil
            end
            return nativeRange
        end

        local function resolveDockCanonicalScrollMax(options)
            options = type(options) == "table" and options or {}
            local passToken = tonumber(panelFrame._dockScrollLayoutPassToken) or 0
            if panelFrame._dockResolvedNativeScrollPassToken == passToken then
                local cachedNativeMax = tonumber(panelFrame._dockResolvedNativeScrollMax)
                if cachedNativeMax ~= nil then
                    return cachedNativeMax, "native"
                end
            end

            local nativeMax = getDockNativeScrollMax()
            if nativeMax ~= nil then
                panelFrame._dockResolvedNativeScrollPassToken = passToken
                panelFrame._dockResolvedNativeScrollMax = nativeMax
                return nativeMax, "native"
            end

            if options.allowFallback == true then
                return getDockFallbackScrollMax(), "fallback"
            end

            return nil, "unavailable"
        end

        local applyDockScrollState
        local function armDockPostRelayoutSync(passToken)
            passToken = tonumber(passToken) or 0
            if passToken <= 0 or not (C_Timer and C_Timer.After) then
                return false
            end
            if panelFrame._dockPendingPostRelayoutSyncPassToken == passToken then
                return false
            end

            panelFrame._dockPendingPostRelayoutSyncPassToken = passToken
            C_Timer.After(0, function()
                if panelFrame._dockPendingPostRelayoutSyncPassToken ~= passToken then
                    return
                end
                panelFrame._dockPendingPostRelayoutSyncPassToken = nil
                if not isDockInteractionVisible() then
                    return
                end
                if (tonumber(panelFrame._dockScrollLayoutPassToken) or 0) ~= passToken then
                    return
                end
                if applyDockScrollState then
                    applyDockScrollState(nil, {
                        allowFallback = false,
                        allowPostRelayoutSync = false,
                    })
                end
            end)
            return true
        end

        local function ensureDockScrollInteractionBindings()
            panelFrame._dockMouseWheelHandler = panelFrame._dockMouseWheelHandler or function(frame, delta)
                local wheelDelta = tonumber(delta) or 0
                if wheelDelta == 0 then
                    return
                end
                if settingsScrollRuntime.closeFloatingControlsForParentScroll(frame) then
                    return
                end
                settingsScrollRuntime.noteFrameInteraction(frame)
                local currentScroll = safeDockMetric(frame, "GetVerticalScroll") or 0
                local nextScroll = currentScroll - (wheelDelta * 40)
                if applyDockScrollState then
                    applyDockScrollState(nextScroll, {
                        allowFallback = false,
                        allowPostRelayoutSync = false,
                    })
                end
            end

            local needsScroll = (safeDockMetric(scrollChild, "GetHeight") or 0) > ((safeDockMetric(scrollFrame, "GetHeight") or 0) + 1)
            scrollFrame:EnableMouseWheel(needsScroll)
            if scrollFrame.GetScript and scrollFrame.SetScript then
                if needsScroll then
                    if scrollFrame:GetScript("OnMouseWheel") ~= panelFrame._dockMouseWheelHandler then
                        scrollFrame:SetScript("OnMouseWheel", panelFrame._dockMouseWheelHandler)
                    end
                elseif scrollFrame:GetScript("OnMouseWheel") ~= nil then
                    scrollFrame:SetScript("OnMouseWheel", nil)
                end
            end
        end

        applyDockScrollState = function(requestedScroll, options)
            options = type(options) == "table" and options or {}
            if panelFrame._dockScrollSyncActive then
                return false
            end

            local maxScroll, maxSource = resolveDockCanonicalScrollMax({
                allowFallback = options.allowFallback == true,
            })
            if maxScroll == nil then
                if options.allowPostRelayoutSync == true then
                    armDockPostRelayoutSync(tonumber(panelFrame._dockScrollLayoutPassToken) or 0)
                end
                return false
            end

            local currentScroll = safeDockMetric(scrollFrame, "GetVerticalScroll") or 0
            local nextScroll = tonumber(requestedScroll)
            if nextScroll == nil then
                nextScroll = currentScroll
            end
            nextScroll = math.max(0, math.min(maxScroll, nextScroll))

            panelFrame._dockScrollSyncActive = true
            local ok = pcall(function()
                if dockNumbersDiffer(currentScroll, nextScroll) and scrollFrame.SetVerticalScroll then
                    scrollFrame._paSkipNextCustomScrollBarHookSync = true
                    scrollFrame:SetVerticalScroll(nextScroll)
                end
                settingsScrollRuntime.sync(
                    scrollFrame,
                    scrollChild,
                    safeDockMetric(scrollFrame, "GetHeight") or 0,
                    safeDockMetric(scrollChild, "GetHeight") or 0
                )
            end)
            panelFrame._dockScrollSyncActive = nil
            if not ok then
                return false
            end

            if maxSource == "native" then
                panelFrame._dockPendingPostRelayoutSyncPassToken = nil
            end
            panelFrame._dockLastCanonicalScrollMax = maxScroll
            panelFrame._dockLastCanonicalScrollSource = maxSource
            panelFrame._dockExpectedScrollMax = getDockFallbackScrollMax()
            panelFrame._dockObservedScrollMax = math.max(getDockObservedScrollMax(), maxScroll)
            return true
        end

        scrollFrame._paCustomScrollAdapter = {
            panelId = "dock",
            resolveCanonicalMax = function(adapterOptions)
                return resolveDockCanonicalScrollMax(adapterOptions)
            end,
            getCurrentValue = function()
                return safeDockMetric(scrollFrame, "GetVerticalScroll") or 0
            end,
            applyValue = function(value, adapterOptions)
                return applyDockScrollState(value, {
                    allowFallback = adapterOptions and adapterOptions.allowFallback == true,
                    allowPostRelayoutSync = adapterOptions and adapterOptions.allowPostRelayoutSync == true,
                })
            end,
        }

        local function sectionHeader(text)
            local fs = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormalLarge", 14)
            fs:SetText(string.format("|cffffd100%s|r", text))
            return fs
        end

        local function buildDockLayoutTokens()
            return {
                PAGE = {
                    MIN_CONTENT_W = 340,
                    SCROLL_WIDTH_FUDGE = 24,
                    LEFT = 16,
                    RIGHT = 16,
                    NARROW_BREAKPOINT = 700,
                    WIDE_COLUMN_GAP = 26,
                    CHECK_LEFT = 20,
                    LABEL_X = 34,
                    CONTROL_X = 202,
                    PLAYER_HEADER_PAD = 20,
                    OFFSCREEN_X = -5000,
                    OFFSCREEN_Y = -5000,
                    BOTTOM_PAD = 20,
                    ROW_H = 24,
                    ROW_GAP = 4,
                    PAIR_ROW_STEP = 30,
                    DROPDOWN_MIN_W = 120,
                    DROPDOWN_MAX_W = 260,
                    NUMERIC_MIN_W = 74,
                    NUMERIC_MAX_W = 120,
                    SLIDER_MIN_W = 120,
                    SLIDER_MAX_W = 220,
                    CONTROL_WIDTH_RIGHT_PAD = 16,
                    SLIDER_WIDTH_RIGHT_PAD = 36,
                    CONTROL_PLACEMENT = {
                        DROPDOWN_X_SHIFT = -16,
                        DROPDOWN_Y_SHIFT = 4,
                        COMPACT_CONTROL_Y_SHIFT = -1,
                        SLIDER_Y_SHIFT = -2,
                        VALUE_TEXT_GAP = 8,
                    },
                },
                TOP_BLOCK = {
                    TOP_PAD = 20,
                    HEADER_LEFT = 16,
                    CONTENT_RIGHT = 20,
                    HEADER_FLOOR = 16,
                    HEADER_BOTTOM_GAP = 14,
                    LABEL_TO_TOGGLE_GAP = 12,
                    TOGGLE_TO_RESET_GAP = 12,
                    LOCK_ROW_FLOOR = 22,
                    HELPER_GAP_RATIO = 0.625,
                    DIVIDER_GAP_RATIO = 1.25,
                    DIVIDER_OFFSET_RATIO = 0.5,
                    PRESET_HEADER_GAP_RATIO = 1.5,
                    LOCK_STACK_NUDGE_Y = -0.5,
                    PRESERVED_HEADER_ADVANCE = 30,
                    LOCK_TOGGLE_MIN_W = 96,
                    LOCK_BUTTON_MIN_TEXT_W = 36,
                    LOCK_BUTTON_PAD_X = 20,
                    LOCK_SEGMENT_INNER_GAP = 4,
                },
                PRESET_AND_TABLE = {
                    LOADOUT_ROW_SHIFT_Y = 8,
                    PRESET_DIVIDER_FALLBACK_GAP = 4,
                    LOADOUT_PRESET_MIN_W = 260,
                    LOADOUT_PRESET_MAX_W = 360,
                    LOADOUT_RIGHT_PAD = 6,
                    MATCH_STATUS_GAP = 2,
                    TABLE_BLOCK_SHIFT_Y = 50,
                    DESTINATION_COLUMN_Y_SHIFT = 40,
                    NAME_SPELL_COLUMNS_Y_SHIFT = 40,
                    RESULT_COLUMN_Y_SHIFT = 46,
                    STATUS_TEXT_Y_SHIFT = 33,
                    SLOT_ENABLE_CHECKBOX_Y_SHIFT = 41,
                    SLOT_HEADER_TEXT_X_SHIFT = 5,
                    TABLE_HEADER_BOTTOM_GAP = 18,
                    SLOT_ENABLE_GAP = 12,
                    SLOT_DEST_MIN_W = 170,
                    SLOT_DEST_RATIO = 0.34,
                    SLOT_NAME_MIN_W = 120,
                    SLOT_SPELL_W = 68,
                    SLOT_RESULT_W = 30,
                    TABLE_COLUMN_GAP = 14,
                    SLOT_ROW_TOP_NUDGE = 2,
                    SLOT_RESULT_TOP_NUDGE = 4,
                    SLOT_ROW_STEP = 34,
                },
                LOWER_SECTIONS = {
                    BLOCK_OFFSET_Y = 30,
                    TABLE_TO_DIVIDER_GAP = 4,
                    DIVIDER_TO_LAYOUT_GAP = 24,
                    SEGMENTED_MIN_W = 220,
                    SEGMENTED_MAX_W = 360,
                    CONTROL_RIGHT_PAD = 12,
                    SLIDER_CONTROL_MIN_W = 162,
                    SLIDER_CONTROL_MAX_W = 230,
                    LAYOUT_STEPPER_MIN_W = 132,
                    LAYOUT_STEPPER_MAX_W = 154,
                    FONT_SIZE_STEPPER_MIN_W = 56,
                    FONT_SIZE_STEPPER_MAX_W = 68,
                    OUTLINE_ROW_MIN_W = 120,
                    OUTLINE_ROW_MAX_W = 150,
                    SECTION_HEADER_STEP = 26,
                    ROW_STEP = 34,
                    WRAP_PRESENT_TIGHTEN = 5,
                    LAYOUT_HINT_TOP_NUDGE = 3,
                    LAYOUT_HINT_STEP = 18,
                    SECTION_GAP_TIGHT = 4,
                    SECTION_GAP_LOOSE = 6,
                    VISIBILITY_DIVIDER_TOP_GAP = 4,
                    VISIBILITY_DIVIDER_STEP = 12,
                    VISIBILITY_BLOCK_SHIFT_Y = 16,
                    VISIBILITY_LABELS_SHIFT_Y = 5,
                    VISIBILITY_HEADER_STEP = 24,
                    FONT_TO_SIZE_GAP = 5,
                    SIZE_TO_SWATCH_GAP = 1,
                    FONT_ROW_CONTROL_MIN_W = 260,
                    FONT_PICKER_MIN_W = 118,
                    FONT_ROW_STEP = 36,
                },
                FIXED_FOOTPRINTS = {
                    SEED_W = 1,
                    LOCK_ROW_SEED_H = 22,
                    LOWER_SECTIONS_SEED_H = 1,
                    RESET_ANCHOR_W = 102,
                    RESET_ANCHOR_H = 22,
                    VISIBILITY_LABEL_SPACER_H = 22,
                    VISIBILITY_SPACER_H = 22,
                    ROW_ENABLE_HOLDER_W = 132,
                    ROW_ENABLE_HOLDER_H = 22,
                    ROW_ENABLE_BUTTON_W = 64,
                    ROW_ENABLE_BUTTON_H = 22,
                    STANDARD_CONTROL_H = 22,
                    DIVIDER_H = 1,
                    FONT_COLOR_SWATCH_SIZE = 16,
                    LAYOUT_STEPPER_SEED_W = 168,
                    LAYOUT_ICON_SLIDER_SEED_W = 260,
                    FONT_PICKER_SEED_W = 180,
                    FONT_SIZE_STEPPER_SEED_W = 168,
                },
            }
        end

        local dockLayoutTokens = buildDockLayoutTokens()
        local PAGE = dockLayoutTokens.PAGE
        local TOP_BLOCK = dockLayoutTokens.TOP_BLOCK
        local PRESET_AND_TABLE = dockLayoutTokens.PRESET_AND_TABLE
        local LOWER_SECTIONS = dockLayoutTokens.LOWER_SECTIONS
        local FIXED_FOOTPRINTS = dockLayoutTokens.FIXED_FOOTPRINTS

        local function rebuildDock()
            if PortalAuthority.RebuildDock then PortalAuthority:RebuildDock() end
            if PortalAuthority.ApplyDockPosition then PortalAuthority:ApplyDockPosition() end
        end

        local function refreshDockVisibility()
            if PortalAuthority.ApplyDockCombatVisibilityDriver then
                PortalAuthority:ApplyDockCombatVisibilityDriver()
            end

            if InCombatLockdown() then
                if PortalAuthority.QueueDockVisibilityRefresh then
                    PortalAuthority:QueueDockVisibilityRefresh()
                end
                return
            end

            if PortalAuthority.UpdateDockVisibility then
                PortalAuthority:UpdateDockVisibility(true)
            elseif PortalAuthority.RefreshDockVisibility then
                PortalAuthority:RefreshDockVisibility(true)
            end
        end

        local function queueDockPanelRefresh()
            if not panel or panel._paDockRefreshQueued then
                return
            end
            panel._paDockRefreshQueued = true
            if C_Timer and C_Timer.After then
                C_Timer.After(0, function()
                    if panel then
                        panel._paDockRefreshQueued = nil
                    end
                    if not panel or not panel.IsShown or not panel:IsShown() or not panel._refresh then
                        return
                    end
                    if isControlHydrating(panel) then
                        return
                    end
                    panel:_refresh()
                end)
                return
            end
            panel._paDockRefreshQueued = nil
            if panel and panel.IsShown and panel:IsShown() and panel._refresh and not isControlHydrating(panel) then
                panel:_refresh()
            end
        end

        local function applyLiveDockXY(x, y)
            if widgets.x and widgets.x.SetValue then
                widgets.x:SetValue(x)
            end
            if widgets.y and widgets.y.SetValue then
                widgets.y:SetValue(y)
            end

            if PortalAuthorityDB.dockX == nil then
                PortalAuthorityDB.dockX = x
            end
            if PortalAuthorityDB.dockY == nil then
                PortalAuthorityDB.dockY = y
            end
        end

        local refreshDockXYDisplay

        refreshDockXYDisplay = function()
            local x, y
            if PortalAuthority and type(PortalAuthority._lastDockX) == "number" and type(PortalAuthority._lastDockY) == "number" then
                x, y = PortalAuthority._lastDockX, PortalAuthority._lastDockY
            else
                x, y = PortalAuthorityDB.dockX or 0, PortalAuthorityDB.dockY or 0
            end

            applyLiveDockXY(x, y)
        end

        widgets.playerHeader = createTopRightHeader(self, -PAGE.PLAYER_HEADER_PAD)
        widgets.header = sectionHeader("Mythic+ Dock")
        widgets.sectionDescriptor = createSettingsSectionDescriptor(scrollChild, "Configure your custom portal layout.")
        widgets.positionLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        widgets.positionLabel:SetText("")
        widgets.positionLabel:SetTextColor(1, 1, 1, 1)

        widgets.lockDockDivider = scrollChild:CreateTexture(nil, "ARTWORK")
        widgets.lockDockDivider:SetColorTexture(0.24, 0.27, 0.32, 0.10)
        widgets.hideDungeonDivider = scrollChild:CreateTexture(nil, "ARTWORK")
        widgets.hideDungeonDivider:SetColorTexture(0.24, 0.27, 0.32, 0.10)
        widgets.visibilityDivider = scrollChild:CreateTexture(nil, "ARTWORK")
        widgets.visibilityDivider:SetColorTexture(0.24, 0.27, 0.32, 0.10)
        widgets.loadoutDivider = scrollChild:CreateTexture(nil, "ARTWORK")
        widgets.loadoutDivider:SetColorTexture(0.24, 0.27, 0.32, 0.10)
        widgets.masterRowContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.masterRowContainer:SetSize(FIXED_FOOTPRINTS.SEED_W, FIXED_FOOTPRINTS.LOCK_ROW_SEED_H)
        widgets.lockRowContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.lockRowContainer:SetSize(FIXED_FOOTPRINTS.SEED_W, FIXED_FOOTPRINTS.LOCK_ROW_SEED_H)
        widgets.lowerSectionsContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.lowerSectionsContainer:SetSize(FIXED_FOOTPRINTS.SEED_W, FIXED_FOOTPRINTS.LOWER_SECTIONS_SEED_H)

        widgets.resetDockAnchor = createActionButton(scrollChild, "Reset Anchor", function()
            PortalAuthorityDB.dockLocked = false
            PortalAuthorityDB.dockX, PortalAuthorityDB.dockY = 0, 0
            if PortalAuthority.ResetDockAnchor then
                PortalAuthority:ResetDockAnchor()
            elseif PortalAuthority.ApplyDockPosition then
                PortalAuthority:ApplyDockPosition()
            end
            if PortalAuthority.UpdateDockMovableState then
                PortalAuthority:UpdateDockMovableState()
            end
            refreshDockVisibility()
            if PortalAuthority and PortalAuthority.dockFrame then
                PortalAuthority.dockFrame:SetFrameStrata("HIGH")
                PortalAuthority.dockFrame:Raise()
                if PortalAuthority.dockDragHandle then
                    PortalAuthority.dockDragHandle:SetFrameStrata(PortalAuthority.dockFrame:GetFrameStrata())
                    PortalAuthority.dockDragHandle:SetFrameLevel((PortalAuthority.dockFrame:GetFrameLevel() or 1) + 2)
                end
            end
            if PortalAuthority.NotifyDockPositionChanged then
                PortalAuthority:NotifyDockPositionChanged(PortalAuthorityDB.dockX, PortalAuthorityDB.dockY)
            end
            if widgets.lockDock and widgets.lockDock.Refresh then
                widgets.lockDock:Refresh()
            end
            if relayout then relayout() end
        end, FIXED_FOOTPRINTS.RESET_ANCHOR_W)

        widgets.enableLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        widgets.enableLabel:SetText("Visibility Rules")
        widgets.enableLabel:SetTextColor(1, 1, 1, 1)
        widgets.visibilityLabelSpacer = CreateFrame("Frame", nil, scrollChild)
        widgets.visibilityLabelSpacer:SetSize(FIXED_FOOTPRINTS.SEED_W, FIXED_FOOTPRINTS.VISIBILITY_LABEL_SPACER_H)
        widgets.visibilitySpacer = CreateFrame("Frame", nil, scrollChild)
        widgets.visibilitySpacer:SetSize(FIXED_FOOTPRINTS.SEED_W, FIXED_FOOTPRINTS.VISIBILITY_SPACER_H)
        widgets.dockCustomizationLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 13)
        widgets.dockCustomizationLabel:SetText("")
        widgets.dockCustomizationLabel:SetTextColor(1, 1, 1, 1)
        widgets.lockStateHelper = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.lockStateHelper:SetText("")
        widgets.lockStateHelper:SetTextColor(0.58, 0.58, 0.58, 0.92)
        widgets.lockStateHelper:SetWordWrap(false)
        if widgets.lockStateHelper.SetMaxLines then
            widgets.lockStateHelper:SetMaxLines(1)
        end
        widgets.dockCustomizationHelper = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.dockCustomizationHelper:SetText("Applies preset destinations for the selected Mythic+ Dock preset.")
        widgets.dockCustomizationHelper:SetTextColor(0.58, 0.58, 0.58, 0.92)
        widgets.dockCustomizationMatchStatus = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.dockCustomizationMatchStatus:SetText("")
        widgets.dockCustomizationMatchStatus:SetTextColor(0.66, 0.66, 0.66, 0.94)
        widgets.dockCustomizationMatchStatus:SetWordWrap(false)
        widgets.dockCustomizationMatchStatus:SetJustifyH("LEFT")

        local function getSpellNameByID(spellID)
            if type(spellID) ~= "number" or spellID <= 0 then
                return ""
            end
            if C_Spell and C_Spell.GetSpellInfo then
                local info = C_Spell.GetSpellInfo(spellID)
                if type(info) == "table" and type(info.name) == "string" and info.name ~= "" then
                    return info.name
                end
            end
            if C_Spell and C_Spell.GetSpellName then
                local name = C_Spell.GetSpellName(spellID)
                if type(name) == "string" then
                    return name
                end
            end
            if GetSpellInfo then
                local name = GetSpellInfo(spellID)
                if type(name) == "string" then
                    return name
                end
            end
            return ""
        end

        local function getSpellTextureByID(spellID)
            if type(spellID) ~= "number" or spellID <= 0 then
                return nil
            end
            if C_Spell and C_Spell.GetSpellInfo then
                local info = C_Spell.GetSpellInfo(spellID)
                if type(info) == "table" and info.iconID then
                    return info.iconID
                end
            end
            if C_Spell and C_Spell.GetSpellTexture then
                return C_Spell.GetSpellTexture(spellID)
            end
            if GetSpellTexture then
                return GetSpellTexture(spellID)
            end
            if GetSpellInfo then
                local _, _, texture = GetSpellInfo(spellID)
                return texture
            end
            return nil
        end

        local DOCK_NAME_MAX_LEN = 10
        local getDockSlot
        local resolveSlotName
        local resolveSlotDefaultLabel
        local setDockSlotDefaultName
        local normalizeDockSlotRenameState
        local setDockSlotCustomName
        local getDockSlotDisplayName
        local pendingSpellLoads = {}
        local function requestSpellDataRefresh(slotIndex, spellID)
            if type(spellID) ~= "number" or spellID <= 0 then
                return
            end
            if pendingSpellLoads[slotIndex] == spellID then
                return
            end
            pendingSpellLoads[slotIndex] = spellID

            if C_Spell and C_Spell.RequestLoadSpellData then
                pcall(C_Spell.RequestLoadSpellData, spellID)
            end

            local attempts = 0
            local function tryResolve()
                if pendingSpellLoads[slotIndex] ~= spellID then
                    return
                end

                local slot = getDockSlot(slotIndex)
                if slot.spellID ~= spellID then
                    pendingSpellLoads[slotIndex] = nil
                    return
                end

                if slot.renamed ~= true then
                    setDockSlotDefaultName(slot, spellID)
                end
                local resolved = trim(slot.name or "")
                local texture = getSpellTextureByID(spellID)
                if texture then
                    pendingSpellLoads[slotIndex] = nil
                    queueDockPanelRefresh()
                    if PortalAuthority and PortalAuthority.RebuildDock then
                        PortalAuthority:RebuildDock()
                    end
                    return
                end
                if resolved ~= "" then
                    pendingSpellLoads[slotIndex] = nil
                    return
                end

                attempts = attempts + 1
                if attempts >= 10 or not (C_Timer and C_Timer.After) then
                    pendingSpellLoads[slotIndex] = nil
                    return
                end
                C_Timer.After(0.12, tryResolve)
            end

            tryResolve()
        end

        getDockSlot = function(index)
            PortalAuthorityDB.dockSlots = PortalAuthorityDB.dockSlots or {}
            local slot = PortalAuthorityDB.dockSlots[index]
            if type(slot) ~= "table" then
                slot = {}
                PortalAuthorityDB.dockSlots[index] = slot
            end
            if slot.enabled == nil then slot.enabled = false end
            if slot.selection == nil or slot.selection == "" then
                local spellID = math.floor(tonumber(slot.spellID) or 0)
                slot.selection = (spellID > 0) and tostring(spellID) or "CUSTOM"
            end
            slot.enabled = PA_SafeBool(slot.enabled)
            slot.selection = tostring(slot.selection or "CUSTOM")
            slot.spellID = math.max(0, math.floor(tonumber(slot.spellID) or 0))
            slot.name = tostring(slot.name or "")
            normalizeDockSlotRenameState(slot)
            return slot
        end

        resolveSlotName = function(spellID, fallback)
            local spellName = trim(getSpellNameByID(spellID))
            if spellName ~= "" then
                return spellName
            end
            local map = PortalAuthority and PortalAuthority.SpellMap
            local mapEntry = map and map[spellID]
            if mapEntry and trim(mapEntry.dest) ~= "" then
                return trim(mapEntry.dest)
            end
            return trim(fallback or "")
        end

        resolveSlotDefaultLabel = function(spellID, fallback)
            local map = PortalAuthority and PortalAuthority.SpellMap
            local mapEntry = map and map[spellID]
            local short = trim((mapEntry and mapEntry.short) or "")
            if short ~= "" then
                return short
            end
            local fallbackText = trim(fallback or "")
            if fallbackText ~= "" then
                return fallbackText
            end
            local spellName = trim(getSpellNameByID(spellID))
            if spellName ~= "" then
                return spellName
            end
            if mapEntry and trim(mapEntry.dest) ~= "" then
                return trim(mapEntry.dest)
            end
            return ""
        end

        local function getDockSlotCanonicalDefaultName(spellID)
            local sid = math.max(0, math.floor(tonumber(spellID) or 0))
            if sid <= 0 then
                return ""
            end
            return (resolveSlotDefaultLabel and resolveSlotDefaultLabel(sid, "")) or resolveSlotName(sid, "")
        end

        setDockSlotDefaultName = function(slot, spellID)
            if type(slot) ~= "table" then
                return ""
            end
            local sid = math.max(0, math.floor(tonumber(spellID ~= nil and spellID or slot.spellID) or 0))
            local defaultName = getDockSlotCanonicalDefaultName(sid)
            slot.name = defaultName
            slot.renamed = false
            return defaultName
        end

        normalizeDockSlotRenameState = function(slot)
            if type(slot) ~= "table" then
                return slot
            end
            slot.name = tostring(slot.name or "")
            slot.renamed = slot.renamed == true
            if slot.renamed then
                if trim(slot.name or "") == "" then
                    setDockSlotDefaultName(slot, slot.spellID)
                end
            else
                setDockSlotDefaultName(slot, slot.spellID)
            end
            return slot
        end

        setDockSlotCustomName = function(slot, text)
            if type(slot) ~= "table" then
                return ""
            end
            local customName = trim(text or "")
            if string.len(customName) > DOCK_NAME_MAX_LEN then
                customName = customName:sub(1, DOCK_NAME_MAX_LEN)
            end
            local defaultName = getDockSlotCanonicalDefaultName(slot.spellID)
            if customName == "" or customName == defaultName then
                return setDockSlotDefaultName(slot, slot.spellID)
            end
            slot.name = customName
            slot.renamed = true
            return customName
        end

        getDockSlotDisplayName = function(slot)
            if type(slot) ~= "table" then
                return ""
            end
            normalizeDockSlotRenameState(slot)
            return trim(slot.name or "")
        end

        local function getSpellMapEntryBySpellID(spellID)
            local map = PortalAuthority and PortalAuthority.SpellMap
            return map and map[spellID] or nil
        end

        local function getVisualDockIDForSpell(spellID)
            local sid = math.max(0, math.floor(tonumber(spellID) or 0))
            if sid <= 0 then
                return 0
            end
            local entry = getSpellMapEntryBySpellID(sid)
            local itemID = entry and math.floor(tonumber(entry.useItemID) or 0) or 0
            if itemID > 0 then
                return itemID
            end
            return sid
        end

        local function resolveSpellIDFromVisualDockID(rawValue)
            local visualID = math.max(0, math.floor(tonumber(rawValue) or 0))
            if visualID <= 0 then
                return 0
            end
            local map = PortalAuthority and PortalAuthority.SpellMap
            if type(map) == "table" then
                for sid, entry in pairs(map) do
                    local itemID = entry and math.floor(tonumber(entry.useItemID) or 0) or 0
                    if itemID > 0 and itemID == visualID then
                        local spellID = math.floor(tonumber(sid) or 0)
                        if spellID > 0 then
                            return spellID
                        end
                    end
                end
            end
            return visualID
        end

        local destinationChoicesCache = nil
        local destinationChoiceByValue = nil

        local function buildAcronym(text)
            local out = {}
            for token in tostring(text or ""):gmatch("%a+") do
                table.insert(out, token:sub(1, 1):upper())
            end
            return table.concat(out, "")
        end

        local DOCK_EXPANSION_BY_SPELL_ID = {
            [1254572] = "MIDNIGHT",
            [1254559] = "MIDNIGHT",
            [1254563] = "MIDNIGHT",
            [1254400] = "MIDNIGHT",
            [445440] = "TWW",
            [445417] = "TWW",
            [445416] = "TWW",
            [445441] = "TWW",
            [1237215] = "TWW",
            [1239155] = "TWW",
            [1216786] = "TWW",
            [445444] = "TWW",
            [445414] = "TWW",
            [445443] = "TWW",
            [445269] = "TWW",
            [1226482] = "TWW",
            [432257] = "DF",
            [393273] = "DF",
            [432258] = "DF",
            [393267] = "DF",
            [393283] = "DF",
            [393276] = "DF",
            [393256] = "DF",
            [424197] = "DF",
            [393279] = "DF",
            [393262] = "DF",
            [393222] = "DF",
            [432254] = "DF",
            [373190] = "SL",
            [354468] = "SL",
            [354465] = "SL",
            [354463] = "SL",
            [373191] = "SL",
            [354469] = "SL",
            [373192] = "SL",
            [354466] = "SL",
            [367416] = "SL",
            [354462] = "SL",
            [354467] = "SL",
            [424187] = "BFA",
            [410071] = "BFA",
            [464256] = "BFA",
            [467555] = "BFA",
            [410074] = "BFA",
            [424167] = "BFA",
            [424153] = "LEGION",
            [393766] = "LEGION",
            [424163] = "LEGION",
            [393764] = "LEGION",
            [373262] = "LEGION",
            [410078] = "LEGION",
            [1254551] = "LEGION",
            [159897] = "WOD",
            [159895] = "WOD",
            [159900] = "WOD",
            [159896] = "WOD",
            [159899] = "WOD",
            [159898] = "WOD",
            [159901] = "WOD",
            [159902] = "WOD",
            [131225] = "MOP",
            [131222] = "MOP",
            [131231] = "MOP",
            [131229] = "MOP",
            [131232] = "MOP",
            [131206] = "MOP",
            [131228] = "MOP",
            [131205] = "MOP",
            [131204] = "MOP",
            [445424] = "CATA",
            [410080] = "CATA",
            [424142] = "CATA",
            [1254555] = "WOTLK",
        }

        local DOCK_EXPANSION_BADGE_STYLE = {
            MIDNIGHT = { abbr = "MID", rgb = { 0.63, 0.52, 0.93 } },
            TWW = { abbr = "TWW", rgb = { 0.93, 0.73, 0.24 } },
            DF = { abbr = "DF", rgb = { 0.36, 0.78, 0.95 } },
            SL = { abbr = "SL", rgb = { 0.45, 0.63, 1.00 } },
            BFA = { abbr = "BFA", rgb = { 0.96, 0.77, 0.29 } },
            LEGION = { abbr = "LEG", rgb = { 0.38, 0.94, 0.29 } },
            WOD = { abbr = "WOD", rgb = { 0.89, 0.45, 0.27 } },
            MOP = { abbr = "MOP", rgb = { 0.41, 0.88, 0.57 } },
            CATA = { abbr = "CATA", rgb = { 0.96, 0.40, 0.33 } },
            WOTLK = { abbr = "WOTLK", rgb = { 0.47, 0.72, 0.95 } },
        }

        local function getDockExpansionKey(spellID, info)
            local sid = math.floor(tonumber(spellID) or 0)
            if sid <= 0 then
                return nil
            end
            local mapExpansion = trim((info and info.expansion) or "")
            if mapExpansion ~= "" then
                return mapExpansion:upper()
            end
            return DOCK_EXPANSION_BY_SPELL_ID[sid]
        end

        local function getDockExpansionBadgeMarkup(expansionKey)
            local key = trim(tostring(expansionKey or "")):upper()
            if key == "" then
                return ""
            end
            local style = DOCK_EXPANSION_BADGE_STYLE[key]
            if not style then
                return ""
            end
            local rgb = style.rgb or { 0.75, 0.75, 0.75 }
            local r = math.max(0, math.min(255, math.floor((tonumber(rgb[1]) or 0.75) * 255 + 0.5)))
            local g = math.max(0, math.min(255, math.floor((tonumber(rgb[2]) or 0.75) * 255 + 0.5)))
            local b = math.max(0, math.min(255, math.floor((tonumber(rgb[3]) or 0.75) * 255 + 0.5)))
            local icon = string.format("|TInterface\\Buttons\\WHITE8x8:10:10:0:0:8:8:0:8:0:8:%d:%d:%d:255|t", r, g, b)
            return string.format("%s |cffb8b8b8%s|r", icon, style.abbr or key)
        end

        local function getDestinationChoices()
            if destinationChoicesCache and destinationChoiceByValue then
                return destinationChoicesCache
            end

            local options = {}
            local mapByValue = {}
            local entries = {}
            local categoryOrder = { portals = 1, teleports = 2, mplus = 3, raid = 3 }
            local categoryLabel = { portals = "Portal", teleports = "Teleport", mplus = "Mythic+", raid = "Raid" }
            local spellMap = (PortalAuthority and PortalAuthority.SpellMap) or {}
            local playerClass = nil
            local playerFaction = nil
            if UnitClass then
                _, playerClass = UnitClass("player")
            end
            if UnitFactionGroup then
                playerFaction = UnitFactionGroup("player")
            end
            local function getClassLabel(classFile)
                if type(classFile) ~= "string" or classFile == "" then
                    return ""
                end
                return tostring((LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE[classFile]) or (LOCALIZED_CLASS_NAMES_FEMALE and LOCALIZED_CLASS_NAMES_FEMALE[classFile]) or classFile)
            end
            local function normalizeCityKey(name)
                local key = tostring(name or "")
                key = key:gsub("?", "'")
                key = key:gsub("`", "'")
                return key:lower()
            end
            local ALLIANCE_CITY_DESTS = {
                [normalizeCityKey("Stormwind")] = true,
                [normalizeCityKey("Ironforge")] = true,
                [normalizeCityKey("Darnassus")] = true,
                [normalizeCityKey("Exodar")] = true,
                [normalizeCityKey("Theramore")] = true,
                [normalizeCityKey("Stormshield")] = true,
                [normalizeCityKey("Boralus")] = true,
            }
            local HORDE_CITY_DESTS = {
                [normalizeCityKey("Orgrimmar")] = true,
                [normalizeCityKey("Undercity")] = true,
                [normalizeCityKey("Thunder Bluff")] = true,
                [normalizeCityKey("Silvermoon")] = true,
                [normalizeCityKey("Silvermoon (TBC)")] = true,
                [normalizeCityKey("Stonard")] = true,
                [normalizeCityKey("Warspear")] = true,
                [normalizeCityKey("Dazar'alor")] = true,
            }

            local custom = {
                label = "Custom",
                secondary = "Use Spell ID for manual assignment",
                buttonLabel = "Custom",
                value = "CUSTOM",
                aliases = { "custom", "manual", "spell id" },
            }
            table.insert(options, custom)
            mapByValue[custom.value] = custom

            for spellID, info in pairs(spellMap) do
                local sid = tonumber(spellID)
                local category = info and info.category or nil
                if sid and categoryOrder[category] then
                    local visualID = getVisualDockIDForSpell(sid)
                    local displayCategory = trim((info and info.displayCategory) or "")
                    if displayCategory == "" then
                        displayCategory = category
                    end
                    local displayOrder = categoryOrder[displayCategory] or categoryOrder[category]
                    local displayLabel = categoryLabel[displayCategory] or categoryLabel[category] or tostring(category or "")
                    local displayName = trim((info and info.dest) or "")
                    if displayName == "" then
                        displayName = trim(resolveSlotName(sid, ""))
                    end
                    if displayName == "" then
                        displayName = "Spell " .. sid
                    end
                    local spellName = trim(getSpellNameByID(sid))
                    if spellName == "" then
                        spellName = displayName
                    end
                    local shortName = trim((info and info.short) or "")
                    local requiredClass = trim((info and info.class) or "")
                    if requiredClass == "" and (category == "portals" or category == "teleports") then
                        requiredClass = "MAGE"
                    end
                    if requiredClass == "ANY" then
                        requiredClass = ""
                    end
                    local classLocked = requiredClass ~= "" and playerClass ~= requiredClass
                    local factionLocked = false
                    if playerClass == "MAGE" and (playerFaction == "Alliance" or playerFaction == "Horde") then
                        local cityKey = normalizeCityKey(displayName)
                        if playerFaction == "Alliance" and HORDE_CITY_DESTS[cityKey] then
                            factionLocked = true
                        elseif playerFaction == "Horde" and ALLIANCE_CITY_DESTS[cityKey] then
                            factionLocked = true
                        end
                    end
                    local optionLocked = classLocked or factionLocked
                    local classLabel = getClassLabel(requiredClass)
                    local secondary = string.format("%s  |  ID %d  |  %s", displayLabel, visualID, spellName)
                    local expansionBadge = getDockExpansionBadgeMarkup(getDockExpansionKey(sid, info))
                    if expansionBadge ~= "" then
                        secondary = string.format("%s  |  %s", secondary, expansionBadge)
                    end
                    if classLabel ~= "" then
                        secondary = string.format("%s  |  %s only", secondary, classLabel)
                    end
                    if classLocked then
                        secondary = string.format("%s  |  Unavailable on this class", secondary)
                    end
                    if factionLocked then
                        secondary = string.format("%s  |  Unavailable for your faction", secondary)
                    end
                    local aliases = {
                        tostring(sid),
                        displayName,
                        spellName,
                        shortName,
                        buildAcronym(displayName),
                    }
                    if visualID ~= sid then
                        table.insert(aliases, tostring(visualID))
                    end
                    if classLabel ~= "" then
                        table.insert(aliases, classLabel)
                    end
                    table.insert(entries, {
                        order = displayOrder,
                        name = displayName,
                        value = tostring(sid),
                        label = displayName ~= "" and displayName or ("Spell " .. sid),
                        buttonLabel = string.format("%s: %s", displayLabel, displayName ~= "" and displayName or ("Spell " .. sid)),
                        secondary = string.format("%s  ?  ID %d", categoryLabel[category], sid),
                        aliases = aliases,
                    })
                    local added = entries[#entries]
                    if added then
                        added.secondary = secondary
                        added.disabled = optionLocked
                    end
                end
            end

            table.sort(entries, function(a, b)
                if a.order ~= b.order then
                    return a.order < b.order
                end
                local an = a.name:lower()
                local bn = b.name:lower()
                if an ~= bn then
                    return an < bn
                end
                return tonumber(a.value) < tonumber(b.value)
            end)

            for _, entry in ipairs(entries) do
                table.insert(options, entry)
                mapByValue[entry.value] = entry
            end

            destinationChoicesCache = options
            destinationChoiceByValue = mapByValue
            return options
        end

        local function getDestinationOptionByValue(value)
            getDestinationChoices()
            return destinationChoiceByValue and destinationChoiceByValue[tostring(value or "CUSTOM")] or nil
        end

        local function setDropdownEnabled(spec, enabled)
            if not spec or not spec.control then
                return
            end
            if UIDropDownMenu_EnableDropDown and UIDropDownMenu_DisableDropDown then
                if enabled then
                    UIDropDownMenu_EnableDropDown(spec.control)
                else
                    UIDropDownMenu_DisableDropDown(spec.control)
                end
            end
            spec.control:SetAlpha(enabled and 1 or 0.6)
        end

        local function applyDockChanges(reposition)
            rebuildDock()
            if reposition and PortalAuthority.ApplyDockPosition then
                PortalAuthority:ApplyDockPosition()
            end
            refreshDockVisibility()
        end

        local function onUIChanged(reposition)
            applyDockChanges(reposition)
            local dockSearchPanel = settingsSearchRuntime.getPanelFromObject(scrollChild)
            if dockSearchPanel then
                dockSearchPanel._paSearchRegistryDirty = true
            end
            if relayout then relayout() end
        end

        local function ApplyDockLayoutSettings(reposition)
            if PortalAuthority and PortalAuthority.ApplyDockLayoutSettings then
                PortalAuthority:ApplyDockLayoutSettings(reposition and true or false)
            else
                applyDockChanges(reposition)
            end
            if relayout then relayout() end
        end

        local function ApplyDockAppearanceSettings()
            if PortalAuthority and PortalAuthority.ApplyDockAppearanceSettings then
                PortalAuthority:ApplyDockAppearanceSettings()
            else
                applyDockChanges(false)
            end
            if relayout then relayout() end
        end

        local function normalizeDockSimpleLayoutModeValue(value)
            local mode = string.upper(trim(tostring(value or "GRID")))
            if mode == "HORIZONTAL" then
                mode = "HORIZONTAL_ROW"
            elseif mode == "VERTICAL" then
                mode = "VERTICAL_COLUMN"
            end
            if mode ~= "HORIZONTAL_ROW" and mode ~= "VERTICAL_COLUMN" and mode ~= "GRID" then
                mode = "GRID"
            end
            return mode
        end

        local function normalizeDockLabelModeValue(value)
            if value == false then
                return "OFF"
            end
            if value == true then
                return "OUTSIDE"
            end
            local mode = string.upper(trim(tostring(value or "OUTSIDE")))
            if mode ~= "OFF" and mode ~= "OUTSIDE" and mode ~= "INSIDE" then
                mode = "OUTSIDE"
            end
            return mode
        end

        local function normalizeDockLabelSideValue(value)
            local side = string.upper(trim(tostring(value or "BOTTOM")))
            if side ~= "BOTTOM" and side ~= "TOP" and side ~= "LEFT" and side ~= "RIGHT" and side ~= "CENTER" then
                side = "BOTTOM"
            end
            return side
        end

        local function isOutsideDockLabelSideValue(value)
            return value == "BOTTOM" or value == "TOP" or value == "LEFT" or value == "RIGHT"
        end

        local function normalizeDockOutsideLabelSideValue(value, fallback)
            local resolvedFallback = string.upper(trim(tostring(fallback or "BOTTOM")))
            if resolvedFallback ~= "BOTTOM" and resolvedFallback ~= "TOP" and resolvedFallback ~= "LEFT" and resolvedFallback ~= "RIGHT" then
                resolvedFallback = "BOTTOM"
            end

            local side = string.upper(trim(tostring(value or resolvedFallback)))
            if side ~= "BOTTOM" and side ~= "TOP" and side ~= "LEFT" and side ~= "RIGHT" then
                side = resolvedFallback
            end
            if side ~= "BOTTOM" and side ~= "TOP" and side ~= "LEFT" and side ~= "RIGHT" then
                side = "BOTTOM"
            end
            return side
        end

        local function normalizeOutlineToggleValue(value)
            if type(value) == "string" then
                local upper = string.upper(trim(value))
                if upper == "OUTLINE" or upper == "THICKOUTLINE" then
                    return "OUTLINE"
                end
            end
            return ""
        end

        local function normalizeHoverGlowToggleValue(value)
            if value == true then
                return true
            end
            if value == false or value == nil then
                return false
            end
            if type(value) == "number" then
                return value ~= 0
            end
            if type(value) == "string" then
                local lower = string.lower(trim(value))
                if lower == "true" or lower == "1" then
                    return true
                end
                return false
            end
            return PA_SafeBool(value)
        end

        local function getDockSimpleLayoutModeForSettings(defaults)
            local db = PortalAuthorityDB or {}
            local fallback = (defaults and defaults.dockSimpleLayoutMode) or "GRID"

            -- Runtime effective mode is authoritative for what the dock is currently rendering.
            if PortalAuthority and PortalAuthority._dockEffectiveLayoutMode ~= nil then
                local runtimeMode = normalizeDockSimpleLayoutModeValue(PortalAuthority._dockEffectiveLayoutMode)
                db.dockSimpleLayoutMode = runtimeMode
                db.dockSimpleLayoutModePersist = runtimeMode
                return runtimeMode
            end

            if db.dockSimpleLayoutMode ~= nil then
                local persistedMode = normalizeDockSimpleLayoutModeValue(db.dockSimpleLayoutMode)
                db.dockSimpleLayoutMode = persistedMode
                db.dockSimpleLayoutModePersist = persistedMode
                return persistedMode
            end

            if db.dockSimpleLayoutModePersist ~= nil then
                local fallbackPersistMode = normalizeDockSimpleLayoutModeValue(db.dockSimpleLayoutModePersist)
                db.dockSimpleLayoutMode = fallbackPersistMode
                db.dockSimpleLayoutModePersist = fallbackPersistMode
                return fallbackPersistMode
            end

            local normalizedFallback = normalizeDockSimpleLayoutModeValue(fallback)
            db.dockSimpleLayoutMode = normalizedFallback
            db.dockSimpleLayoutModePersist = normalizedFallback
            return normalizedFallback
        end

        local function syncLayoutModeSegmentSelection(forceVisualOnly)
            local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
            local resolvedMode = getDockSimpleLayoutModeForSettings(defaults)
            if widgets.layoutModeSegment and widgets.layoutModeSegment.Refresh and not forceVisualOnly then
                widgets.layoutModeSegment:Refresh()
            end
            if widgets.layoutModeSegment and widgets.layoutModeSegment.SetVisualSelectedValue then
                widgets.layoutModeSegment:SetVisualSelectedValue(resolvedMode)
            end
        end

        local function getDockLabelModeForSettings(defaults)
            if ensureDatabase then
                ensureDatabase()
            end
            local db = PortalAuthorityDB or {}
            local fallback = (defaults and defaults.dockLabelMode) or "OUTSIDE"
            local liveRaw = db.dockLabelMode
            local persistRaw = db.dockLabelModePersist
            if normalizeDockLabelModeValue(liveRaw or "") == "OFF" or normalizeDockLabelModeValue(persistRaw or "") == "OFF" then
                db.dockHideDungeonName = true
            end
            if db.dockHideDungeonName then
                db.dockLabelMode = "OFF"
                db.dockLabelModePersist = "OFF"
                return "OFF"
            end
            local live = db.dockLabelMode
            local persisted = db.dockLabelModePersist
            local resolvedLive = (live ~= nil) and normalizeDockLabelModeValue(live) or nil
            local resolvedPersist = (persisted ~= nil) and normalizeDockLabelModeValue(persisted) or nil
            local resolved
            if resolvedLive == "OFF" or resolvedPersist == "OFF" then
                resolved = "OFF"
            elseif resolvedLive ~= nil then
                resolved = resolvedLive
            elseif resolvedPersist ~= nil then
                resolved = resolvedPersist
            else
                resolved = normalizeDockLabelModeValue(fallback)
            end
            db.dockLabelMode = resolved
            db.dockLabelModePersist = resolved
            return resolved
        end

        local function getDockStoredLabelSideForSettings(defaults)
            if ensureDatabase then
                ensureDatabase()
            end
            local db = PortalAuthorityDB or {}
            local fallback = (defaults and defaults.dockLabelSide) or "BOTTOM"
            local source = db.dockLabelSide
            if source == nil then
                source = db.dockLabelSidePersist
            end
            return normalizeDockLabelSideValue(source or fallback)
        end

        local function getDockOutsideLabelSideForSettings(defaults)
            local db = PortalAuthorityDB or {}
            local mode = getDockLabelModeForSettings(defaults)
            local fallback = (defaults and defaults.dockLabelSideOutsidePersist) or (defaults and defaults.dockLabelSide) or "BOTTOM"
            local resolved = getDockStoredLabelSideForSettings(defaults)
            if mode == "OUTSIDE" and isOutsideDockLabelSideValue(resolved) then
                db.dockLabelSideOutsidePersist = resolved
            end
            if mode == "OUTSIDE" and isOutsideDockLabelSideValue(resolved) then
                return resolved
            end
            return normalizeDockOutsideLabelSideValue(db.dockLabelSideOutsidePersist, fallback)
        end

        local function getDockInsideLabelSideForSettings(defaults)
            local resolved = getDockStoredLabelSideForSettings(defaults)
            if resolved == "TOP" or resolved == "BOTTOM" then
                return resolved
            end
            return "CENTER"
        end

        local function setDockLabelSideForSettings(side, modeOverride)
            local db = PortalAuthorityDB or {}
            local resolvedSide = normalizeDockLabelSideValue(side)
            local resolvedMode = normalizeDockLabelModeValue(modeOverride or db.dockLabelMode or db.dockLabelModePersist or "OUTSIDE")
            db.dockLabelSide = resolvedSide
            db.dockLabelSidePersist = resolvedSide
            if resolvedMode == "OUTSIDE" and isOutsideDockLabelSideValue(resolvedSide) then
                db.dockLabelSideOutsidePersist = resolvedSide
            end
            return resolvedSide
        end

        local setLabelStyleRowsVisible

        local function forceDockLabelUiState()
            local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
            local resolvedMode = getDockLabelModeForSettings(defaults)
            local resolvedOutsideSide = getDockOutsideLabelSideForSettings(defaults)
            local resolvedInsideSide = getDockInsideLabelSideForSettings(defaults)
            if PortalAuthorityDB and resolvedMode == "OFF" then
                PortalAuthorityDB.dockHideDungeonName = true
                PortalAuthorityDB.dockLabelMode = "OFF"
                PortalAuthorityDB.dockLabelModePersist = "OFF"
            end
            if widgets.labelMode and widgets.labelMode.SetVisualSelectedValue then
                widgets.labelMode:SetVisualSelectedValue(resolvedMode)
            end
            if widgets.labelSide and widgets.labelSide.SetVisualSelectedValue then
                widgets.labelSide:SetVisualSelectedValue(resolvedOutsideSide)
            end
            if widgets.labelSideInside and widgets.labelSideInside.SetVisualSelectedValue then
                widgets.labelSideInside:SetVisualSelectedValue(resolvedInsideSide)
            end
            local showSide = (resolvedMode ~= "OFF")
            if widgets.labelSide and widgets.labelSide.control and widgets.labelSide.label then
                if resolvedMode == "OUTSIDE" then
                    widgets.labelSide.control:Show()
                    widgets.labelSide.label:Show()
                else
                    widgets.labelSide.control:Hide()
                    widgets.labelSide.label:Hide()
                end
            end
            if widgets.labelSideInside and widgets.labelSideInside.control and widgets.labelSideInside.label then
                if resolvedMode == "INSIDE" then
                    widgets.labelSideInside.control:Show()
                    widgets.labelSideInside.label:Show()
                else
                    widgets.labelSideInside.control:Hide()
                    widgets.labelSideInside.label:Hide()
                end
            end
            setLabelStyleRowsVisible(showSide)
        end

        setLabelStyleRowsVisible = function(show)
            local visible = show and true or false

            local function setSpecVisible(spec, specVisible)
                if not spec then
                    return
                end
                if spec.label and spec.label.SetShown then
                    spec.label:SetShown(specVisible)
                end
                if spec.control and spec.control.SetShown then
                    spec.control:SetShown(specVisible)
                end
            end

            setSpecVisible(widgets.font, visible)
            if widgets.fontSize and widgets.fontSize.control and widgets.fontSize.control.SetShown then
                widgets.fontSize.control:SetShown(visible)
            end
            if widgets.color and widgets.color.swatch and widgets.color.swatch.SetShown then
                widgets.color.swatch:SetShown(visible)
            end
            if widgets.color and widgets.color.inlineLabel and widgets.color.inlineLabel.SetShown then
                widgets.color.inlineLabel:SetShown(false)
            end
            setSpecVisible(widgets.outlineToggle, visible)

            if not visible and widgets.font and widgets.font.picker and widgets.font.picker.Close then
                widgets.font.picker:Close()
            end
        end

        local function forceStyleToggleUiState()
            local db = PortalAuthorityDB or {}
            local outlineValue = normalizeOutlineToggleValue(db.dockTextOutline)
            local hoverValue = normalizeHoverGlowToggleValue(db.dockHoverGlow)

            -- Canonicalize persisted values so visual state and runtime state cannot drift.
            db.dockTextOutline = outlineValue
            db.dockHoverGlow = hoverValue and true or false

            if widgets.outlineToggle and widgets.outlineToggle.SetVisualSelectedValue then
                widgets.outlineToggle:SetVisualSelectedValue(outlineValue)
            end
            if widgets.hoverGlowSegment and widgets.hoverGlowSegment.SetVisualSelectedValue then
                widgets.hoverGlowSegment:SetVisualSelectedValue(hoverValue and true or false)
            end
        end

        local function forceDockFontUiState()
            local db = PortalAuthorityDB or {}
            local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
            local selectedFontPath = db.dockFontPath
            if selectedFontPath == nil then
                selectedFontPath = defaults.dockFontPath or ""
            end
            if widgets.font and widgets.font.SetVisualSelectedValue then
                widgets.font:SetVisualSelectedValue(selectedFontPath)
            elseif widgets.font and widgets.font.Refresh then
                widgets.font:Refresh()
            end
        end

        local function forceDockFontSizeUiState()
            local db = PortalAuthorityDB or {}
            local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
            local rawValue = tonumber(db.dockFontSizeUI or db.dockFontSize or defaults.dockFontSize or 12)
            local n = math.floor((rawValue or 12) + 0.5)
            if n < 8 then n = 8 end
            if n > 48 then n = 48 end
            db.dockFontSize = n
            db.dockFontSizeUI = n

            if widgets.fontSize and widgets.fontSize.SetVisualValue then
                widgets.fontSize:SetVisualValue(n)
            elseif widgets.fontSize and widgets.fontSize.Refresh then
                widgets.fontSize:Refresh()
            end
        end

        local function syncLabelModeSegmentSelection(forceVisualOnly)
            forceDockLabelUiState()
        end

        local function syncLabelSideSegmentSelection(forceVisualOnly)
            forceDockLabelUiState()
        end

        local updateLabelModeApplicability

        local function updateLayoutModeApplicability()
            local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
            local mode = getDockSimpleLayoutModeForSettings(defaults)
            local isGrid = (mode == "GRID")

            if widgets.iconsPerRow and widgets.iconsPerRow.SetEnabled then
                widgets.iconsPerRow:SetEnabled(isGrid)
            end

            if widgets.iconsPerRow and widgets.iconsPerRow.control and widgets.iconsPerRow.label then
                if isGrid then
                    widgets.iconsPerRow.control:Show()
                    widgets.iconsPerRow.label:Show()
                else
                    widgets.iconsPerRow.control:Hide()
                    widgets.iconsPerRow.label:Hide()
                end
            end

            if widgets.iconsPerRowGridOnlyHint then
                widgets.iconsPerRowGridOnlyHint:SetShown(false)
            end
        end

        updateLabelModeApplicability = function()
            if not widgets.labelMode then
                return
            end

            local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
            local mode = getDockLabelModeForSettings(defaults)
            local showSide = (mode ~= "OFF")

            if widgets.labelSide and widgets.labelSide.control and widgets.labelSide.label then
                if mode == "OUTSIDE" then
                    widgets.labelSide.control:Show()
                    widgets.labelSide.label:Show()
                else
                    widgets.labelSide.control:Hide()
                    widgets.labelSide.label:Hide()
                end
            end
            if widgets.labelSideInside and widgets.labelSideInside.control and widgets.labelSideInside.label then
                if mode == "INSIDE" then
                    widgets.labelSideInside.control:Show()
                    widgets.labelSideInside.label:Show()
                else
                    widgets.labelSideInside.control:Hide()
                    widgets.labelSideInside.label:Hide()
                end
            end
            setLabelStyleRowsVisible(showSide)
        end

        local function getSeason01PresetSpellIDs()
            if PortalAuthority and PortalAuthority.GetMPlusDockPresetSpellIDs then
                local spellIDs = PortalAuthority:GetMPlusDockPresetSpellIDs("SEASON_01")
                if type(spellIDs) == "table" and #spellIDs > 0 then
                    return spellIDs
                end
            end

            return {
                1254400, -- Windrunner Spire
                159898,  -- Skyreach
                1254551, -- Seat of the Triumvirate
                1254555, -- Pit of Saron
                1254563, -- Nexus-Point Xenas
                1254559, -- Maisara Caverns
                1254572, -- Magister's Terrace
                393273,  -- Algeth'ar Academy
            }
        end

        local season01PresetSpellIDs = getSeason01PresetSpellIDs()

        local function getCustomSeason01MatchState()
            local enabledSpellIDs = {}
            for i = 1, 10 do
                local slot = getDockSlot(i)
                if PA_SafeBool(slot.enabled) then
                    table.insert(enabledSpellIDs, math.max(0, math.floor(tonumber(slot.spellID) or 0)))
                end
            end

            if #enabledSpellIDs ~= #season01PresetSpellIDs then
                return false, false
            end

            local counts = {}
            for _, spellID in ipairs(season01PresetSpellIDs) do
                counts[spellID] = (counts[spellID] or 0) + 1
            end
            for _, spellID in ipairs(enabledSpellIDs) do
                if spellID <= 0 then
                    return false, false
                end
                local remaining = counts[spellID] or 0
                if remaining <= 0 then
                    return false, false
                end
                counts[spellID] = remaining - 1
            end

            local orderMatches = true
            for idx, spellID in ipairs(season01PresetSpellIDs) do
                if enabledSpellIDs[idx] ~= spellID then
                    orderMatches = false
                    break
                end
            end

            return true, orderMatches
        end

        local function applySeason01Loadout()
            -- Midnight Season 01 loadout slots 1-8; slots 9-10 remain editable but disabled.
            local presetSpellIDs = season01PresetSpellIDs

            for i = 1, 10 do
                local slot = getDockSlot(i)
                local presetSpellID = presetSpellIDs[i]
                if presetSpellID and presetSpellID > 0 then
                    slot.spellID = presetSpellID
                    slot.selection = tostring(presetSpellID)
                    setDockSlotDefaultName(slot, presetSpellID)
                    slot.enabled = true
                else
                    setDockSlotDefaultName(slot, 0)
                    slot.enabled = false
                end
            end

            onUIChanged(false)
        end

        local function normalizeLoadoutPresetValue(value)
            local preset = string.upper(trim(tostring(value or "CUSTOM")))
            if preset == "SEASON_02" then
                preset = "SEASON_01"
            end
            if preset ~= "SEASON_01" and preset ~= "CUSTOM" then
                preset = "CUSTOM"
            end
            return preset
        end

        PortalAuthorityDB.dockLoadoutPreset = normalizeLoadoutPresetValue(PortalAuthorityDB.dockLoadoutPreset)

        local function buildCustomLoadoutSnapshot()
            local snapshot = {}
            for i = 1, 10 do
                local slot = getDockSlot(i)
                local spellID = math.max(0, math.floor(tonumber(slot.spellID) or 0))
                local selection = tostring(slot.selection or "")
                if selection == "" then
                    selection = (spellID > 0) and tostring(spellID) or "CUSTOM"
                end
                snapshot[i] = {
                    enabled = PA_SafeBool(slot.enabled),
                    selection = selection,
                    spellID = spellID,
                    name = tostring(slot.name or ""),
                    renamed = slot.renamed == true,
                }
            end
            return snapshot
        end

        local function saveCustomLoadoutSnapshot()
            PortalAuthorityDB.dockCustomLoadoutSlots = buildCustomLoadoutSnapshot()
        end

        local function restoreCustomLoadoutSnapshot()
            local snapshot = PortalAuthorityDB and PortalAuthorityDB.dockCustomLoadoutSlots
            if type(snapshot) ~= "table" then
                return false
            end

            local changed = false
            for i = 1, 10 do
                local source = snapshot[i]
                if type(source) == "table" then
                    local slot = getDockSlot(i)
                    local enabled = PA_SafeBool(source.enabled)
                    local spellID = math.max(0, math.floor(tonumber(source.spellID) or 0))
                    local selection = tostring(source.selection or "")
                    if selection == "" then
                        selection = (spellID > 0) and tostring(spellID) or "CUSTOM"
                    end
                    local name = tostring(source.name or "")
                    local renamed = source.renamed == true

                    if slot.enabled ~= enabled
                        or slot.spellID ~= spellID
                        or tostring(slot.selection or "") ~= selection
                        or tostring(slot.name or "") ~= name
                        or (slot.renamed == true) ~= renamed then
                        changed = true
                    end

                    slot.enabled = enabled
                    slot.spellID = spellID
                    slot.selection = selection
                    slot.name = name
                    slot.renamed = renamed
                    normalizeDockSlotRenameState(slot)
                end
            end
            return changed
        end

        local lastLoadoutPresetSelection = normalizeLoadoutPresetValue(PortalAuthorityDB.dockLoadoutPreset)
        PortalAuthorityDB.dockLoadoutPreset = lastLoadoutPresetSelection
        if lastLoadoutPresetSelection == "CUSTOM" and type(PortalAuthorityDB.dockCustomLoadoutSlots) ~= "table" then
            saveCustomLoadoutSnapshot()
        end

        local suppressLoadoutPresetAutoCustom = false
        local function refreshLoadoutPresetControl()
            lastLoadoutPresetSelection = normalizeLoadoutPresetValue(PortalAuthorityDB.dockLoadoutPreset)
            if widgets.loadoutPresetSegment and widgets.loadoutPresetSegment.Refresh then
                widgets.loadoutPresetSegment:Refresh()
            end
        end
        local function setLoadoutPresetCustom()
            if suppressLoadoutPresetAutoCustom then
                return
            end
            saveCustomLoadoutSnapshot()
            lastLoadoutPresetSelection = "CUSTOM"
            if PortalAuthorityDB.dockLoadoutPreset ~= "CUSTOM" then
                PortalAuthorityDB.dockLoadoutPreset = "CUSTOM"
                refreshLoadoutPresetControl()
            end
        end

        local function createSliderControl(labelText, key, min, max, step, isFloat, onApply)
            local label = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
            label:SetText(labelText)
            local slider = CreateFrame("Slider", nil, scrollChild, "OptionsSliderTemplate")
            slider:SetMinMaxValues(min, max)
            slider:SetValueStep(step)
            if slider.SetObeyStepOnDrag then
                slider:SetObeyStepOnDrag(true)
            end
            if slider.Low then slider.Low:SetText("") end
            if slider.High then slider.High:SetText("") end
            if slider.Text then slider.Text:SetText("") end
            local valueText = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)

            local suppress = false
            local function normalize(v)
                local n = tonumber(v) or min
                if n < min then n = min end
                if n > max then n = max end
                if isFloat then
                    return tonumber(string.format("%.2f", n))
                end
                return math.floor(n + 0.5)
            end
            local function fmt(v)
                if isFloat then
                    return string.format("%.2f", v)
                end
                return tostring(math.floor(v + 0.5))
            end

            slider:SetScript("OnValueChanged", function(selfSlider, value)
                if suppress or isControlHydrating(selfSlider) then return end
                local n = normalize(value)
                if not isFloat and selfSlider:GetValue() ~= n then
                    suppress = true
                    selfSlider:SetValue(n)
                    suppress = false
                end
                PortalAuthorityDB[key] = n
                valueText:SetText(fmt(n))
                if onApply then onApply() end
            end)

            local spec = { kind = "slider", label = label, control = slider, valueText = valueText }
            spec.Refresh = function()
                local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                local n = normalize(PortalAuthorityDB[key] or defaults[key] or min)
                PortalAuthorityDB[key] = n
                suppress = true
                slider:SetValue(n)
                suppress = false
                valueText:SetText(fmt(n))
            end
            spec.Refresh()
            return settingsSearchRuntime.registerSpec(spec)
        end

        local CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A = 0.10, 0.11, 0.14, 0.95
        local CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A = 0.16, 0.17, 0.20, 0.95
        local CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A = 0.24, 0.27, 0.32, 1.0
        local CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A = 0.30, 0.33, 0.38, 1.0

        local function CreatePremiumSlider(parent, labelText, min, max, step, settingKey, width, onApply, isFloat, tooltipText)
            local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
            label:SetText(labelText)

            local sliderMin = tonumber(min) or 0
            local sliderMax = tonumber(max) or 100
            if sliderMax < sliderMin then
                sliderMin, sliderMax = sliderMax, sliderMin
            end

            local container = CreateFrame("Frame", nil, parent)
            container:SetHeight(22)
            container:SetWidth(math.max(120, tonumber(width) or 220))

            local valueButton = CreateFrame("Button", nil, container)
            valueButton:SetSize(44, 16)
            valueButton:SetPoint("RIGHT", container, "RIGHT", 0, 0)

            local valueText = createStyledFontString(valueButton, "ARTWORK", "GameFontHighlightSmall", 11)
            valueText:SetPoint("RIGHT", valueButton, "RIGHT", 0, 0)
            valueText:SetJustifyH("RIGHT")
            valueText:SetTextColor(0.76, 0.76, 0.78, 1)

            local valueEdit = CreateFrame("EditBox", nil, valueButton)
            valueEdit:SetAllPoints(valueButton)
            valueEdit:SetAutoFocus(false)
            valueEdit:SetJustifyH("RIGHT")
            valueEdit:SetTextInsets(0, 0, 0, 0)
            valueEdit:SetTextColor(1, 1, 1, 1)
            valueEdit:SetHighlightColor(1, 1, 1, 0.25)
            applyGlobalFontToObject(valueEdit, 11)
            valueEdit:Hide()

            local slider = CreateFrame("Slider", nil, container)
            slider:SetPoint("TOPLEFT", container, "TOPLEFT", 0, 0)
            slider:SetPoint("BOTTOMRIGHT", valueButton, "BOTTOMLEFT", -8, 0)
            slider:SetMinMaxValues(sliderMin, sliderMax)
            slider:SetValueStep(step)
            if slider.SetObeyStepOnDrag then
                slider:SetObeyStepOnDrag(true)
            end
            slider:SetThumbTexture("Interface\\Buttons\\WHITE8x8")
            local inputThumb = slider:GetThumbTexture()
            if inputThumb then
                inputThumb:SetSize(16, 16)
                -- Keep native thumb almost invisible while preserving drag mechanics.
                inputThumb:SetVertexColor(1, 1, 1, 0.01)
            end
            slider:EnableMouse(true)
            slider:SetOrientation("HORIZONTAL")

            local trackBg = slider:CreateTexture(nil, "BACKGROUND")
            trackBg:SetTexture("Interface\\Buttons\\WHITE8x8")
            trackBg:SetPoint("LEFT", slider, "LEFT", 0, 0)
            trackBg:SetPoint("RIGHT", slider, "RIGHT", 0, 0)
            trackBg:SetHeight(2)
            trackBg:SetVertexColor(0.18, 0.18, 0.19, 0.95)

            local trackActive = slider:CreateTexture(nil, "ARTWORK")
            trackActive:SetTexture("Interface\\Buttons\\WHITE8x8")
            trackActive:SetPoint("LEFT", slider, "LEFT", 0, 0)
            trackActive:SetHeight(2)
            trackActive:SetWidth(0)
            trackActive:SetVertexColor(1.0, 0.82, 0.0, 0.75)

            local thumb = slider:CreateTexture(nil, "OVERLAY")
            thumb:SetTexture("Interface\\Buttons\\WHITE8x8")
            thumb:SetSize(8, 8)
            thumb:SetVertexColor(1.0, 0.84, 0.08, 0.98)
            if thumb.SetMask then
                thumb:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask")
            end

            local thumbGlow = slider:CreateTexture(nil, "ARTWORK")
            thumbGlow:SetTexture("Interface\\Buttons\\WHITE8x8")
            thumbGlow:SetSize(14, 14)
            thumbGlow:SetVertexColor(1.0, 0.82, 0.0, 0)
            if thumbGlow.SetMask then
                thumbGlow:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask")
            end
            thumbGlow:SetBlendMode("ADD")

            local suppress = false
            local currentValue = nil
            local dragging = false
            local hovering = false

            local function normalize(v)
                local n = tonumber(v) or sliderMin
                if n < sliderMin then n = sliderMin end
                if n > sliderMax then n = sliderMax end
                if step and step > 0 then
                    n = sliderMin + (math.floor(((n - sliderMin) / step) + 0.5) * step)
                end
                if isFloat then
                    return tonumber(string.format("%.2f", n))
                end
                return math.floor(n + 0.5)
            end

            local function fmt(v)
                if isFloat then
                    return string.format("%.2f", tonumber(v) or 0)
                end
                return tostring(math.floor((tonumber(v) or 0) + 0.5))
            end

            local function resolveApply()
                if onApply then
                    onApply()
                    return
                end
                if settingKey == "dockIconsPerLine" or settingKey == "dockIconSpacing" then
                    ApplyDockLayoutSettings(false)
                else
                    ApplyDockAppearanceSettings()
                end
            end

            local function applyVisualState()
                local minV, maxV = slider:GetMinMaxValues()
                local value = normalize(slider:GetValue())
                local span = math.max(0.0001, (maxV - minV))
                local pct = (value - minV) / span
                pct = math.max(0, math.min(1, pct))
                local widthNow = slider:GetWidth() or 0
                local x = pct * widthNow

                thumb:ClearAllPoints()
                thumb:SetPoint("CENTER", slider, "LEFT", x, 0)
                thumbGlow:ClearAllPoints()
                thumbGlow:SetPoint("CENTER", thumb, "CENTER", 0, 0)

                trackActive:ClearAllPoints()
                trackActive:SetPoint("LEFT", slider, "LEFT", 0, 0)
                trackActive:SetPoint("RIGHT", thumb, "CENTER", 0, 0)

                local glowAlpha = 0
                if dragging then
                    glowAlpha = 0.34
                    trackActive:SetVertexColor(1.0, 0.86, 0.16, 0.9)
                    thumb:SetVertexColor(1.0, 0.9, 0.22, 1)
                elseif hovering then
                    glowAlpha = 0.22
                    trackActive:SetVertexColor(1.0, 0.85, 0.12, 0.85)
                    thumb:SetVertexColor(1.0, 0.88, 0.18, 1)
                else
                    trackActive:SetVertexColor(1.0, 0.82, 0.0, 0.75)
                    thumb:SetVertexColor(1.0, 0.84, 0.08, 0.98)
                end
                thumbGlow:SetVertexColor(1.0, 0.82, 0.0, glowAlpha)
            end

            local function setValueFromCursor()
                local minV, maxV = slider:GetMinMaxValues()
                local left = slider:GetLeft()
                local right = slider:GetRight()
                if not left or not right or right <= left then
                    return
                end
                local cx = GetCursorPosition()
                local scale = slider:GetEffectiveScale() or 1
                if not cx or scale <= 0 then
                    return
                end
                cx = cx / scale
                local pct = (cx - left) / (right - left)
                if pct < 0 then pct = 0 end
                if pct > 1 then pct = 1 end
                local raw = minV + ((maxV - minV) * pct)
                slider:SetValue(normalize(raw))
            end

            local function setValueFromInput(text)
                local normalizedText = (text or ""):gsub(",", ".")
                local parsed = tonumber(normalizedText)
                if parsed == nil then
                    return
                end
                local n = normalize(parsed)
                suppress = true
                slider:SetValue(n)
                suppress = false
                if currentValue ~= n then
                    currentValue = n
                    PortalAuthorityDB[settingKey] = n
                    if settingKey == "dockIconSize" then
                        PortalAuthorityDB.dockIconSizeUI = n
                        PortalAuthorityDB.dockIconWidth = n
                        PortalAuthorityDB.dockIconHeight = n
                    end
                    resolveApply()
                end
                valueText:SetText(fmt(n))
                applyVisualState()
            end

            local function beginEdit()
                valueText:Hide()
                valueEdit:SetText(fmt(slider:GetValue()))
                valueEdit:Show()
                valueEdit:SetFocus()
                valueEdit:HighlightText()
            end

            local function endEdit(commit)
                if commit then
                    setValueFromInput(valueEdit:GetText())
                end
                valueEdit:Hide()
                valueText:Show()
                valueEdit:ClearFocus()
                valueText:SetText(fmt(slider:GetValue()))
            end

            valueButton:SetScript("OnClick", function()
                beginEdit()
            end)
            valueEdit:SetScript("OnEnterPressed", function(edit)
                endEdit(true)
                edit:ClearFocus()
            end)
            valueEdit:SetScript("OnEscapePressed", function(edit)
                endEdit(false)
                edit:ClearFocus()
            end)
            valueEdit:SetScript("OnEditFocusLost", function()
                endEdit(true)
            end)

            slider:SetScript("OnValueChanged", function(selfSlider, value)
                local n = normalize(value)
                if selfSlider:GetValue() ~= n then
                    suppress = true
                    selfSlider:SetValue(n)
                    suppress = false
                end
                valueText:SetText(fmt(n))
                applyVisualState()
                if suppress or isControlHydrating(selfSlider) then
                    return
                end
                if currentValue == n then
                    return
                end
                currentValue = n
                PortalAuthorityDB[settingKey] = n
                if settingKey == "dockIconSize" then
                    PortalAuthorityDB.dockIconSizeUI = n
                    PortalAuthorityDB.dockIconWidth = n
                    PortalAuthorityDB.dockIconHeight = n
                end
                resolveApply()
            end)
            slider:SetScript("OnMouseDown", function()
                dragging = true
                setValueFromCursor()
                applyVisualState()
                slider:SetScript("OnUpdate", function()
                    if dragging then
                        setValueFromCursor()
                    end
                end)
            end)
            slider:SetScript("OnMouseUp", function()
                dragging = false
                slider:SetScript("OnUpdate", nil)
                applyVisualState()
            end)
            slider:SetScript("OnEnter", function(selfSlider)
                hovering = true
                applyVisualState()
                if tooltipText and tooltipText ~= "" then
                    GameTooltip:SetOwner(selfSlider, "ANCHOR_TOP")
                    GameTooltip:SetText(tooltipText, 1, 0.82, 0, 1)
                    GameTooltip:Show()
                end
            end)
            slider:SetScript("OnLeave", function()
                hovering = false
                dragging = false
                slider:SetScript("OnUpdate", nil)
                applyVisualState()
                GameTooltip:Hide()
            end)

            if tooltipText and tooltipText ~= "" then
                label:SetScript("OnEnter", function(selfLabel)
                    GameTooltip:SetOwner(selfLabel, "ANCHOR_TOPLEFT")
                    GameTooltip:SetText(tooltipText, 1, 0.82, 0, 1)
                    GameTooltip:Show()
                end)
                label:SetScript("OnLeave", function()
                    GameTooltip:Hide()
                end)
            end

            local spec = { kind = "premium_slider", label = label, control = container, slider = slider, valueText = valueText, valueEdit = valueEdit }
            spec.SetWidth = function(_, newWidth)
                local fullW = math.max(140, math.floor(tonumber(newWidth) or width or 220))
                container:SetWidth(fullW)
                applyVisualState()
            end
            spec.SetRange = function(_, newMin, newMax)
                local a = tonumber(newMin)
                local b = tonumber(newMax)
                if a == nil or b == nil then
                    return
                end
                if b < a then
                    a, b = b, a
                end
                sliderMin = a
                sliderMax = b
                slider:SetMinMaxValues(sliderMin, sliderMax)
                local n = normalize(PortalAuthorityDB[settingKey] or currentValue or slider:GetValue())
                suppress = true
                slider:SetValue(n)
                suppress = false
                currentValue = n
                PortalAuthorityDB[settingKey] = n
                if settingKey == "dockIconSize" then
                    PortalAuthorityDB.dockIconSizeUI = n
                    PortalAuthorityDB.dockIconWidth = n
                    PortalAuthorityDB.dockIconHeight = n
                end
                valueText:SetText(fmt(n))
                applyVisualState()
            end
            spec.Refresh = function()
                local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                local storedValue = nil
                if PortalAuthorityDB then
                    if settingKey == "dockIconSize" then
                        storedValue = tonumber(PortalAuthorityDB.dockIconSizeUI or PortalAuthorityDB[settingKey])
                    else
                        storedValue = tonumber(PortalAuthorityDB[settingKey])
                    end
                end
                local n = normalize(storedValue or defaults[settingKey] or sliderMin)
                suppress = true
                slider:SetValue(n)
                suppress = false
                currentValue = n
                valueEdit:SetText(fmt(n))
                valueEdit:Hide()
                valueText:Show()
                valueText:SetText(fmt(n))
                applyVisualState()
            end
            container:SetScript("OnSizeChanged", function()
                applyVisualState()
            end)
            spec.Refresh()
            return settingsSearchRuntime.registerSpec(spec)
        end

        local function CreateStepperControl(parent, labelText, min, max, step, settingKey, width, onApply, tooltipText, opts)
            opts = type(opts) == "table" and opts or {}
            local isMicro = opts.micro and true or false
            local microShiftMultiplier = math.max(1, math.floor(tonumber(opts.shiftMultiplier) or 5))
            local customGetValue = type(opts.getValue) == "function" and opts.getValue or nil
            local customSetValue = type(opts.setValue) == "function" and opts.setValue or nil
            local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
            label:SetText(labelText)

            local container = CreateFrame("Frame", nil, parent)
            container:SetHeight(22)
            container:SetWidth(math.max(isMicro and 52 or 120, tonumber(width) or 160))

            local function createStepperButton(symbol)
                local button = CreateFrame("Button", nil, container, isMicro and nil or "BackdropTemplate")
                if not isMicro then
                    button:SetBackdrop({
                        bgFile = "Interface\\Buttons\\WHITE8x8",
                    })
                    button:SetBackdropColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
                    button:SetSize(18, 18)
                else
                    button:SetSize(10, 16)
                end

                local text = createStyledFontString(button, "ARTWORK", "GameFontHighlight", 12)
                text:SetPoint("CENTER", button, "CENTER", 0, 0)
                text:SetText(symbol)
                text:SetTextColor(isMicro and 0.74 or 0.9, isMicro and 0.74 or 0.9, isMicro and 0.76 or 0.92, 1)
                button._text = text
                button._hovered = false
                button._pressed = false

                local function applyVisual(selfBtn)
                    if isMicro then
                        if selfBtn._pressed then
                            selfBtn._text:SetTextColor(0.95, 0.95, 0.98, 1)
                            selfBtn:SetAlpha(0.82)
                        elseif selfBtn._hovered then
                            selfBtn._text:SetTextColor(0.95, 0.95, 0.98, 1)
                            selfBtn:SetAlpha(1)
                        else
                            selfBtn._text:SetTextColor(0.74, 0.74, 0.76, 1)
                            selfBtn:SetAlpha(1)
                        end
                    else
                        if selfBtn._hovered then
                            selfBtn:SetBackdropColor(CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A)
                            selfBtn._text:SetTextColor(1, 0.92, 0.38, 1)
                        else
                            selfBtn:SetBackdropColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
                            selfBtn._text:SetTextColor(0.9, 0.9, 0.92, 1)
                        end
                    end
                end

                button:SetScript("OnEnter", function(selfBtn)
                    selfBtn._hovered = true
                    applyVisual(selfBtn)
                end)
                button:SetScript("OnLeave", function(selfBtn)
                    selfBtn._hovered = false
                    selfBtn._pressed = false
                    applyVisual(selfBtn)
                end)
                button:SetScript("OnMouseDown", function(selfBtn)
                    selfBtn._pressed = true
                    applyVisual(selfBtn)
                end)
                button:SetScript("OnMouseUp", function(selfBtn)
                    selfBtn._pressed = false
                    applyVisual(selfBtn)
                end)
                return button
            end

            local minusButton = createStepperButton(isMicro and "<" or "-")
            local plusButton = createStepperButton(isMicro and ">" or "+")

            if not isMicro then
                minusButton:SetPoint("LEFT", container, "LEFT", 0, 0)
                plusButton:SetPoint("RIGHT", container, "RIGHT", 0, 0)
            end

            local valueButton = CreateFrame("Button", nil, container)
            local microLayout = nil
            if not isMicro then
                valueButton:SetPoint("LEFT", minusButton, "RIGHT", 6, 0)
                valueButton:SetPoint("RIGHT", plusButton, "LEFT", -6, 0)
                valueButton:SetHeight(18)
            else
                valueButton:SetHeight(16)
                microLayout = function()
                    local gap = 3
                    local buttonW = minusButton:GetWidth() or 10
                    local containerW = container:GetWidth() or 52
                    local valueW = math.max(20, math.min(28, containerW - (buttonW * 2) - (gap * 2)))
                    local clusterW = (buttonW * 2) + valueW + (gap * 2)
                    local startX = math.floor((containerW - clusterW) / 2)
                    if startX < 0 then
                        startX = 0
                    end

                    minusButton:ClearAllPoints()
                    minusButton:SetPoint("LEFT", container, "LEFT", startX, 0)

                    valueButton:ClearAllPoints()
                    valueButton:SetPoint("LEFT", minusButton, "RIGHT", gap, 0)
                    valueButton:SetWidth(valueW)

                    plusButton:ClearAllPoints()
                    plusButton:SetPoint("LEFT", valueButton, "RIGHT", gap, 0)
                end
                microLayout()
                container:HookScript("OnSizeChanged", function()
                    if microLayout then
                        microLayout()
                    end
                end)
            end

            local valueText = createStyledFontString(valueButton, "ARTWORK", "GameFontHighlightSmall", 11)
            valueText:SetPoint("CENTER", valueButton, "CENTER", 0, 0)
            if isMicro then
                valueText:SetTextColor(0.86, 0.86, 0.9, 1)
            else
                valueText:SetTextColor(0.76, 0.76, 0.78, 1)
            end

            local valueEdit = CreateFrame("EditBox", nil, valueButton)
            valueEdit:SetAllPoints(valueButton)
            valueEdit:SetAutoFocus(false)
            valueEdit:SetJustifyH("CENTER")
            valueEdit:SetTextInsets(0, 0, 0, 0)
            valueEdit:SetTextColor(1, 1, 1, 1)
            valueEdit:SetHighlightColor(1, 1, 1, 0.25)
            valueEdit:SetNumeric(true)
            applyGlobalFontToObject(valueEdit, 11)
            valueEdit:Hide()

            local stepValue = tonumber(step) or 1
            if stepValue <= 0 then
                stepValue = 1
            end

            local currentValue = nil
            local editingValue = false
            local controlEnabled = true

            local function normalize(v)
                local n = tonumber(v) or min
                if n < min then n = min end
                if n > max then n = max end
                n = min + (math.floor(((n - min) / stepValue) + 0.5) * stepValue)
                if n < min then n = min end
                if n > max then n = max end
                return math.floor(n + 0.5)
            end

            local function fmt(v)
                return tostring(math.floor((tonumber(v) or 0) + 0.5))
            end

            local function setValue(newValue, triggerApply)
                local n = normalize(newValue)
                if currentValue == n then
                    valueText:SetText(fmt(n))
                    return
                end
                currentValue = n
                if customSetValue then
                    customSetValue(n)
                else
                    PortalAuthorityDB[settingKey] = n
                    if settingKey == "dockFontSize" then
                        PortalAuthorityDB.dockFontSizeUI = n
                    end
                end
                valueText:SetText(fmt(n))
                if triggerApply and onApply then
                    onApply()
                end
            end

            local function beginEdit()
                editingValue = true
                valueText:Hide()
                valueEdit:SetText(fmt(currentValue or min))
                valueEdit:Show()
                valueEdit:SetFocus()
                valueEdit:HighlightText()
            end

            local function endEdit(commit)
                if not editingValue then
                    return
                end
                editingValue = false
                if commit then
                    local parsed = tonumber(valueEdit:GetText())
                    if parsed ~= nil then
                        setValue(parsed, true)
                    end
                end
                valueEdit:Hide()
                valueText:Show()
                valueEdit:ClearFocus()
                valueText:SetText(fmt(currentValue or min))
            end

            local function applyEnabledState()
                local enabledAlpha = controlEnabled and 1 or 0.5
                container:SetAlpha(enabledAlpha)
                label:SetAlpha(enabledAlpha)
                minusButton:SetEnabled(controlEnabled)
                plusButton:SetEnabled(controlEnabled)
                valueButton:SetEnabled(controlEnabled)
                if not controlEnabled and editingValue then
                    endEdit(false)
                end
            end

            minusButton:SetScript("OnClick", function()
                if not controlEnabled then
                    return
                end
                local mult = 1
                if isMicro and IsShiftKeyDown and IsShiftKeyDown() then
                    mult = microShiftMultiplier
                end
                setValue((currentValue or min) - (stepValue * mult), true)
            end)
            plusButton:SetScript("OnClick", function()
                if not controlEnabled then
                    return
                end
                local mult = 1
                if isMicro and IsShiftKeyDown and IsShiftKeyDown() then
                    mult = microShiftMultiplier
                end
                setValue((currentValue or min) + (stepValue * mult), true)
            end)
            valueButton:SetScript("OnClick", function()
                if not controlEnabled then
                    return
                end
                beginEdit()
            end)
            valueEdit:SetScript("OnEnterPressed", function(edit)
                endEdit(true)
                edit:ClearFocus()
            end)
            valueEdit:SetScript("OnEscapePressed", function(edit)
                endEdit(false)
                edit:ClearFocus()
            end)
            valueEdit:SetScript("OnEditFocusLost", function()
                endEdit(true)
            end)

            if tooltipText and tooltipText ~= "" then
                label:SetScript("OnEnter", function(selfLabel)
                    GameTooltip:SetOwner(selfLabel, "ANCHOR_TOPLEFT")
                    GameTooltip:SetText(tooltipText, 1, 0.82, 0, 1)
                    GameTooltip:Show()
                end)
                label:SetScript("OnLeave", function()
                    GameTooltip:Hide()
                end)
            end

            local spec = {
                kind = "stepper",
                label = label,
                control = container,
                valueButton = valueButton,
                valueText = valueText,
                valueEdit = valueEdit,
                minus = minusButton,
                plus = plusButton,
            }
            spec.SetWidth = function(_, newWidth)
                local minWidth = isMicro and 52 or 120
                container:SetWidth(math.max(minWidth, math.floor(tonumber(newWidth) or width or 160)))
            end
            spec.SetEnabled = function(_, enabled)
                controlEnabled = enabled and true or false
                applyEnabledState()
            end
            spec.IsEnabled = function()
                return controlEnabled
            end
            spec.SetVisualValue = function(_, value)
                local n = normalize(value)
                currentValue = n
                valueText:SetText(fmt(n))
                if valueEdit:IsShown() then
                    valueEdit:SetText(fmt(n))
                end
                applyEnabledState()
            end
            spec.Refresh = function()
                local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                local storedValue = nil
                if customGetValue then
                    storedValue = customGetValue()
                else
                    storedValue = PortalAuthorityDB[settingKey]
                    if settingKey == "dockFontSize" then
                        storedValue = tonumber(PortalAuthorityDB.dockFontSizeUI or PortalAuthorityDB.dockFontSize)
                    end
                end
                local n = normalize(storedValue or defaults[settingKey] or min)
                currentValue = n
                if not customGetValue and not customSetValue then
                    PortalAuthorityDB[settingKey] = n
                    if settingKey == "dockFontSize" then
                        PortalAuthorityDB.dockFontSizeUI = n
                    end
                end
                valueText:SetText(fmt(n))
                if valueEdit:IsShown() then
                    valueEdit:SetText(fmt(n))
                end
                applyEnabledState()
            end
            spec.Refresh()
            return settingsSearchRuntime.registerSpec(spec)
        end
        createCanonicalDockFontSizeStepperControl = CreateStepperControl

        local function CreateFontPicker(parent, labelText, settingKey, width, onApply)
            local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
            label:SetText(labelText)

            local function normalizeFontPathKey(path)
                local value = trim(tostring(path or ""))
                value = value:gsub("/", "\\")
                return string.lower(value)
            end

            local function fallbackFontLabelForPath(path)
                local value = trim(tostring(path or ""))
                value = value:gsub("/", "\\")
                if value == "" then
                    return "Global UI Font"
                end
                local name = value:match("([^\\]+)$")
                if name and name ~= "" then
                    return name
                end
                return value
            end

            local function resolveFontSelection(rawValue, options)
                local selectedValue = tostring(rawValue or "")
                local selectedKey = normalizeFontPathKey(selectedValue)
                local selectedLabel = nil
                local matchedValue = selectedValue

                for _, option in ipairs(options or {}) do
                    local optionValue = tostring(option.value or "")
                    if normalizeFontPathKey(optionValue) == selectedKey then
                        matchedValue = optionValue
                        selectedLabel = option.buttonLabel or option.label
                        break
                    end
                end

                if not selectedLabel then
                    selectedLabel = fallbackFontLabelForPath(selectedValue)
                end

                return tostring(matchedValue or ""), tostring(selectedLabel or "")
            end

            local button = CreateFrame("Button", nil, parent, "BackdropTemplate")
            button:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            button:SetBackdropColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
            button:SetBackdropBorderColor(CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A)
            button:SetHeight(22)
            button:SetWidth(math.max(140, tonumber(width) or 220))

            local text = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 11)
            text:SetPoint("LEFT", button, "LEFT", 8, 0)
            text:SetPoint("RIGHT", button, "RIGHT", -18, 0)
            text:SetJustifyH("LEFT")
            text:SetTextColor(0.92, 0.92, 0.92, 1)

            local caret = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 10)
            caret:SetPoint("RIGHT", button, "RIGHT", -7, 0)
            caret:SetText("v")
            caret:SetTextColor(0.76, 0.76, 0.78, 1)

            local picker
            picker = CreatePicker(UIParent, {}, function(value, option, wasClear)
                local selectedValue = value
                if wasClear then
                    selectedValue = ""
                end
                selectedValue = tostring(selectedValue or "")
                PortalAuthorityDB[settingKey] = selectedValue
                local activeOptions = picker and picker._allOptions or {}
                local visualValue, visualLabel = resolveFontSelection(selectedValue, activeOptions)
                text:SetText(visualLabel ~= "" and visualLabel or "Global UI Font")
                if picker then
                    picker:SetSelectedValue(visualValue)
                end
                if onApply then
                    onApply()
                end
            end, {
                title = "Select Font Face",
                searchHint = "Search fonts by name",
                width = 420,
                height = 380,
                showSecondary = false,
                useOptionFontPreview = true,
                previewFontSize = 13,
                rowHeight = 26,
            })

            local function buildFontOptions()
                return buildSharedFontPickerChoices()
            end

            local function applyButtonVisual(hovered)
                if hovered then
                    button:SetBackdropColor(CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A)
                    button:SetBackdropBorderColor(CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A)
                    caret:SetTextColor(0.88, 0.88, 0.90, 1)
                else
                    button:SetBackdropColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
                    button:SetBackdropBorderColor(CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A)
                    caret:SetTextColor(0.76, 0.76, 0.78, 1)
                end
            end

            button:SetScript("OnEnter", function()
                applyButtonVisual(true)
            end)
            button:SetScript("OnLeave", function()
                applyButtonVisual(false)
            end)

            local spec = {
                kind = "font_picker",
                label = label,
                control = button,
                picker = picker,
                text = text,
            }

            spec.SetWidth = function(_, newWidth)
                button:SetWidth(math.max(140, math.floor(tonumber(newWidth) or width or 220)))
            end

            spec.SetVisualSelectedValue = function(_, rawValue)
                local options = picker and picker._allOptions or buildFontOptions()
                if picker and (not picker._allOptions or #picker._allOptions == 0) then
                    picker:SetOptions(options)
                    options = picker._allOptions or options
                end
                local selectedValue, selectedLabel = resolveFontSelection(rawValue, options)
                if picker then
                    picker:SetSelectedValue(selectedValue)
                end
                text:SetText(selectedLabel ~= "" and selectedLabel or "Global UI Font")
            end

            spec.Refresh = function()
                local options = buildFontOptions()
                picker:SetOptions(options)

                local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                local rawValue = PortalAuthorityDB[settingKey]
                if rawValue == nil then
                    rawValue = defaults[settingKey] or ""
                end

                local selectedValue, selectedLabel = resolveFontSelection(rawValue, options)

                picker:SetSelectedValue(selectedValue)
                text:SetText(selectedLabel ~= "" and selectedLabel or "Global UI Font")
                button:SetEnabled(#options > 0)
                button:SetAlpha(#options > 0 and 1 or 0.6)
            end

            button:SetScript("OnClick", function()
                if picker and picker.IsShown and picker:IsShown() then
                    picker:Close()
                    return
                end
                spec.Refresh()
                picker:Open(button)
            end)

            spec.Refresh()
            return settingsSearchRuntime.registerSpec(spec, "font_picker")
        end

        local OFF_RED_BG_R, OFF_RED_BG_G, OFF_RED_BG_B, OFF_RED_BG_A = 0.23, 0.05, 0.075, 0.93
        local OFF_RED_BORDER_R, OFF_RED_BORDER_G, OFF_RED_BORDER_B, OFF_RED_BORDER_A = 0.21, 0.045, 0.068, 0.88
        local OFF_RED_BORDER_SELECTED_R, OFF_RED_BORDER_SELECTED_G, OFF_RED_BORDER_SELECTED_B, OFF_RED_BORDER_SELECTED_A = 0.22, 0.049, 0.074, 1.0
        local OFF_RED_TEXT_R, OFF_RED_TEXT_G, OFF_RED_TEXT_B, OFF_RED_TEXT_A = 0.90, 0.76, 0.76, 1.0
        local OFF_RED_SELECTED_ALPHA = 0.95
        local OFF_RED_TOPSHEEN_ALPHA = 0.14

        local function setSegmentBorderColor(btn, r, g, b, a)
            if not btn then
                return
            end
            if btn._paBorder then
                local rr = tonumber(r) or CONTROL_BASE_BORDER_R
                local gg = tonumber(g) or CONTROL_BASE_BORDER_G
                local bb = tonumber(b) or CONTROL_BASE_BORDER_B
                local aa = tonumber(a) or CONTROL_BASE_BORDER_A
                local colorKey = string.format("%.4f:%.4f:%.4f:%.4f", rr, gg, bb, aa)
                if btn._paBorder._paLastBorderColorKey ~= colorKey then
                    btn._paBorder:SetBackdropBorderColor(rr, gg, bb, aa)
                    btn._paBorder._paLastBorderColorKey = colorKey
                end
                btn._paBorder:SetAlpha(1)
                btn._paBorder:Show()
            end
        end
        local function createSegmentedChoice(labelText, key, choices, onApply, opts)
            return createPremiumSegmentedChoice(scrollChild, labelText, key, choices, onApply, opts)
        end

        local function styleSecondaryActionButton(btn, styleOpts)
            styleSecondaryActionButtonShared(btn, styleOpts)
        end

        local refreshLockDockVisualText
        local applyDockModuleEnabledState
        local applyDockGizmoVisibilityOverrideState
        local function isDockModuleEnabled()
            return PortalAuthorityDB == nil or PortalAuthorityDB.dockEnabled ~= false
        end

        widgets.lockDock = createSegmentedChoice("Lock Position", "dockLocked", {
            { label = "Unlocked", value = false, toggleState = "off" },
            { label = "Locked", value = true, toggleState = "on" },
        }, function()
            if PortalAuthority.UpdateDockMovableState then
                PortalAuthority:UpdateDockMovableState()
            end

            refreshDockVisibility()
            if refreshLockDockVisualText then
                refreshLockDockVisualText()
            end
            if relayout then relayout() end
        end, { semantic = "selection", selectionVariant = "lock_meta" })

        refreshLockDockVisualText = function()
            local isLocked = PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.dockLocked)
            if widgets.lockDock and type(widgets.lockDock.buttons) == "table" then
                for _, btn in ipairs(widgets.lockDock.buttons) do
                    if btn and btn.Text then
                        if btn._value == false then
                            btn.Text:SetText("Unlocked")
                        elseif btn._value == true then
                            btn.Text:SetText("Locked")
                        end
                    end
                end
            end
            if widgets.lockStateHelper then
                if not isDockModuleEnabled() then
                    widgets.lockStateHelper:SetText("Dock is disabled. Re-enable to edit settings.")
                elseif isLocked then
                    widgets.lockStateHelper:SetText("Dock is locked.")
                else
                    widgets.lockStateHelper:SetText("Dock is unlocked - drag to reposition.")
                end
            end
        end
        refreshLockDockVisualText()

        widgets.dockEnabled = createSegmentedChoice("Module", "dockEnabled", {
            { label = "Off", value = false, toggleState = "off" },
            { label = "On", value = true, toggleState = "on" },
        }, function()
            refreshDockVisibility()
            if refreshLockDockVisualText then
                refreshLockDockVisualText()
            end
            if relayout then
                relayout()
            end
            if applyDockModuleEnabledState then
                applyDockModuleEnabledState()
            elseif self and self._refresh then
                self._refresh()
            end
        end, { semantic = "toggle" })
        self._settingsWindowHeaderToggleSource = widgets.dockEnabled

        widgets.hideCity = createSegmentedChoice("Show in Major City", "dockHideInMajorCity", {
            { label = "Off", value = true, toggleState = "off" },
            { label = "On", value = false, toggleState = "on" },
        }, function()
            refreshDockVisibility()
        end, { semantic = "toggle" })

        widgets.hideDungeon = createSegmentedChoice("Show in Dungeon", "dockHideInDungeon", {
            { label = "Off", value = true, toggleState = "off" },
            { label = "On", value = false, toggleState = "on" },
        }, function()
            refreshDockVisibility()
        end, { semantic = "toggle" })

        widgets.hideCombat = createSegmentedChoice("Show in Combat", "dockHideInCombat", {
            { label = "Off", value = true, toggleState = "off" },
            { label = "On", value = false, toggleState = "on" },
        }, function()
            refreshDockVisibility()
        end, { semantic = "toggle" })

            widgets.hideNames = createSegmentedChoice("Show Portal Name", "dockHideDungeonName", {
                { label = "Off", value = true, toggleState = "off" },
                { label = "On", value = false, toggleState = "on" },
            }, function()
                if PortalAuthorityDB.dockHideDungeonName then
                    PortalAuthorityDB.dockLabelMode = "OFF"
                    PortalAuthorityDB.dockLabelModePersist = "OFF"
                else
                    local currentMode = normalizeDockLabelModeValue(PortalAuthorityDB.dockLabelMode)
                    if currentMode == "OFF" then
                        PortalAuthorityDB.dockLabelMode = "OUTSIDE"
                        PortalAuthorityDB.dockLabelModePersist = "OUTSIDE"
                    end
                end
                syncLabelModeSegmentSelection(false)
                syncLabelSideSegmentSelection(false)
                if updateLabelModeApplicability then
                    updateLabelModeApplicability()
                end
                rebuildDock()
            end, { semantic = "toggle" })

        widgets.gizmoMode = createSegmentedChoice("Gizmo Mode |T132311:14:14:0:0:64:64:4:60:4:60|t", "dockGizmoMode", {
            { label = "Off", value = false, toggleState = "off" },
            { label = "On", value = true, toggleState = "on" },
        }, function()
            refreshDockVisibility()
            if applyDockGizmoVisibilityOverrideState then
                applyDockGizmoVisibilityOverrideState()
            end
        end, { semantic = "toggle" })
        do
            local gizmoTooltip = "Only show the dock when the Mythic+ dungeon window is open."
            local gizmoLabel = widgets.gizmoMode and widgets.gizmoMode.label or nil
            if gizmoLabel then
                local hit = gizmoLabel._paGizmoTooltipHit
                if not hit then
                    hit = CreateFrame("Frame", nil, scrollChild)
                    hit:SetPoint("TOPLEFT", gizmoLabel, "TOPLEFT", -2, 2)
                    hit:SetPoint("BOTTOMRIGHT", gizmoLabel, "BOTTOMRIGHT", 2, -2)
                    hit:EnableMouse(true)
                    hit:SetScript("OnEnter", function(selfHit)
                        GameTooltip:SetOwner(selfHit, "ANCHOR_TOP")
                        GameTooltip:SetText(gizmoTooltip, 1, 1, 1, 1)
                        GameTooltip:Show()
                    end)
                    hit:SetScript("OnLeave", function()
                        GameTooltip:Hide()
                    end)
                    gizmoLabel._paGizmoTooltipHit = hit
                end
                hit:SetShown(gizmoLabel:IsShown())
            end
        end

        -- Gizmo Mode temporarily overrides these three controls visually and at runtime
        -- without rewriting the user's saved DB preferences underneath.
        local function setDockVisibilityControlGizmoLocked(spec, locked, moduleEnabled)
            if not spec then
                return
            end

            if spec.SetEnabled then
                spec:SetEnabled(moduleEnabled and true or false)
            end

            if spec.buttons then
                for _, btn in ipairs(spec.buttons) do
                    if btn then
                        btn._paHovered = false
                        btn._paPressed = false
                        if btn.SetPushedTextOffset then
                            btn:SetPushedTextOffset(0, 0)
                        end
                        if btn.EnableMouse then
                            btn:EnableMouse((moduleEnabled and true or false) and (not locked))
                        end
                    end
                end
            end

            if spec.label and spec.label.SetAlpha then
                spec.label:SetAlpha(locked and moduleEnabled and 0.54 or (moduleEnabled and 1 or 0.55))
            end
            if spec.control and spec.control.SetAlpha then
                spec.control:SetAlpha(locked and moduleEnabled and 0.56 or (moduleEnabled and 1 or 0.55))
            end
            if spec.control and spec.control.Text and spec.control.Text.SetAlpha then
                spec.control.Text:SetAlpha(locked and moduleEnabled and 0.56 or (moduleEnabled and 1 or 0.7))
            end
        end

        applyDockGizmoVisibilityOverrideState = function()
            local moduleEnabled = isDockModuleEnabled()
            local gizmoModeEnabled = moduleEnabled and PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.dockGizmoMode)

            local function syncVisibilityControl(spec)
                if not spec then
                    return
                end
                if spec.Refresh then
                    spec:Refresh()
                end
                if gizmoModeEnabled then
                    if spec.SetVisualSelectedValue then
                        spec:SetVisualSelectedValue(false)
                    elseif spec.SetSelectedValue then
                        spec:SetSelectedValue(false, false)
                    end
                    setDockVisibilityControlGizmoLocked(spec, true, moduleEnabled)
                else
                    setSettingsControlEnabled(spec, moduleEnabled)
                    setDockVisibilityControlGizmoLocked(spec, false, moduleEnabled)
                end
            end

            syncVisibilityControl(widgets.hideCity)
            syncVisibilityControl(widgets.hideDungeon)
            syncVisibilityControl(widgets.hideCombat)
        end

        for _, spec in ipairs({ widgets.dockEnabled, widgets.hideCity, widgets.hideCombat, widgets.hideDungeon, widgets.gizmoMode }) do
            if spec and spec.label then
                spec.label:SetWordWrap(false)
                if spec.label.SetMaxLines then
                    spec.label:SetMaxLines(1)
                end
            end
        end

        styleSecondaryActionButton(widgets.resetDockAnchor, {
            baseBg = { 0.06, 0.07, 0.09, 0.95 },
            hoverBg = { 0.08, 0.09, 0.11, 0.95 },
            pressedBg = { 0.05, 0.06, 0.08, 0.96 },
            baseBorder = { 0.21, 0.24, 0.28, 0.62 },
            hoverBorder = { 0.25, 0.28, 0.33, 0.68 },
            pressedBorder = { 0.23, 0.26, 0.30, 0.66 },
            textColor = { 0.82, 0.83, 0.86, 1 },
        })
        widgets.resetDockAnchor:HookScript("OnEnter", function(selfButton)
            GameTooltip:SetOwner(selfButton, "ANCHOR_TOP")
            GameTooltip:SetText("Resets dock position to default.", 1, 1, 1, 1)
            GameTooltip:Show()
        end)
        widgets.resetDockAnchor:HookScript("OnLeave", function()
            GameTooltip:Hide()
        end)
        widgets.loadoutPresetSegment = createSegmentedChoice("", "dockLoadoutPreset", {
            { label = "|TInterface\\AddOns\\PortalAuthority\\Media\\Images\\WoW_Overclock_Midnight_Logo_enUS_64.png:24:24:0:0|t Midnight Season 01", value = "SEASON_01" },
            { label = "Custom", value = "CUSTOM" },
        }, function(value)
            local selectedPreset = normalizeLoadoutPresetValue(value)
            local previousPreset = lastLoadoutPresetSelection
            lastLoadoutPresetSelection = selectedPreset
            if widgets.destinationPicker and widgets.destinationPicker.Close then
                widgets.destinationPicker:Close()
            end
            if selectedPreset == "CUSTOM" then
                local restored = restoreCustomLoadoutSnapshot()
                if restored then
                    onUIChanged(false)
                end
            elseif selectedPreset == "SEASON_01" then
                if previousPreset == "CUSTOM" then
                    saveCustomLoadoutSnapshot()
                end
                suppressLoadoutPresetAutoCustom = true
                applySeason01Loadout()
                suppressLoadoutPresetAutoCustom = false
            end
        end, { semantic = "selection" })
        if widgets.loadoutPresetSegment and widgets.loadoutPresetSegment.label then
            widgets.loadoutPresetSegment.label:SetText("")
            widgets.loadoutPresetSegment.label:Hide()
        end

        local function CreateLayoutSection()
            widgets.layoutSectionHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
            widgets.layoutSectionHeader:SetText("Structure")
            widgets.layoutSectionHeader:SetTextColor(1, 1, 1, 1)

            widgets.layoutModeSegment = createSegmentedChoice("Layout Mode", "dockSimpleLayoutMode", {
                { label = "Horizontal Row", value = "HORIZONTAL_ROW" },
                { label = "Vertical Column", value = "VERTICAL_COLUMN" },
                { label = "Grid", value = "GRID" },
            }, function(value)
                PortalAuthorityDB.dockSimpleLayoutMode = normalizeDockSimpleLayoutModeValue(value or PortalAuthorityDB.dockSimpleLayoutMode)
                PortalAuthorityDB.dockSimpleLayoutModePersist = PortalAuthorityDB.dockSimpleLayoutMode
                ApplyDockLayoutSettings(false)
                updateLayoutModeApplicability()
                syncLayoutModeSegmentSelection(false)
                if C_Timer and C_Timer.After then
                    C_Timer.After(0, function()
                        if not panel or not panel:IsShown() then
                            return
                        end
                        syncLayoutModeSegmentSelection(false)
                        updateLayoutModeApplicability()
                    end)
                end
            end, {
                semantic = "selection",
                normalizeValue = normalizeDockSimpleLayoutModeValue,
                getValue = function()
                    local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                    local mode = getDockSimpleLayoutModeForSettings(defaults)
                    return mode
                end,
                setValue = function(mode)
                    local value = normalizeDockSimpleLayoutModeValue(mode)
                    PortalAuthorityDB.dockSimpleLayoutMode = value
                    PortalAuthorityDB.dockSimpleLayoutModePersist = value
                end,
            })

            widgets.iconsPerRow = CreateStepperControl(scrollChild, "Wrap", 1, 10, 1, "dockIconsPerLine", FIXED_FOOTPRINTS.LAYOUT_STEPPER_SEED_W, function()
                PortalAuthorityDB.dockWrapAfter = PortalAuthorityDB.dockIconsPerLine
                ApplyDockLayoutSettings(false)
            end)
            widgets.iconsPerRowGridOnlyHint = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
            widgets.iconsPerRowGridOnlyHint:SetText("Grid only")
            widgets.iconsPerRowGridOnlyHint:SetTextColor(0.58, 0.58, 0.58, 0.92)
            widgets.iconsPerRowGridOnlyHint:Hide()

            widgets.layoutIconSize = CreatePremiumSlider(scrollChild, "Icon Size", 16, 72, 1, "dockIconSize", FIXED_FOOTPRINTS.LAYOUT_ICON_SLIDER_SEED_W, function()
                ApplyDockLayoutSettings(false)
            end)

            widgets.layoutSpacingHint = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
            widgets.layoutSpacingHint:SetText("Tip: Unlock the dock to adjust icon spacing visually.")
            widgets.layoutSpacingHint:SetTextColor(0.58, 0.58, 0.58, 0.92)
        end

        local function CreateAppearanceSection()
            widgets.labelsSectionHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
            widgets.labelsSectionHeader:SetText("Labels")
            widgets.labelsSectionHeader:SetTextColor(1, 1, 1, 1)

            local function applyDockLabelSideSelection(value, modeOverride)
                local resolvedMode = normalizeDockLabelModeValue(modeOverride or (PortalAuthorityDB and PortalAuthorityDB.dockLabelMode) or "OUTSIDE")
                setDockLabelSideForSettings(value, resolvedMode)
                ApplyDockAppearanceSettings()
                syncLabelSideSegmentSelection(false)
                if updateLabelModeApplicability then
                    updateLabelModeApplicability()
                end
                relayout()
                if C_Timer and C_Timer.After then
                    C_Timer.After(0, function()
                        if not panel or not panel:IsShown() then
                            return
                        end
                        syncLabelSideSegmentSelection(true)
                        if updateLabelModeApplicability then
                            updateLabelModeApplicability()
                        end
                        relayout()
                    end)
                end
            end

            widgets.labelMode = createSegmentedChoice("Labels", "dockLabelMode", {
                { label = "Off", value = "OFF", toggleState = "off" },
                { label = "Outside", value = "OUTSIDE", toggleState = "on" },
                { label = "Inside", value = "INSIDE", toggleState = "on" },
            }, function(value)
                local resolvedMode = normalizeDockLabelModeValue(value or PortalAuthorityDB.dockLabelMode)
                PortalAuthorityDB.dockLabelMode = resolvedMode
                PortalAuthorityDB.dockLabelModePersist = resolvedMode
                PortalAuthorityDB.dockHideDungeonName = (resolvedMode == "OFF")
                ApplyDockAppearanceSettings()
                syncLabelModeSegmentSelection(false)
                syncLabelSideSegmentSelection(false)
                if updateLabelModeApplicability then
                    updateLabelModeApplicability()
                end
                relayout()
                if C_Timer and C_Timer.After then
                    C_Timer.After(0, function()
                        if not panel or not panel:IsShown() then
                            return
                        end
                        syncLabelModeSegmentSelection(true)
                        syncLabelSideSegmentSelection(true)
                        if updateLabelModeApplicability then
                            updateLabelModeApplicability()
                        end
                        relayout()
                    end)
                end
            end, {
                semantic = "selection",
                normalizeValue = normalizeDockLabelModeValue,
                getValue = function()
                    local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                    return getDockLabelModeForSettings(defaults)
                end,
                setValue = function(mode)
                    local resolvedMode = normalizeDockLabelModeValue(mode)
                    PortalAuthorityDB.dockLabelMode = resolvedMode
                    PortalAuthorityDB.dockLabelModePersist = resolvedMode
                    PortalAuthorityDB.dockHideDungeonName = (resolvedMode == "OFF")
                end,
            })

            widgets.labelSide = createSegmentedChoice("Label Side", "dockLabelSide", {
                { label = "Bottom", value = "BOTTOM" },
                { label = "Top", value = "TOP" },
                { label = "Left", value = "LEFT" },
                { label = "Right", value = "RIGHT" },
            }, function(value)
                applyDockLabelSideSelection(value or (PortalAuthorityDB and PortalAuthorityDB.dockLabelSide), "OUTSIDE")
            end, {
                semantic = "selection",
                normalizeValue = normalizeDockLabelSideValue,
                getValue = function()
                    local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                    return getDockOutsideLabelSideForSettings(defaults)
                end,
                setValue = function(side)
                    setDockLabelSideForSettings(side, "OUTSIDE")
                end,
            })

            do
                local insideContainer = CreateFrame("Frame", nil, scrollChild)
                local topBottom = createPremiumSegmentedChoice(insideContainer, "", nil, {
                    { label = "Top", value = "TOP" },
                    { label = "Bottom", value = "BOTTOM" },
                }, function(value)
                    applyDockLabelSideSelection(value, "INSIDE")
                end, {
                    semantic = "selection",
                    normalizeValue = normalizeDockLabelSideValue,
                    minWidth = 0,
                })
                local center = createPremiumSegmentedChoice(insideContainer, "", nil, {
                    { label = "Center", value = "CENTER" },
                }, function(value)
                    applyDockLabelSideSelection(value, "INSIDE")
                end, {
                    semantic = "selection",
                    normalizeValue = normalizeDockLabelSideValue,
                    minWidth = 0,
                })

                if topBottom.label then
                    topBottom.label:Hide()
                end
                if center.label then
                    center.label:Hide()
                end

                widgets.labelSideInside = {
                    kind = "segmented_composite",
                    label = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12),
                    control = insideContainer,
                    topBottom = topBottom,
                    center = center,
                }
                widgets.labelSideInside.label:SetText("Label Side")

                widgets.labelSideInside.Layout = function(_, width)
                    local totalWidth = math.max(120, tonumber(width) or 120)
                    local groupGap = 4
                    local halfWidth = math.max(58, (totalWidth - groupGap) / 2)

                    insideContainer:SetSize(totalWidth, 22)

                    topBottom.control:ClearAllPoints()
                    topBottom.control:SetPoint("TOPLEFT", insideContainer, "TOPLEFT", 0, 0)
                    topBottom:Layout(halfWidth)

                    center.control:ClearAllPoints()
                    center.control:SetPoint("TOPLEFT", topBottom.control, "TOPRIGHT", groupGap, 0)
                    center:Layout(halfWidth)

                    if topBottom.label then
                        topBottom.label:Hide()
                    end
                    if center.label then
                        center.label:Hide()
                    end
                end

                widgets.labelSideInside.Refresh = function(self)
                    local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                    self:SetVisualSelectedValue(getDockInsideLabelSideForSettings(defaults))
                end

                widgets.labelSideInside.SetVisualSelectedValue = function(_, value)
                    local visual = normalizeDockLabelSideValue(value)
                    if visual ~= "TOP" and visual ~= "BOTTOM" then
                        visual = "CENTER"
                    end
                    topBottom:SetVisualSelectedValue(visual)
                    center:SetVisualSelectedValue(visual)
                end

                widgets.labelSideInside.SetEnabled = function(_, enabled)
                    topBottom:SetEnabled(enabled and true or false)
                    center:SetEnabled(enabled and true or false)
                    widgets.labelSideInside.label:SetAlpha(enabled and 1 or 0.65)
                end

                widgets.labelSideInside:Refresh()
            end

            widgets.styleSectionHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
            widgets.styleSectionHeader:SetText("Style")
            widgets.styleSectionHeader:SetTextColor(1, 1, 1, 1)

            widgets.font = CreateFontPicker(scrollChild, "Font", "dockFontPath", FIXED_FOOTPRINTS.FONT_PICKER_SEED_W, function()
                ApplyDockAppearanceSettings()
            end)
            widgets.fontSize = CreateStepperControl(scrollChild, "Size", 8, 48, 1, "dockFontSize", FIXED_FOOTPRINTS.FONT_SIZE_STEPPER_SEED_W, function()
                ApplyDockAppearanceSettings()
            end, nil, { micro = true, shiftMultiplier = 5 })
            if widgets.fontSize and widgets.fontSize.label then
                widgets.fontSize.label:SetText("")
                widgets.fontSize.label:Hide()
            end
            widgets.outlineToggle = createSegmentedChoice("Outline", "dockTextOutline", {
                { label = "Off", value = "", toggleState = "off" },
                { label = "On", value = "OUTLINE", toggleState = "on" },
            }, function()
                ApplyDockAppearanceSettings()
            end, {
                semantic = "toggle",
                normalizeValue = normalizeOutlineToggleValue,
                getValue = function()
                    local raw = PortalAuthorityDB and PortalAuthorityDB.dockTextOutline or ""
                    return normalizeOutlineToggleValue(raw)
                end,
                setValue = function(value)
                    PortalAuthorityDB.dockTextOutline = normalizeOutlineToggleValue(value)
                end,
            })

            widgets.color = {}
            widgets.color.inlineLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
            widgets.color.inlineLabel:SetText("")
            widgets.color.inlineLabel:Hide()
            widgets.color.swatch = CreateFrame("Button", nil, scrollChild, "BackdropTemplate")
            widgets.color.swatch:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
                edgeSize = 10,
                insets = { left = 2, right = 2, top = 2, bottom = 2 },
            })

            widgets.hoverGlowSegment = createSegmentedChoice("Hover Glow", "dockHoverGlow", {
                { label = "Off", value = false, toggleState = "off" },
                { label = "On", value = true, toggleState = "on" },
            }, function()
                ApplyDockAppearanceSettings()
            end, {
                semantic = "toggle",
                normalizeValue = normalizeHoverGlowToggleValue,
                getValue = function()
                    return normalizeHoverGlowToggleValue(PortalAuthorityDB and PortalAuthorityDB.dockHoverGlow)
                end,
                setValue = function(value)
                    PortalAuthorityDB.dockHoverGlow = normalizeHoverGlowToggleValue(value)
                end,
            })
        end

        widgets.portalSlotsLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        widgets.portalSlotsLabel:SetText("")
        widgets.portalSlotsLabel:SetTextColor(1, 1, 1, 1)
        widgets.slotColStatus = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.slotColStatus:SetText("")
        widgets.slotColDestination = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.slotColDestination:SetText("Destination")
        widgets.slotColName = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.slotColName:SetText("Label")
        widgets.slotColSpellID = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.slotColSpellID:SetText("Spell ID")
        widgets.slotColResult = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.slotColResult:SetText("")
        CreateLayoutSection()
        CreateAppearanceSection()
        updateLayoutModeApplicability()
        syncLabelModeSegmentSelection(true)
        syncLabelSideSegmentSelection(true)
        if updateLabelModeApplicability then
            updateLabelModeApplicability()
        end
        local initialDestinationChoices = getDestinationChoices()
        widgets.destinationPicker = CreatePicker(UIParent, initialDestinationChoices, nil)
        widgets.destinationPicker._sourceOptionsRef = initialDestinationChoices
        widgets.destinationPicker:HookScript("OnHide", function(picker)
            local owner = picker and picker._ownerButton or nil
            if owner and owner.SetPillState then
                owner:SetPillState("normal")
            elseif owner and owner.UpdateVisual then
                owner._open = false
                owner:UpdateVisual()
            end
            if picker then
                picker._ownerButton = nil
            end
        end)
        local function captureDockPopoverTemplateChromeRegions(edit)
            if not edit or edit._paDockPopoverTemplateChromeRegions then
                return
            end

            local regions = {}
            local seen = {}
            local function capture(region)
                if not region or seen[region] then
                    return
                end
                if not region.GetObjectType or region:GetObjectType() ~= "Texture" then
                    return
                end
                seen[region] = true
                regions[#regions + 1] = region
            end

            capture(edit.Left)
            capture(edit.Middle)
            capture(edit.Right)

            if edit.GetRegions then
                for i = 1, select("#", edit:GetRegions()) do
                    capture(select(i, edit:GetRegions()))
                end
            end

            edit._paDockPopoverTemplateChromeRegions = regions
        end

        local function suppressDockPopoverTemplateChrome(edit)
            if not edit then
                return
            end

            captureDockPopoverTemplateChromeRegions(edit)
            for _, region in ipairs(edit._paDockPopoverTemplateChromeRegions or {}) do
                if region.SetAlpha then
                    region:SetAlpha(0)
                end
                if region.Hide then
                    region:Hide()
                end
            end
        end

        local function ensureDockPopoverEditSkin(edit, textSize)
            if not edit then
                return
            end

            captureDockPopoverTemplateChromeRegions(edit)
            applyGlobalFontToObject(edit, tonumber(textSize) or 11)
            edit:SetTextColor(1, 1, 1, 1)
            edit:SetTextInsets(8, 8, 0, 0)
            edit:SetJustifyH("LEFT")

            if not edit._paPremiumBg then
                edit._paPremiumBg = edit:CreateTexture(nil, "BACKGROUND")
                edit._paPremiumBg:SetAllPoints(edit)
                edit._paPremiumBg:SetTexture("Interface\\Buttons\\WHITE8x8")
                edit._paPremiumBorder = CreateFrame("Frame", nil, edit, "BackdropTemplate")
                edit._paPremiumBorder:SetBackdrop({
                    edgeFile = "Interface\\Buttons\\WHITE8x8",
                    edgeSize = 1,
                })
            end

            local function refreshDockPopoverEditSkin()
                suppressDockPopoverTemplateChrome(edit)
                local parent = edit:GetParent()
                local parentStrata = parent and parent.GetFrameStrata and parent:GetFrameStrata() or "DIALOG"
                local parentLevel = parent and parent.GetFrameLevel and parent:GetFrameLevel() or 1
                edit:SetFrameStrata(parentStrata)
                edit:SetFrameLevel(math.max(parentLevel + 10, edit:GetFrameLevel() or 1))
                if edit._paPremiumBorder then
                    edit._paPremiumBorder:SetPoint("TOPLEFT", edit, "TOPLEFT", -1, 1)
                    edit._paPremiumBorder:SetPoint("BOTTOMRIGHT", edit, "BOTTOMRIGHT", 1, -1)
                    edit._paPremiumBorder:SetFrameStrata(parentStrata)
                    edit._paPremiumBorder:SetFrameLevel(math.max(parentLevel + 9, 1))
                end
                if edit:HasFocus() then
                    edit._paPremiumBg:SetVertexColor(0.12, 0.13, 0.17, 0.95)
                    edit._paPremiumBorder:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                else
                    edit._paPremiumBg:SetVertexColor(0.10, 0.11, 0.14, 0.95)
                    edit._paPremiumBorder:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                end
            end

            if not edit._paDockPopoverSkinInitialized then
                edit:HookScript("OnShow", refreshDockPopoverEditSkin)
                edit:HookScript("OnEditFocusGained", refreshDockPopoverEditSkin)
                edit:HookScript("OnEditFocusLost", refreshDockPopoverEditSkin)
                edit._paDockPopoverSkinInitialized = true
                edit._paDockPopoverRefreshVisual = refreshDockPopoverEditSkin
            end

            refreshDockPopoverEditSkin()
        end

        local function restoreDockPopoverAnchorLabel(popover, anchorRow)
            if not popover then
                return
            end

            local label = popover._paSuppressedAnchorLabel
            if label then
                if popover._paSuppressedAnchorLabelWasShown then
                    if label.Show then
                        label:Show()
                    end
                else
                    if label.Hide then
                        label:Hide()
                    end
                end
                if label.SetAlpha then
                    label:SetAlpha(popover._paSuppressedAnchorLabelAlpha or 1)
                end
            end

            popover._paSuppressedAnchorLabel = nil
            popover._paSuppressedAnchorLabelAlpha = nil
            popover._paSuppressedAnchorLabelWasShown = nil

            anchorRow = anchorRow or popover.anchorRow
            if type(popover._paReleaseAnchorVisual) == "function" then
                popover._paReleaseAnchorVisual(anchorRow)
            end
        end

        local function suppressDockPopoverAnchorLabel(popover, row)
            if not popover then
                return
            end

            restoreDockPopoverAnchorLabel(popover)

            local anchorLabelKey = popover._paAnchorLabelKey
            local anchorLabel = anchorLabelKey and row and row[anchorLabelKey] and row[anchorLabelKey].label or nil
            if anchorLabel and anchorLabel.GetAlpha and anchorLabel.SetAlpha then
                popover._paSuppressedAnchorLabel = anchorLabel
                popover._paSuppressedAnchorLabelAlpha = anchorLabel:GetAlpha()
                popover._paSuppressedAnchorLabelWasShown = anchorLabel.IsShown and anchorLabel:IsShown() or true
                if anchorLabel.Hide then
                    anchorLabel:Hide()
                else
                    anchorLabel:SetAlpha(0)
                end
            end

            if type(popover._paApplyAnchorVisual) == "function" then
                popover._paApplyAnchorVisual(row)
            end
        end

        widgets.renamePopover = CreateFrame("Frame", nil, scrollChild, "BackdropTemplate")
        widgets.renamePopover:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            edgeSize = 10,
            insets = { left = 2, right = 2, top = 2, bottom = 2 },
        })
        widgets.renamePopover:SetBackdropColor(0.05, 0.06, 0.08, 0.98)
        widgets.renamePopover:SetBackdropBorderColor(0.24, 0.27, 0.31, 1)
        widgets.renamePopover:SetFrameStrata("DIALOG")
        widgets.renamePopover:SetToplevel(true)
        widgets.renamePopover:SetClampedToScreen(true)
        widgets.renamePopover:Hide()
        widgets.renamePopover.slotIndex = nil
        widgets.renamePopover.anchorRow = nil
        widgets.renamePopover.originalText = ""

        widgets.renamePopover.edit = CreateFrame("EditBox", nil, widgets.renamePopover, "InputBoxTemplate")
        widgets.renamePopover.edit:SetAutoFocus(false)
        widgets.renamePopover.edit:SetTextInsets(8, 8, 0, 0)
        widgets.renamePopover.edit:SetTextColor(1, 1, 1, 1)
        widgets.renamePopover.edit:SetHighlightColor(1, 1, 1, 0.25)
        widgets.renamePopover.edit:SetMaxLetters(DOCK_NAME_MAX_LEN)
        ensureDockPopoverEditSkin(widgets.renamePopover.edit, 11)
        widgets.renamePopover._paAnchorLabelKey = "namePill"
        widgets.renamePopover._paApplyAnchorVisual = function(row)
            if row and row.namePill and row.namePill.SetPillState then
                row.namePill:SetPillState("focus")
            elseif row and row.namePill and row.namePill.UpdateVisual then
                row.namePill._focused = true
                row.namePill:UpdateVisual()
            end
        end
        widgets.renamePopover._paReleaseAnchorVisual = function(row)
            if row and row.namePill and row.namePill.SetPillState then
                row.namePill:SetPillState("normal")
            elseif row and row.namePill and row.namePill.UpdateVisual then
                row.namePill._focused = false
                row.namePill:UpdateVisual()
            end
        end

        widgets.renamePopover.hint = createStyledFontString(widgets.renamePopover, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.renamePopover.hint:SetJustifyH("LEFT")
        widgets.renamePopover.hint:SetTextColor(0.72, 0.72, 0.72, 1)
        widgets.renamePopover.hint:SetText("")

        local function updateRenameHint()
            local pop = widgets.renamePopover
            if not pop or not pop.edit or not pop.hint then
                return
            end
            local text = tostring(pop.edit:GetText() or "")
            local n = string.len(text)
            local over = n > DOCK_NAME_MAX_LEN
            pop.hint:SetText(string.format("%d/%d", n, DOCK_NAME_MAX_LEN))
            if over then
                pop.hint:SetTextColor(1, 0.36, 0.36, 1)
            else
                pop.hint:SetTextColor(0.72, 0.72, 0.72, 1)
            end
        end

        function widgets.renamePopover:Close(save)
            local slotIndex = self.slotIndex
            local edit = self.edit
            local anchorRow = self.anchorRow
            if not self:IsShown() then
                self.slotIndex = nil
                self.anchorRow = nil
                self.originalText = ""
                restoreDockPopoverAnchorLabel(self, anchorRow)
                return
            end

            local changed = false
            if save and slotIndex then
                local slot = getDockSlot(slotIndex)
                local previousName = tostring(slot.name or "")
                local previousRenamed = slot.renamed == true
                local text = trim(edit:GetText() or "")
                setDockSlotCustomName(slot, text)
                if tostring(slot.name or "") ~= previousName or (slot.renamed == true) ~= previousRenamed then
                    changed = true
                end
            end

            self.slotIndex = nil
            self.anchorRow = nil
            self.originalText = ""
            restoreDockPopoverAnchorLabel(self, anchorRow)
            self:Hide()
            if edit then
                edit:ClearFocus()
            end
            if changed then
                setLoadoutPresetCustom()
                onUIChanged(false)
            end
        end

        function widgets.renamePopover:OpenForRow(slotIndex, row)
            if not row or not row.namePill then
                return
            end
            if widgets.spellIDPopover and widgets.spellIDPopover:IsShown() and widgets.spellIDPopover.Close then
                widgets.spellIDPopover:Close(false)
            end
            if self.anchorRow and self.anchorRow ~= row then
                restoreDockPopoverAnchorLabel(self, self.anchorRow)
            end
            local slot = getDockSlot(slotIndex)
            if not slot.enabled then
                return
            end

            local current = getDockSlotDisplayName(slot)

            self:ClearAllPoints()
            self:SetFrameLevel(math.max((row.namePill:GetFrameLevel() or 1) + 20, self:GetFrameLevel() or 1))
            self:SetPoint("TOPLEFT", row.namePill, "TOPLEFT", -2, 2)
            self:SetPoint("TOPRIGHT", row.namePill, "TOPRIGHT", 2, 2)
            self:SetHeight(44)
            self.edit:ClearAllPoints()
            self.edit:SetPoint("TOPLEFT", self, "TOPLEFT", 6, -6)
            self.edit:SetPoint("TOPRIGHT", self, "TOPRIGHT", -6, -6)
            self.edit:SetHeight(20)
            self.hint:ClearAllPoints()
            self.hint:SetPoint("TOPLEFT", self.edit, "BOTTOMLEFT", 2, -2)

            self.slotIndex = slotIndex
            self.anchorRow = row
            self.originalText = current
            suppressDockPopoverAnchorLabel(self, row)
            self.edit:SetText(current)
            updateRenameHint()
            self:Show()
            self:Raise()
            if self.edit._paDockPopoverRefreshVisual then
                self.edit._paDockPopoverRefreshVisual()
            end
            self.edit:SetFocus()
            if self.edit.HighlightText then
                self.edit:HighlightText(0, 0)
            end
            if self.edit.SetCursorPosition then
                self.edit:SetCursorPosition(string.len(current or ""))
            end
        end

        widgets.renamePopover.edit:SetScript("OnEnterPressed", function()
            widgets.renamePopover:Close(true)
        end)
        widgets.renamePopover.edit:SetScript("OnEscapePressed", function()
            widgets.renamePopover:Close(false)
        end)
        widgets.renamePopover.edit:SetScript("OnEditFocusLost", function()
            if widgets.renamePopover and widgets.renamePopover:IsShown() then
                widgets.renamePopover:Close(false)
            end
        end)
        widgets.renamePopover.edit:SetScript("OnTextChanged", function()
            updateRenameHint()
        end)

        local DOCK_SPELLID_MAX_LEN = 10
        widgets.spellIDPopover = CreateFrame("Frame", nil, scrollChild, "BackdropTemplate")
        widgets.spellIDPopover:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            edgeSize = 10,
            insets = { left = 2, right = 2, top = 2, bottom = 2 },
        })
        widgets.spellIDPopover:SetBackdropColor(0.05, 0.06, 0.08, 0.98)
        widgets.spellIDPopover:SetBackdropBorderColor(0.24, 0.27, 0.31, 1)
        widgets.spellIDPopover:SetFrameStrata("DIALOG")
        widgets.spellIDPopover:SetToplevel(true)
        widgets.spellIDPopover:SetClampedToScreen(true)
        widgets.spellIDPopover:Hide()
        widgets.spellIDPopover.slotIndex = nil
        widgets.spellIDPopover.anchorRow = nil
        widgets.spellIDPopover.originalText = ""

        widgets.spellIDPopover.edit = CreateFrame("EditBox", nil, widgets.spellIDPopover, "InputBoxTemplate")
        widgets.spellIDPopover.edit:SetAutoFocus(false)
        widgets.spellIDPopover.edit:SetTextInsets(8, 8, 0, 0)
        widgets.spellIDPopover.edit:SetTextColor(1, 1, 1, 1)
        widgets.spellIDPopover.edit:SetHighlightColor(1, 1, 1, 0.25)
        widgets.spellIDPopover.edit:SetMaxLetters(DOCK_SPELLID_MAX_LEN)
        ensureDockPopoverEditSkin(widgets.spellIDPopover.edit, 11)
        widgets.spellIDPopover._paAnchorLabelKey = "spellIDPill"
        widgets.spellIDPopover._paApplyAnchorVisual = nil
        widgets.spellIDPopover._paReleaseAnchorVisual = nil

        widgets.spellIDPopover.hint = createStyledFontString(widgets.spellIDPopover, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.spellIDPopover.hint:SetJustifyH("LEFT")
        widgets.spellIDPopover.hint:SetTextColor(0.72, 0.72, 0.72, 1)
        widgets.spellIDPopover.hint:SetText("")

        local function updateSpellIDHint()
            local pop = widgets.spellIDPopover
            if not pop or not pop.edit or not pop.hint then
                return
            end
            local text = trim(tostring(pop.edit:GetText() or ""))
            local n = string.len(text)
            local over = n > DOCK_SPELLID_MAX_LEN
            local numeric = (text == "" or text:match("^%d+$") ~= nil)
            pop.hint:SetText(string.format("%d/%d", n, DOCK_SPELLID_MAX_LEN))
            if over or not numeric then
                pop.hint:SetTextColor(1, 0.36, 0.36, 1)
            else
                pop.hint:SetTextColor(0.72, 0.72, 0.72, 1)
            end
        end

        function widgets.spellIDPopover:Close(save)
            local slotIndex = self.slotIndex
            local edit = self.edit
            local anchorRow = self.anchorRow
            if not self:IsShown() then
                self.slotIndex = nil
                self.anchorRow = nil
                self.originalText = ""
                restoreDockPopoverAnchorLabel(self, anchorRow)
                return
            end

            local changed = false
            if save and slotIndex then
                local slot = getDockSlot(slotIndex)
                local rawValue = tonumber(edit:GetText() or "")
                if rawValue ~= nil then
                    local spellID = resolveSpellIDFromVisualDockID(rawValue)
                    if slot.spellID ~= spellID then
                        changed = true
                    end
                    slot.spellID = spellID
                    if spellID > 0 and getDestinationOptionByValue(tostring(spellID)) then
                        slot.selection = tostring(spellID)
                    else
                        slot.selection = "CUSTOM"
                    end
                    setDockSlotDefaultName(slot, spellID)
                    if spellID > 0 and trim(slot.name or "") == "" then
                        requestSpellDataRefresh(slotIndex, spellID)
                    end
                end
            end

            self.slotIndex = nil
            self.anchorRow = nil
            self.originalText = ""
            restoreDockPopoverAnchorLabel(self, anchorRow)
            self:Hide()
            if edit then
                edit:ClearFocus()
            end
            if changed then
                setLoadoutPresetCustom()
                onUIChanged(false)
            end
        end

        function widgets.spellIDPopover:OpenForRow(slotIndex, row)
            if not row or not row.spellIDPill then
                return
            end
            local slot = getDockSlot(slotIndex)
            if not slot.enabled then
                return
            end

            if widgets.renamePopover and widgets.renamePopover:IsShown() and widgets.renamePopover.Close then
                widgets.renamePopover:Close(false)
            end
            if self.anchorRow and self.anchorRow ~= row then
                restoreDockPopoverAnchorLabel(self, self.anchorRow)
            end

            local current = tostring(getVisualDockIDForSpell(slot.spellID or 0))
            self:ClearAllPoints()
            self:SetFrameLevel(math.max((row.spellIDPill:GetFrameLevel() or 1) + 20, self:GetFrameLevel() or 1))
            self:SetPoint("TOPLEFT", row.spellIDPill, "TOPLEFT", -2, 2)
            self:SetPoint("TOPRIGHT", row.spellIDPill, "TOPRIGHT", 2, 2)
            self:SetHeight(44)
            self.edit:ClearAllPoints()
            self.edit:SetPoint("TOPLEFT", self, "TOPLEFT", 6, -6)
            self.edit:SetPoint("TOPRIGHT", self, "TOPRIGHT", -6, -6)
            self.edit:SetHeight(20)
            self.hint:ClearAllPoints()
            self.hint:SetPoint("TOPLEFT", self.edit, "BOTTOMLEFT", 2, -2)

            self.slotIndex = slotIndex
            self.anchorRow = row
            self.originalText = current
            suppressDockPopoverAnchorLabel(self, row)
            self.edit:SetText(current)
            updateSpellIDHint()
            self:Show()
            self:Raise()
            if self.edit._paDockPopoverRefreshVisual then
                self.edit._paDockPopoverRefreshVisual()
            end
            self.edit:SetFocus()
            if self.edit.HighlightText then
                self.edit:HighlightText(0, 0)
            end
            if self.edit.SetCursorPosition then
                self.edit:SetCursorPosition(string.len(current or ""))
            end
        end

        widgets.spellIDPopover.edit:SetScript("OnEnterPressed", function()
            widgets.spellIDPopover:Close(true)
        end)
        widgets.spellIDPopover.edit:SetScript("OnEscapePressed", function()
            widgets.spellIDPopover:Close(false)
        end)
        widgets.spellIDPopover.edit:SetScript("OnEditFocusLost", function()
            if widgets.spellIDPopover and widgets.spellIDPopover:IsShown() then
                widgets.spellIDPopover:Close(false)
            end
        end)
        widgets.spellIDPopover.edit:SetScript("OnTextChanged", function()
            updateSpellIDHint()
        end)

        local function setPillCursor(mode)
            if not SetCursor and not ResetCursor then
                return
            end

            local function trySet(path)
                if not SetCursor or not path or path == "" then
                    return false
                end
                local ok = pcall(SetCursor, path)
                return ok and true or false
            end

            if mode == "ibeam" then
                if trySet("Interface\\Cursor\\UI-Cursor-Chat") then
                    return
                end
                if trySet("Interface\\CURSOR\\UI-Cursor-Chat") then
                    return
                end
            elseif mode == "hand" then
                if trySet("Interface\\Cursor\\UI-Cursor-Move") then
                    return
                end
                if trySet("Interface\\CURSOR\\UI-Cursor-Move") then
                    return
                end
            end

            if ResetCursor then
                pcall(ResetCursor)
            end
        end

        local function SetPillState(frame, state)
            if not frame then
                return
            end
            local s = tostring(state or "normal")
            frame._disabled = (s == "disabled")
            frame._focused = (s == "focus")
            frame._open = (s == "open")
            frame._pressed = (s == "pressed")
            frame._hovered = (s == "hover")
            if frame._disabled then
                frame._focused = false
                frame._open = false
                frame._pressed = false
                frame._hovered = false
            end
            if frame.UpdateVisual then
                frame:UpdateVisual()
            end
        end

        local function styleRowPill(frame, palette, pillKind)
            frame:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
                edgeSize = 8,
                insets = { left = 1, right = 1, top = 1, bottom = 1 },
            })
            frame._palette = palette or {}
            frame._pillKind = pillKind or "readonly"
            frame._hovered = false
            frame._pressed = false
            frame._focused = false
            frame._open = false
            frame._disabled = false

            if not frame.glow then
                frame.glow = frame:CreateTexture(nil, "BORDER")
                frame.glow:SetAllPoints()
                frame.glow:SetTexture("Interface\\Buttons\\WHITE8x8")
                frame.glow:SetBlendMode("ADD")
            end

            function frame:SetPillState(state)
                SetPillState(self, state)
            end

            function frame:UpdateVisual()
                local p = self._palette or {}
                local state = "base"
                if self._disabled then
                    state = "disabled"
                elseif self._focused then
                    state = "focus"
                elseif self._open then
                    state = "open"
                elseif self._pressed then
                    state = "pressed"
                elseif self._hovered then
                    state = "hover"
                end
                local c = p[state] or p.base or { 0.08, 0.09, 0.12, 0.95, 0.24, 0.27, 0.32, 1, 0 }
                self:SetBackdropColor(c[1], c[2], c[3], c[4])
                self:SetBackdropBorderColor(c[5], c[6], c[7], c[8])
                if self.glow then
                    self.glow:SetVertexColor(1, 0.82, 0.1, c[9] or 0)
                end
                if self.label then
                    local tc = p.text or { 1, 1, 1, 1 }
                    local td = p.textDisabled or { 0.62, 0.62, 0.64, 1 }
                    if self._disabled then
                        self.label:SetTextColor(td[1], td[2], td[3], td[4])
                    else
                        self.label:SetTextColor(tc[1], tc[2], tc[3], tc[4])
                    end
                end
                if self.chevron then
                    local cc = p.chevron or { 0.78, 0.78, 0.82, 1 }
                    local cd = p.chevronDisabled or { 0.45, 0.45, 0.48, 1 }
                    if self._disabled then
                        self.chevron:SetTextColor(cd[1], cd[2], cd[3], cd[4])
                    else
                        self.chevron:SetTextColor(cc[1], cc[2], cc[3], cc[4])
                    end
                end
                if self.editGlyph then
                    self.editGlyph:SetShown((not self._disabled) and self._hovered and (not self._focused))
                end
            end

            frame:SetScript("OnEnter", function(selfFrame)
                if selfFrame._disabled then
                    selfFrame._hovered = false
                    selfFrame:UpdateVisual()
                    return
                end
                selfFrame._hovered = true
                selfFrame:UpdateVisual()
            end)
            frame:SetScript("OnLeave", function(selfFrame)
                selfFrame._hovered = false
                selfFrame._pressed = false
                selfFrame:UpdateVisual()
            end)
            frame:SetScript("OnMouseDown", function(selfFrame)
                if selfFrame._disabled then
                    return
                end
                selfFrame._pressed = true
                selfFrame:UpdateVisual()
            end)
            frame:SetScript("OnMouseUp", function(selfFrame)
                selfFrame._pressed = false
                selfFrame:UpdateVisual()
            end)
            frame:UpdateVisual()
        end

        local function ApplyPillStyle_Editable(frame)
            styleRowPill(frame, {
                base = { CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A, 0.00 },
                hover = { CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A, CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A, 0.03 },
                pressed = { CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A, CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A, 0.02 },
                focus = { CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A, 1.00, 0.82, 0.10, 0.95, 0.08 },
                disabled = { 0.05, 0.06, 0.08, 0.86, 0.16, 0.18, 0.22, 0.85, 0.00 },
                text = { 0.90, 0.90, 0.92, 1 },
                textDisabled = { 0.58, 0.58, 0.61, 1 },
            }, "editable")
            if not frame.editGlyph then
                frame.editGlyph = createStyledFontString(frame, "ARTWORK", "GameFontHighlightSmall", 10)
                frame.editGlyph:SetPoint("RIGHT", frame, "RIGHT", -6, 0)
                frame.editGlyph:SetText("...")
                frame.editGlyph:SetTextColor(0.72, 0.72, 0.76, 0.9)
                frame.editGlyph:Hide()
            end
        end

        local function ApplyPillStyle_Dropdown(frame)
            styleRowPill(frame, {
                base = { CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A, 0.00 },
                hover = { CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A, CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A, 0.04 },
                pressed = { CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A, CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A, 0.03 },
                open = { CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A, 1.00, 0.82, 0.10, 0.82, 0.07 },
                focus = { CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A, 0.00 },
                disabled = { 0.05, 0.06, 0.08, 0.86, 0.16, 0.18, 0.22, 0.85, 0.00 },
                text = { 0.95, 0.95, 0.97, 1 },
                textDisabled = { 0.56, 0.56, 0.60, 1 },
                chevron = { 0.78, 0.78, 0.82, 1 },
                chevronDisabled = { 0.45, 0.45, 0.48, 1 },
            }, "dropdown")
        end

        local function ApplyPillStyle_Readonly(frame)
            styleRowPill(frame, {
                base = { 0.05, 0.06, 0.08, 0.90, 0.17, 0.19, 0.24, 0.9, 0.00 },
                hover = { 0.05, 0.06, 0.08, 0.90, 0.17, 0.19, 0.24, 0.9, 0.00 },
                pressed = { 0.05, 0.06, 0.08, 0.90, 0.17, 0.19, 0.24, 0.9, 0.00 },
                focus = { 0.05, 0.06, 0.08, 0.90, 0.17, 0.19, 0.24, 0.9, 0.00 },
                disabled = { 0.04, 0.05, 0.07, 0.82, 0.14, 0.16, 0.21, 0.82, 0.00 },
                text = { 0.78, 0.78, 0.82, 1 },
                textDisabled = { 0.52, 0.52, 0.55, 1 },
            }, "readonly")
        end

        local function registerDockSlotRowSearch(row)
            if type(row) ~= "table" or not frameIsAlive(row.enabled) then
                return nil
            end

            local primaryRef = row.destination and row.destination.label or nil
            if not frameIsAlive(primaryRef) then
                primaryRef = row.namePill and row.namePill.label or nil
            end
            if not frameIsAlive(primaryRef) then
                return nil
            end

            local extraRefs = {}
            local candidateRefs = {
                row.namePill and row.namePill.label or nil,
                row.spellIDPill and row.spellIDPill.label or nil,
                row.destination and row.destination.label or nil,
            }
            for i = 1, #candidateRefs do
                local ref = candidateRefs[i]
                if frameIsAlive(ref) and ref ~= primaryRef then
                    extraRefs[#extraRefs + 1] = ref
                end
            end

            return settingsSearchRuntime.registerControlText(primaryRef, row.enabled, "toggle", extraRefs)
        end

        local function createRowEnableToggle(parent, slotIndex)
            local holder = CreateFrame("Frame", nil, parent)
            holder:SetSize(FIXED_FOOTPRINTS.ROW_ENABLE_HOLDER_W, FIXED_FOOTPRINTS.ROW_ENABLE_HOLDER_H)
            holder._checked = false

            local PRESS_TEXT_OFFSET_X = 0.30
            local PRESS_TEXT_OFFSET_Y = -0.30

            local function isDockRowHost(selfBtn)
                return isUsingCustomSettingsWindowVisualStyle(selfBtn)
            end

            local function setDockRowNativeOffset(selfBtn, offsetX, offsetY)
                if not selfBtn or not selfBtn.SetPushedTextOffset then
                    return
                end
                local scale = selfBtn.GetEffectiveScale and selfBtn:GetEffectiveScale() or 1
                if scale == 0 then
                    scale = 1
                end
                local ox = tonumber(offsetX) or 0
                local oy = tonumber(offsetY) or 0
                if math.abs(ox) < 0.5 and ox ~= 0 then
                    ox = (ox < 0) and -0.5 or 0.5
                end
                if math.abs(oy) < 0.5 and oy ~= 0 then
                    oy = (oy < 0) and -0.5 or 0.5
                end
                ox = ox / scale
                oy = oy / scale
                selfBtn:SetPushedTextOffset(ox, oy)
            end

            local function clearDockRowNativeOffset(selfBtn)
                if isDockRowHost(selfBtn) then
                    setDockRowNativeOffset(selfBtn, 0, 0)
                end
            end

            local function createToggleButton(text)
                local btn = createActionButton(holder, text, nil, FIXED_FOOTPRINTS.ROW_ENABLE_BUTTON_W, {
                    textOrigin = "choice_caption",
                    searchChoiceLabelMode = "suppress_generic",
                })
                if btn.Text then
                    applyGlobalFontToObject(btn.Text, 10)
                end
                btn._hovered = false
                btn._selected = false
                btn._kind = "off"

                local function ensureFlatSkin(selfBtn)
                    if not selfBtn then
                        return
                    end
                    if not selfBtn._paSkinReady then
                        selfBtn._paSkinReady = true
                        selfBtn._paBg = selfBtn:CreateTexture(nil, "ARTWORK")
                        selfBtn._paBg:SetAllPoints(selfBtn)
                        selfBtn._paBg:SetTexture("Interface\\Buttons\\WHITE8x8")
                        selfBtn._paBorder = CreateFrame("Frame", nil, selfBtn, "BackdropTemplate")
                        selfBtn._paBorder:SetPoint("TOPLEFT", selfBtn, "TOPLEFT", -1, 1)
                        selfBtn._paBorder:SetPoint("BOTTOMRIGHT", selfBtn, "BOTTOMRIGHT", 1, -1)
                        selfBtn._paBorder:SetBackdrop({
                            edgeFile = "Interface\\Buttons\\WHITE8x8",
                            edgeSize = 1,
                        })
                        selfBtn._paBorder:SetBackdropBorderColor(CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A)
                        setSegmentBorderColor(selfBtn, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A)
                        selfBtn._paTopSheen = selfBtn:CreateTexture(nil, "OVERLAY")
                        selfBtn._paTopSheen:SetAllPoints(selfBtn)
                        selfBtn._paTopSheen:SetTexture("Interface\\Buttons\\WHITE8x8")
                        if selfBtn._paTopSheen.SetGradientAlpha then
                            selfBtn._paTopSheen:SetGradientAlpha("VERTICAL", 1, 1, 1, 0.12, 1, 1, 1, 0.0)
                        elseif selfBtn._paTopSheen.SetGradient and CreateColor then
                            selfBtn._paTopSheen:SetGradient("VERTICAL", CreateColor(1, 1, 1, 0.12), CreateColor(1, 1, 1, 0.0))
                        else
                            selfBtn._paTopSheen:SetVertexColor(1, 1, 1, 0.1)
                        end
                        selfBtn._paGlow = selfBtn:CreateTexture(nil, "BORDER")
                        selfBtn._paGlow:SetAllPoints(selfBtn)
                        selfBtn._paGlow:SetTexture("Interface\\Buttons\\WHITE8x8")
                        selfBtn._paGlow:SetBlendMode("ADD")
                    end

                    local n = selfBtn.GetNormalTexture and selfBtn:GetNormalTexture() or nil
                    local p = selfBtn.GetPushedTexture and selfBtn:GetPushedTexture() or nil
                    local h = selfBtn.GetHighlightTexture and selfBtn:GetHighlightTexture() or nil
                    local d = selfBtn.GetDisabledTexture and selfBtn:GetDisabledTexture() or nil
                    if n then n:SetAlpha(0); if n.Hide then n:Hide() end end
                    if p then p:SetAlpha(0); if p.Hide then p:Hide() end end
                    if h then h:SetAlpha(0); if h.Hide then h:Hide() end end
                    if d then d:SetAlpha(0); if d.Hide then d:Hide() end end

                    local skinParts = {
                        "Left", "Middle", "Right",
                        "LeftDisabled", "MiddleDisabled", "RightDisabled",
                        "LeftHighlight", "MiddleHighlight", "RightHighlight",
                        "LeftPressed", "MiddlePressed", "RightPressed",
                    }
                    for _, part in ipairs(skinParts) do
                        local tex = selfBtn[part]
                        if tex and tex.SetAlpha then
                            tex:SetAlpha(0)
                        end
                        if tex and tex.Hide then
                            tex:Hide()
                        end
                    end

                    if selfBtn._paBorder then
                        local baseLevel = selfBtn:GetFrameLevel() or 0
                        selfBtn._paBorder:SetFrameStrata(selfBtn:GetFrameStrata())
                        selfBtn._paBorder:SetFrameLevel(baseLevel + 3)
                    end
                end

                function btn:ApplyVisual()
                    ensureFlatSkin(self)
                    local useHostToggleTheme = isUsingCustomSettingsWindowVisualStyle(self)
                    local enabled = self._disabled ~= true
                    if useHostToggleTheme then
                        local bgColor = self._hovered and SETTINGS_WINDOW_HOST_COLORS.hoverBg or SETTINGS_WINDOW_HOST_COLORS.idleBg
                        local borderColor = self._hovered and SETTINGS_WINDOW_HOST_COLORS.hoverBorder or SETTINGS_WINDOW_HOST_COLORS.idleBorder
                        local textColor = self._hovered and SETTINGS_WINDOW_HOST_COLORS.hoverText or SETTINGS_WINDOW_HOST_COLORS.idleText

                        if not enabled then
                            bgColor = SETTINGS_WINDOW_HOST_COLORS.disabledBg
                            borderColor = SETTINGS_WINDOW_HOST_COLORS.disabledBorder
                            textColor = SETTINGS_WINDOW_HOST_COLORS.disabledText
                            if self._paGlow then
                                self._paGlow:SetVertexColor(1, 1, 1, 0)
                            end
                            if self._paTopSheen then
                                self._paTopSheen:SetAlpha(0.05)
                            end
                            self:SetAlpha(0.58)
                        elseif self._selected then
                            if self._kind == "on" then
                                bgColor = SETTINGS_WINDOW_HOST_COLORS.onBg
                                borderColor = SETTINGS_WINDOW_HOST_COLORS.onBorder
                                textColor = SETTINGS_WINDOW_HOST_COLORS.onText
                                if self._paGlow then
                                    self._paGlow:SetVertexColor(unpackColor(SETTINGS_WINDOW_HOST_COLORS.onBorder))
                                    self._paGlow:SetAlpha(self._hovered and 0.16 or 0.10)
                                end
                            else
                                bgColor = SETTINGS_WINDOW_HOST_COLORS.offBg
                                borderColor = SETTINGS_WINDOW_HOST_COLORS.offBorder
                                textColor = SETTINGS_WINDOW_HOST_COLORS.offText
                                if self._paGlow then
                                    self._paGlow:SetVertexColor(unpackColor(SETTINGS_WINDOW_HOST_COLORS.offBorder))
                                    self._paGlow:SetAlpha(self._hovered and 0.12 or 0.08)
                                end
                            end
                            if self._paTopSheen then
                                self._paTopSheen:SetAlpha(self._hovered and 0.18 or 0.12)
                            end
                            self:SetAlpha(1)
                        else
                            if self._paGlow then
                                self._paGlow:SetVertexColor(1, 1, 1, 0)
                            end
                            if self._paTopSheen then
                                self._paTopSheen:SetAlpha(self._hovered and 0.12 or 0.08)
                            end
                            self:SetAlpha(0.98)
                        end

                        self._paBg:SetVertexColor(unpackColor(bgColor))
                        if self._paBorder then
                            setSegmentBorderColor(self, unpackColor(borderColor))
                        end
                        if self.Text then
                            self.Text:SetTextColor(unpackColor(textColor))
                        end
                        return
                    end

                    if not enabled then
                        self._paBg:SetVertexColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
                        if self._paGlow then
                            self._paGlow:SetVertexColor(1, 1, 1, 0)
                        end
                        if self._paBorder then
                            setSegmentBorderColor(self, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, 0.72)
                        end
                        if self._paTopSheen then
                            self._paTopSheen:SetAlpha(0.04)
                        end
                        if self.Text then
                            self.Text:SetTextColor(0.50, 0.50, 0.53, 1)
                        end
                        self:SetAlpha(0.45)
                        return
                    end

                    if self._selected then
                        if self._kind == "on" then
                            if self._hovered then
                                self._paBg:SetVertexColor(0.13, 0.28, 0.15, 0.98)
                            else
                                self._paBg:SetVertexColor(0.11, 0.23, 0.13, 0.96)
                            end
                            if self._paGlow then
                                self._paGlow:SetVertexColor(0.28, 1.0, 0.36, self._hovered and 0.14 or 0.1)
                            end
                            if self._paBorder then
                                setSegmentBorderColor(self, 0.18, 0.55, 0.2, self._hovered and 0.95 or 0.82)
                            end
                            if self.Text then
                                self.Text:SetTextColor(0.72, 1, 0.74, 1)
                            end
                        else
                            self._paBg:SetVertexColor(OFF_RED_BG_R, OFF_RED_BG_G, OFF_RED_BG_B, OFF_RED_BG_A)
                            if self._paGlow then
                                self._paGlow:SetVertexColor(0.95, 0.22, 0.22, 0)
                            end
                            if self._paBorder then
                                setSegmentBorderColor(
                                    self,
                                    OFF_RED_BORDER_SELECTED_R,
                                    OFF_RED_BORDER_SELECTED_G,
                                    OFF_RED_BORDER_SELECTED_B,
                                    OFF_RED_BORDER_SELECTED_A
                                )
                            end
                            if self.Text then
                                self.Text:SetTextColor(OFF_RED_TEXT_R, OFF_RED_TEXT_G, OFF_RED_TEXT_B, OFF_RED_TEXT_A)
                            end
                        end
                        if self._paTopSheen then
                            if self._kind == "on" then
                                self._paTopSheen:SetAlpha(0.22)
                            else
                                self._paTopSheen:SetAlpha(OFF_RED_TOPSHEEN_ALPHA)
                            end
                        end
                        if self._kind == "on" then
                            self:SetAlpha(0.98)
                        else
                            self:SetAlpha(OFF_RED_SELECTED_ALPHA)
                        end
                    else
                        if self._hovered then
                            self._paBg:SetVertexColor(CONTROL_HOVER_BG_R, CONTROL_HOVER_BG_G, CONTROL_HOVER_BG_B, CONTROL_HOVER_BG_A)
                            if self._paBorder then
                                setSegmentBorderColor(self, CONTROL_HOVER_BORDER_R, CONTROL_HOVER_BORDER_G, CONTROL_HOVER_BORDER_B, CONTROL_HOVER_BORDER_A)
                            end
                        else
                            self._paBg:SetVertexColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
                            if self._paBorder then
                                setSegmentBorderColor(self, CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A)
                            end
                        end
                        if self._paGlow then
                            self._paGlow:SetVertexColor(1, 1, 1, 0)
                        end
                        if self._paTopSheen then
                            self._paTopSheen:SetAlpha(self._hovered and 0.12 or 0.08)
                        end
                        if self.Text then
                            self.Text:SetTextColor(0.85, 0.85, 0.88, 1)
                        end
                        self:SetAlpha(0.96)
                    end
                end

                btn:SetScript("OnEnter", function(selfBtn)
                    selfBtn._hovered = true
                    selfBtn:ApplyVisual()
                end)
                btn:SetScript("OnLeave", function(selfBtn)
                    selfBtn._hovered = false
                    clearDockRowNativeOffset(selfBtn)
                    selfBtn:ApplyVisual()
                end)
                btn:HookScript("OnShow", function(selfBtn)
                    clearDockRowNativeOffset(selfBtn)
                end)
                btn:SetScript("OnMouseDown", function(selfBtn)
                    if selfBtn._disabled then
                        return
                    end
                    if not isDockRowHost(selfBtn) then
                        return
                    end
                    setDockRowNativeOffset(selfBtn, PRESS_TEXT_OFFSET_X, PRESS_TEXT_OFFSET_Y)
                end)
                btn:SetScript("OnMouseUp", function(selfBtn)
                    clearDockRowNativeOffset(selfBtn)
                end)
                function btn:SetEnabled(enabled)
                    local allow = enabled and true or false
                    self._disabled = not allow
                    self._hovered = false
                    self._pressed = false
                    clearDockRowNativeOffset(self)
                    self:EnableMouse(allow)
                    self:ApplyVisual()
                end
                btn:ApplyVisual()
                if isDockRowHost(btn) then
                    setDockRowNativeOffset(btn, 0, 0)
                end
                return btn
            end

            holder.disabledBtn = createToggleButton("Disabled")
            holder.disabledBtn._kind = "off"
            holder.enabledBtn = createToggleButton("Enabled")
            holder.enabledBtn._kind = "on"

            holder.disabledBtn:SetPoint("TOPLEFT", holder, "TOPLEFT", 0, 0)
            holder.enabledBtn:SetPoint("TOPRIGHT", holder, "TOPRIGHT", 0, 0)
            holder.disabledBtn:SetSize(FIXED_FOOTPRINTS.ROW_ENABLE_BUTTON_W, FIXED_FOOTPRINTS.ROW_ENABLE_BUTTON_H)
            holder.enabledBtn:SetSize(FIXED_FOOTPRINTS.ROW_ENABLE_BUTTON_W, FIXED_FOOTPRINTS.ROW_ENABLE_BUTTON_H)

            function holder:SetChecked(v)
                self._checked = PA_SafeBool(v)
                self.disabledBtn._selected = not self._checked
                self.enabledBtn._selected = self._checked
                self.disabledBtn:ApplyVisual()
                self.enabledBtn:ApplyVisual()
            end

            function holder:GetChecked()
                return self._checked
            end

            function holder:SetEnabled(enabled)
                local allow = enabled and true or false
                self._enabled = allow
                if self.disabledBtn and self.disabledBtn.SetEnabled then
                    self.disabledBtn:SetEnabled(allow)
                end
                if self.enabledBtn and self.enabledBtn.SetEnabled then
                    self.enabledBtn:SetEnabled(allow)
                end
                self:SetAlpha(allow and 1 or 0.55)
            end

            holder.disabledBtn:SetScript("OnClick", function()
                local slot = getDockSlot(slotIndex)
                if not slot.enabled then
                    return
                end
                slot.enabled = false
                setLoadoutPresetCustom()
                onUIChanged(false)
            end)
            holder.enabledBtn:SetScript("OnClick", function()
                local slot = getDockSlot(slotIndex)
                if slot.enabled then
                    return
                end
                slot.enabled = true
                setLoadoutPresetCustom()
                onUIChanged(false)
            end)

            holder:SetChecked(false)
            holder:SetEnabled(true)
            registerSettingsWindowVisualRefresh(holder, function(selfHolder)
                if selfHolder.disabledBtn and selfHolder.disabledBtn.ApplyVisual then
                    selfHolder.disabledBtn:ApplyVisual()
                end
                if selfHolder.enabledBtn and selfHolder.enabledBtn.ApplyVisual then
                    selfHolder.enabledBtn:ApplyVisual()
                end
            end)
            return holder
        end

        for i = 1, 10 do
            local slotIndex = i
            local row = { index = slotIndex }
            row.enabled = createRowEnableToggle(scrollChild, slotIndex)
            row.status = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
            row.status:SetJustifyH("LEFT")
            row.status:SetText("")
            row.status:Hide()
            row.namePill = CreateFrame("Button", nil, scrollChild, "BackdropTemplate")
            ApplyPillStyle_Editable(row.namePill)
            row.namePill.label = createStyledFontString(row.namePill, "ARTWORK", "GameFontHighlightSmall", 11)
            row.namePill.label:SetPoint("LEFT", row.namePill, "LEFT", 8, 0)
            row.namePill.label:SetPoint("RIGHT", row.namePill, "RIGHT", -20, 0)
            row.namePill.label:SetJustifyH("LEFT")
            row.namePill.label:SetWordWrap(false)
            local function openNameEditor()
                if widgets.renamePopover and widgets.renamePopover.OpenForRow then
                    widgets.renamePopover:OpenForRow(slotIndex, row)
                end
            end
            row.namePill:SetScript("OnClick", openNameEditor)
            row.nameIBeam = CreateFrame("EditBox", nil, row.namePill)
            row.nameIBeam:SetAllPoints(row.namePill)
            row.nameIBeam:SetAutoFocus(false)
            row.nameIBeam:EnableMouse(true)
            if row.nameIBeam.SetMouseClickEnabled then
                row.nameIBeam:SetMouseClickEnabled(true)
            end
            if row.nameIBeam.SetMouseMotionEnabled then
                row.nameIBeam:SetMouseMotionEnabled(true)
            end
            if row.nameIBeam.EnableKeyboard then
                row.nameIBeam:EnableKeyboard(false)
            end
            row.nameIBeam:SetFrameLevel((row.namePill:GetFrameLevel() or 1) + 5)
            row.nameIBeam:SetText(" ")
            row.nameIBeam:SetTextInsets(0, 0, 0, 0)
            row.nameIBeam:SetAlpha(0)
            row.nameIBeam:SetScript("OnEditFocusGained", nil)
            row.nameIBeam:SetScript("OnEnterPressed", nil)
            row.nameIBeam:SetScript("OnEscapePressed", nil)
            row.nameIBeam:SetScript("OnMouseUp", function()
                openNameEditor()
            end)
            row.nameIBeam:SetScript("OnEnter", function()
                if row.namePill and row.namePill.SetPillState and not row.namePill._disabled then
                    row.namePill:SetPillState(row.namePill._focused and "focus" or "hover")
                end
            end)
            row.nameIBeam:SetScript("OnLeave", function()
                if row.namePill and row.namePill.SetPillState then
                    row.namePill:SetPillState(row.namePill._focused and "focus" or "normal")
                end
            end)
            row.spellIDPill = CreateFrame("Button", nil, scrollChild, "BackdropTemplate")
            row.spellIDPill:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
                edgeSize = 8,
                insets = { left = 1, right = 1, top = 1, bottom = 1 },
            })
            row.spellIDPill:SetBackdropColor(CONTROL_BASE_BG_R, CONTROL_BASE_BG_G, CONTROL_BASE_BG_B, CONTROL_BASE_BG_A)
            row.spellIDPill:SetBackdropBorderColor(CONTROL_BASE_BORDER_R, CONTROL_BASE_BORDER_G, CONTROL_BASE_BORDER_B, CONTROL_BASE_BORDER_A)
            row.spellIDPill.hover = row.spellIDPill:CreateTexture(nil, "HIGHLIGHT")
            row.spellIDPill.hover:SetAllPoints()
            row.spellIDPill.hover:SetTexture("Interface\\Buttons\\WHITE8x8")
            row.spellIDPill.hover:SetVertexColor(1, 1, 1, 0.06)
            row.spellIDPill.label = createStyledFontString(row.spellIDPill, "ARTWORK", "GameFontHighlightSmall", 11)
            row.spellIDPill.label:SetPoint("LEFT", row.spellIDPill, "LEFT", 8, 0)
            row.spellIDPill.label:SetPoint("RIGHT", row.spellIDPill, "RIGHT", -8, 0)
            row.spellIDPill.label:SetJustifyH("LEFT")
            row.spellIDPill.label:SetWordWrap(false)
            row.spellIDPill:SetScript("OnClick", function()
                if widgets.spellIDPopover and widgets.spellIDPopover.OpenForRow then
                    widgets.spellIDPopover:OpenForRow(slotIndex, row)
                end
            end)
            row.destination = CreateFrame("Button", nil, scrollChild, "BackdropTemplate")
            row.destination:SetHeight(FIXED_FOOTPRINTS.STANDARD_CONTROL_H)
            ApplyPillStyle_Dropdown(row.destination)
            row.destination.label = createStyledFontString(row.destination, "ARTWORK", "GameFontHighlightSmall", 11)
            row.destination.label:SetPoint("LEFT", row.destination, "LEFT", 8, 0)
            row.destination.label:SetPoint("RIGHT", row.destination, "RIGHT", -18, 0)
            row.destination.label:SetJustifyH("LEFT")
            row.destination.label:SetWordWrap(false)
            row.destination.chevron = createStyledFontString(row.destination, "ARTWORK", "GameFontHighlightSmall", 10)
            row.destination.chevron:SetPoint("RIGHT", row.destination, "RIGHT", -7, 0)
            row.destination.chevron:SetText("v")
            row.destination:SetScript("OnMouseDown", function(selfButton)
                selfButton._pressed = true
                selfButton:UpdateVisual()
            end)
            row.destination:SetScript("OnMouseUp", function(selfButton)
                selfButton._pressed = false
                selfButton:UpdateVisual()
            end)
            row.destination:UpdateVisual()
            row.destination:SetScript("OnClick", function(selfButton)
                if not selfButton:IsEnabled() then
                    return
                end
                if widgets.destinationPicker and widgets.destinationPicker.IsShown and widgets.destinationPicker:IsShown() and widgets.destinationPicker._ownerButton == selfButton then
                    widgets.destinationPicker:Close()
                    return
                end
                local slot = getDockSlot(slotIndex)
                local destinationChoices = getDestinationChoices()
                if widgets.destinationPicker._sourceOptionsRef ~= destinationChoices then
                    widgets.destinationPicker:SetOptions(destinationChoices)
                    widgets.destinationPicker._sourceOptionsRef = destinationChoices
                end
                widgets.destinationPicker:SetSelectedValue(slot.selection)
                widgets.destinationPicker:SetOnSelect(function(value, option, isClear)
                    if isClear then
                        slot.selection = "CUSTOM"
                        slot.spellID = 0
                        setDockSlotDefaultName(slot, 0)
                    elseif value == "CUSTOM" then
                        slot.selection = "CUSTOM"
                        setDockSlotDefaultName(slot, slot.spellID)
                    else
                        local spellID = math.floor(tonumber(value) or 0)
                        if spellID > 0 then
                            slot.selection = tostring(spellID)
                            slot.spellID = spellID
                            setDockSlotDefaultName(slot, spellID)
                        else
                            slot.selection = "CUSTOM"
                            slot.spellID = 0
                            setDockSlotDefaultName(slot, 0)
                        end
                    end
                    setLoadoutPresetCustom()
                    onUIChanged(false)
                end)
                if widgets.destinationPicker then
                    widgets.destinationPicker._ownerButton = selfButton
                end
                if selfButton.SetPillState then
                    selfButton:SetPillState("open")
                else
                    selfButton._open = true
                    selfButton:UpdateVisual()
                end
                widgets.destinationPicker:Open(selfButton)
            end)

            row.result = CreateFrame("Button", nil, scrollChild, "BackdropTemplate")
            row.result:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
                edgeSize = 10,
                insets = { left = 2, right = 2, top = 2, bottom = 2 },
            })
            row.result:SetBackdropColor(0, 0, 0, 0.45)
            row.result:SetBackdropBorderColor(0.25, 0.25, 0.25, 1)
            row.result.icon = row.result:CreateTexture(nil, "ARTWORK")
            row.result.icon:SetAllPoints()
            row.result:SetScript("OnEnter", function()
                local slot = getDockSlot(slotIndex)
                if slot.spellID <= 0 then
                    return
                end
                GameTooltip:SetOwner(row.result, "ANCHOR_RIGHT")
                if GameTooltip.SetSpellByID then
                    GameTooltip:SetSpellByID(slot.spellID)
                else
                    GameTooltip:SetText(resolveSlotName(slot.spellID, "Unknown"))
                end
                GameTooltip:Show()
            end)
            row.result:SetScript("OnLeave", function()
                GameTooltip:Hide()
            end)
            registerDockSlotRowSearch(row)
            slotRows[slotIndex] = row
        end

        local function refreshSwatch()
            local c = PortalAuthorityDB.dockFontColor
            widgets.color.swatch:SetBackdropColor(c.r, c.g, c.b, c.a)
        end
        widgets.color.swatch:SetScript("OnClick", function()
            openColorPicker(function()
                refreshSwatch()
                ApplyDockAppearanceSettings()
            end)
        end)

        local function syncCheckboxes()
            if widgets.lockDock and widgets.lockDock.Refresh then widgets.lockDock:Refresh() end
            if refreshLockDockVisualText then refreshLockDockVisualText() end
            if widgets.loadoutPresetSegment and widgets.loadoutPresetSegment.Refresh then widgets.loadoutPresetSegment:Refresh() end
            if widgets.dockEnabled and widgets.dockEnabled.Refresh then widgets.dockEnabled:Refresh() end
            if widgets.hideNames and widgets.hideNames.Refresh then widgets.hideNames:Refresh() end
            if widgets.gizmoMode and widgets.gizmoMode.Refresh then widgets.gizmoMode:Refresh() end
            if applyDockGizmoVisibilityOverrideState then applyDockGizmoVisibilityOverrideState() end
        end

        local function setDockObjectVisible(obj, visible)
            if not obj then
                return
            end
            if visible then
                if obj.Show then
                    obj:Show()
                end
            else
                if obj.Hide then
                    obj:Hide()
                end
            end
        end

        local function placeControl(spec, xLabel, xControl, y, controlW, anchorFrame)
            local anchorParent = anchorFrame or scrollChild
            local placement = PAGE.CONTROL_PLACEMENT
            setDockObjectVisible(spec.label, true)
            setDockObjectVisible(spec.control, true)
            spec.label:ClearAllPoints()
            spec.label:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", xLabel, y)
            if spec.kind == "dropdown" then
                spec.control:ClearAllPoints()
                spec.control:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", xControl + placement.DROPDOWN_X_SHIFT, y + placement.DROPDOWN_Y_SHIFT)
                UIDropDownMenu_SetWidth(spec.control, controlW)
            elseif spec.kind == "font_picker" then
                spec.control:ClearAllPoints()
                spec.control:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", xControl, y + placement.COMPACT_CONTROL_Y_SHIFT)
                if spec.SetWidth then
                    spec:SetWidth(controlW)
                else
                    spec.control:SetWidth(controlW)
                end
            elseif spec.kind == "premium_slider" then
                spec.control:ClearAllPoints()
                spec.control:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", xControl, y + placement.COMPACT_CONTROL_Y_SHIFT)
                if spec.SetWidth then
                    spec:SetWidth(controlW)
                else
                    spec.control:SetWidth(controlW)
                end
            elseif spec.kind == "stepper" then
                spec.control:ClearAllPoints()
                spec.control:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", xControl, y + placement.COMPACT_CONTROL_Y_SHIFT)
                if spec.SetWidth then
                    spec:SetWidth(controlW)
                else
                    spec.control:SetWidth(controlW)
                end
            elseif spec.kind == "segmented" then
                spec.control:ClearAllPoints()
                spec.control:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", xControl, y + placement.COMPACT_CONTROL_Y_SHIFT)
                if spec.Layout then
                    spec:Layout(controlW)
                else
                    spec.control:SetWidth(controlW)
                    spec.control:SetHeight(FIXED_FOOTPRINTS.STANDARD_CONTROL_H)
                end
            elseif spec.kind == "slider" then
                spec.control:ClearAllPoints()
                spec.control:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", xControl, y + placement.SLIDER_Y_SHIFT)
                spec.control:SetWidth(controlW)
                if spec.valueText then
                    setDockObjectVisible(spec.valueText, true)
                    spec.valueText:ClearAllPoints()
                    spec.valueText:SetPoint("LEFT", spec.control, "RIGHT", placement.VALUE_TEXT_GAP, 0)
                end
            else
                spec.control:ClearAllPoints()
                spec.control:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", xControl, y)
                spec.control:SetSize(controlW, FIXED_FOOTPRINTS.STANDARD_CONTROL_H)
            end
        end
        local function setSlotRowEnabledVisuals(row, slotEnabled, moduleEnabled)
            local allowModuleInteraction = moduleEnabled and true or false
            local allowSlotInteraction = allowModuleInteraction and (slotEnabled and true or false)

            setSettingsControlEnabled(row.enabled, allowModuleInteraction)

            if not allowSlotInteraction
                and widgets.destinationPicker
                and widgets.destinationPicker.Close
                and widgets.destinationPicker.IsShown
                and widgets.destinationPicker:IsShown()
                and widgets.destinationPicker._ownerButton == row.destination then
                widgets.destinationPicker:Close()
            end

            row.destination:SetEnabled(allowSlotInteraction)
            row.destination:SetAlpha(allowSlotInteraction and 1 or 0.86)
            if not allowSlotInteraction then
                if row.destination.SetPillState then
                    row.destination:SetPillState("disabled")
                else
                    row.destination._disabled = true
                    row.destination._hovered = false
                    row.destination._pressed = false
                    if row.destination.UpdateVisual then
                        row.destination:UpdateVisual()
                    end
                end
            else
                if row.destination.SetPillState and row.destination._disabled then
                    row.destination:SetPillState(row.destination._open and "open" or "normal")
                elseif row.destination.UpdateVisual then
                    row.destination._disabled = false
                    row.destination:UpdateVisual()
                end
            end

            row.spellIDPill:SetEnabled(allowSlotInteraction)
            row.spellIDPill:SetAlpha(allowSlotInteraction and 1 or 0.75)
            row.spellIDPill.label:SetTextColor(1, 1, 1, allowSlotInteraction and 1 or 0.6)

            row.namePill:SetEnabled(allowSlotInteraction)
            row.namePill:SetAlpha(allowSlotInteraction and 1 or 0.86)
            if row.nameIBeam then
                row.nameIBeam:EnableMouse(allowSlotInteraction)
                if row.nameIBeam.SetEnabled then
                    row.nameIBeam:SetEnabled(allowSlotInteraction)
                end
                if row.nameIBeam.SetMouseClickEnabled then
                    row.nameIBeam:SetMouseClickEnabled(allowSlotInteraction)
                end
                if not allowSlotInteraction and row.nameIBeam.ClearFocus then
                    row.nameIBeam:ClearFocus()
                end
            end
            if not allowSlotInteraction then
                if row.namePill.SetPillState then
                    row.namePill:SetPillState("disabled")
                else
                    row.namePill._disabled = true
                    row.namePill._hovered = false
                    row.namePill._pressed = false
                    if row.namePill.UpdateVisual then
                        row.namePill:UpdateVisual()
                    end
                end
            else
                if row.namePill.SetPillState and row.namePill._disabled then
                    row.namePill:SetPillState(row.namePill._focused and "focus" or "normal")
                elseif row.namePill.UpdateVisual then
                    row.namePill._disabled = false
                    row.namePill:UpdateVisual()
                else
                    row.namePill.label:SetTextColor(1, 1, 1, 1)
                end
            end

            row.result:EnableMouse(allowSlotInteraction)
            row.result:SetAlpha(allowSlotInteraction and 1 or 0.6)
            row.result.icon:SetDesaturated(not allowSlotInteraction)

            row.status:SetAlpha(0)
        end

        local function refreshSlotRows()
            local moduleEnabled = isDockModuleEnabled()
            for i = 1, 10 do
                local row = slotRows[i]
                local slot = getDockSlot(i)

                row.enabled:SetChecked(slot.enabled)
                local selected = getDestinationOptionByValue(slot.selection)
                if slot.selection == "CUSTOM" then
                    if slot.spellID > 0 then
                        row.destination.label:SetText(string.format("Custom (%d)", getVisualDockIDForSpell(slot.spellID)))
                    else
                        row.destination.label:SetText("Custom")
                    end
                else
                    row.destination.label:SetText((selected and selected.buttonLabel) or ("Spell " .. tostring(slot.selection)))
                end

                local displayName = getDockSlotDisplayName(slot)
                row.namePill.label:SetText(displayName ~= "" and displayName or "-")
                row.spellIDPill.label:SetText(tostring(getVisualDockIDForSpell(slot.spellID or 0)))

                local texture = getSpellTextureByID(slot.spellID) or "Interface\\ICONS\\INV_Misc_QuestionMark"
                row.result.icon:SetTexture(texture)
                row.result.icon:SetTexCoord(0, 1, 0, 1)
                if slot.spellID > 0 and (texture == nil or texture == "Interface\\ICONS\\INV_Misc_QuestionMark") then
                    requestSpellDataRefresh(i, slot.spellID)
                end

                row.status:SetText("")

                setSlotRowEnabledVisuals(row, slot.enabled, moduleEnabled)
                if widgets.renamePopover and widgets.renamePopover:IsShown() and widgets.renamePopover.slotIndex == i and not slot.enabled then
                    widgets.renamePopover:Close(false)
                end
                if widgets.spellIDPopover and widgets.spellIDPopover:IsShown() and widgets.spellIDPopover.slotIndex == i and not slot.enabled then
                    widgets.spellIDPopover:Close(false)
                end
            end
        end

        applyDockModuleEnabledState = function()
            local moduleEnabled = isDockModuleEnabled()

            setSettingsControlEnabled(widgets.lockDock, moduleEnabled)
            setSettingsControlEnabled(widgets.resetDockAnchor, moduleEnabled)
            setSettingsControlEnabled(widgets.loadoutPresetSegment, moduleEnabled)
            setSettingsControlEnabled(widgets.hideNames, moduleEnabled)
            setSettingsControlEnabled(widgets.gizmoMode, moduleEnabled)
            setSettingsControlEnabled(widgets.layoutModeSegment, moduleEnabled)
            setSettingsControlEnabled(widgets.iconsPerRow, moduleEnabled)
            setSettingsControlEnabled(widgets.layoutIconSize, moduleEnabled)
            setSettingsControlEnabled(widgets.labelMode, moduleEnabled)
            setSettingsControlEnabled(widgets.labelSide, moduleEnabled)
            setSettingsControlEnabled(widgets.labelSideInside, moduleEnabled)
            setSettingsControlEnabled(widgets.font, moduleEnabled)
            setSettingsControlEnabled(widgets.fontSize, moduleEnabled)
            setSettingsControlEnabled(widgets.color and widgets.color.swatch or nil, moduleEnabled)
            setSettingsControlEnabled(widgets.outlineToggle, moduleEnabled)
            setSettingsControlEnabled(widgets.hoverGlowSegment, moduleEnabled)
            if applyDockGizmoVisibilityOverrideState then
                applyDockGizmoVisibilityOverrideState()
            end

            if widgets.lowerSectionsContainer and widgets.lowerSectionsContainer.SetAlpha then
                widgets.lowerSectionsContainer:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.loadoutPresetSegment and widgets.loadoutPresetSegment.label and widgets.loadoutPresetSegment.label.SetAlpha then
                widgets.loadoutPresetSegment.label:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.lockRowContainer and widgets.lockRowContainer.SetAlpha then
                widgets.lockRowContainer:SetAlpha(moduleEnabled and 1 or 0.55)
            end

            for _, textWidget in ipairs({
                widgets.lockStateHelper,
                widgets.dockCustomizationHelper,
                widgets.dockCustomizationMatchStatus,
                widgets.enableLabel,
                widgets.layoutSectionHeader,
                widgets.labelsSectionHeader,
                widgets.styleSectionHeader,
                widgets.layoutSpacingHint,
                widgets.iconsPerRowGridOnlyHint,
                widgets.slotColDestination,
                widgets.slotColName,
                widgets.slotColSpellID,
                widgets.slotColResult,
            }) do
                setSettingsTextEnabled(textWidget, moduleEnabled)
            end

            if widgets.color and widgets.color.inlineLabel then
                setSettingsTextEnabled(widgets.color.inlineLabel, moduleEnabled)
            end

            if not moduleEnabled then
                if widgets.destinationPicker and widgets.destinationPicker.Close then
                    widgets.destinationPicker:Close()
                end
                if widgets.renamePopover and widgets.renamePopover.Close then
                    widgets.renamePopover:Close(false)
                end
                if widgets.spellIDPopover and widgets.spellIDPopover.Close then
                    widgets.spellIDPopover:Close(false)
                end
            end
        end

        relayout = function()
            syncCheckboxes()
            forceDockFontUiState()
            forceDockFontSizeUiState()
            forceStyleToggleUiState()
            do
                local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                local resolvedLayoutMode = getDockSimpleLayoutModeForSettings(defaults)
                if widgets.layoutModeSegment and widgets.layoutModeSegment.SetVisualSelectedValue then
                    widgets.layoutModeSegment:SetVisualSelectedValue(resolvedLayoutMode)
                end
                forceDockLabelUiState()
            end
            refreshSwatch()
            refreshSlotRows()

            local viewportW = scrollFrame:GetWidth()
            local contentW = math.max(PAGE.MIN_CONTENT_W, viewportW - PAGE.SCROLL_WIDTH_FUDGE)
            local left, right = PAGE.LEFT, PAGE.RIGHT
            local narrow = contentW < PAGE.NARROW_BREAKPOINT
            local ROW_H, ROW_GAP = PAGE.ROW_H, PAGE.ROW_GAP
            local ROW_STEP = ROW_H + ROW_GAP

            local pairContent = contentW - left - right
            local colGap = narrow and 0 or PAGE.WIDE_COLUMN_GAP
            local colW = narrow and pairContent or math.floor((pairContent - colGap) / 2)
            local CHECK_X = PAGE.CHECK_LEFT - left
            local LOADOUT_ROW_SHIFT_Y = PRESET_AND_TABLE.LOADOUT_ROW_SHIFT_Y -- single knob: positive moves the Midnight Loadout row down
            local TABLE_BLOCK_SHIFT_Y = PRESET_AND_TABLE.TABLE_BLOCK_SHIFT_Y -- single knob: positive moves the entire destination table down (preset row is unaffected)
            local LOWER_SECTIONS_BLOCK_OFFSET_Y = LOWER_SECTIONS.BLOCK_OFFSET_Y -- single knob: positive moves divider above Layout + everything below up
            local DESTINATION_COLUMN_Y_SHIFT = PRESET_AND_TABLE.DESTINATION_COLUMN_Y_SHIFT -- single knob: positive moves the entire Destination column up
            local NAME_SPELL_COLUMNS_Y_SHIFT = PRESET_AND_TABLE.NAME_SPELL_COLUMNS_Y_SHIFT -- single knob: positive moves Name + Spell ID columns up together
            local RESULT_COLUMN_Y_SHIFT = PRESET_AND_TABLE.RESULT_COLUMN_Y_SHIFT -- single knob: positive moves the entire Result column up
            local STATUS_TEXT_Y_SHIFT = PRESET_AND_TABLE.STATUS_TEXT_Y_SHIFT -- single knob: positive moves ENABLED/DISABLED status text up
            local SLOT_ENABLE_CHECKBOX_Y_SHIFT = PRESET_AND_TABLE.SLOT_ENABLE_CHECKBOX_Y_SHIFT -- single knob: positive moves all slot-row enable checkboxes up
            local SLOT_HEADER_TEXT_X_SHIFT = PRESET_AND_TABLE.SLOT_HEADER_TEXT_X_SHIFT -- single knob: positive moves Destination/Name/Spell ID header text right
            local VISIBILITY_BLOCK_SHIFT_Y = LOWER_SECTIONS.VISIBILITY_BLOCK_SHIFT_Y -- single knob: positive moves Visibility Rules + everything below it down (divider stays fixed)
            local VISIBILITY_LABELS_SHIFT_Y = LOWER_SECTIONS.VISIBILITY_LABELS_SHIFT_Y -- single knob: positive moves only visibility labels down (toggles stay fixed)
            local LABEL_X = PAGE.LABEL_X
            local CONTROL_X = PAGE.CONTROL_X
            local presetDividerReferenceGap = PRESET_AND_TABLE.PRESET_DIVIDER_FALLBACK_GAP

            local dropdownW = math.max(PAGE.DROPDOWN_MIN_W, math.min(PAGE.DROPDOWN_MAX_W, colW - CONTROL_X - PAGE.CONTROL_WIDTH_RIGHT_PAD))
            local numericW = math.max(PAGE.NUMERIC_MIN_W, math.min(PAGE.NUMERIC_MAX_W, colW - CONTROL_X - PAGE.CONTROL_WIDTH_RIGHT_PAD))
            local sliderW = math.max(PAGE.SLIDER_MIN_W, math.min(PAGE.SLIDER_MAX_W, colW - CONTROL_X - PAGE.SLIDER_WIDTH_RIGHT_PAD))

            local function columnBase(col)
                if col == 2 then
                    return left + colW + colGap
                end
                return left
            end

            local function pair(leftSpec, rightSpec, rowY, leftWidth, rightWidth)
                local leftBase = columnBase(1)
                if narrow then
                    placeControl(leftSpec, leftBase + LABEL_X, leftBase + CONTROL_X, rowY, leftWidth or dropdownW)
                    rowY = rowY - PAGE.PAIR_ROW_STEP
                    placeControl(rightSpec, leftBase + LABEL_X, leftBase + CONTROL_X, rowY, rightWidth or dropdownW)
                    return rowY - PAGE.PAIR_ROW_STEP
                end
                local rightBase = columnBase(2)
                placeControl(leftSpec, leftBase + LABEL_X, leftBase + CONTROL_X, rowY, leftWidth or dropdownW)
                placeControl(rightSpec, rightBase + LABEL_X, rightBase + CONTROL_X, rowY, rightWidth or dropdownW)
                return rowY - PAGE.PAIR_ROW_STEP
            end

            scrollChild:SetWidth(contentW)
            widgets.playerHeader:ClearAllPoints()
            widgets.playerHeader:SetPoint("TOPRIGHT", self, "TOPRIGHT", -PAGE.PLAYER_HEADER_PAD, -PAGE.PLAYER_HEADER_PAD)

            local leftBase = columnBase(1)
            local tableLeft = leftBase + CHECK_X
            local dividerLeftX = tableLeft
            local loadoutPresetW = math.max(
                PRESET_AND_TABLE.LOADOUT_PRESET_MIN_W,
                math.min(PRESET_AND_TABLE.LOADOUT_PRESET_MAX_W, contentW - tableLeft - right - PRESET_AND_TABLE.LOADOUT_RIGHT_PAD)
            )

            widgets.positionLabel:ClearAllPoints()
            setDockObjectVisible(widgets.positionLabel, false)
            widgets.positionLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)

            local lockRowLeft = tableLeft
            local lockLabelToToggleGap = TOP_BLOCK.LABEL_TO_TOGGLE_GAP
            local lockToggleToResetGap = TOP_BLOCK.TOGGLE_TO_RESET_GAP
            local resetW, resetH = FIXED_FOOTPRINTS.RESET_ANCHOR_W, FIXED_FOOTPRINTS.RESET_ANCHOR_H
            local lockLabel = widgets.lockDock and widgets.lockDock.label or nil
            local lockLabelW = 0
            local lockLabelH = 0
            if lockLabel then
                lockLabelW = math.ceil(lockLabel:GetStringWidth() or 0)
                lockLabelH = math.ceil(lockLabel:GetStringHeight() or 0)
            end
            local masterLabel = widgets.dockEnabled and widgets.dockEnabled.label or nil
            local masterLabelH = 0
            if masterLabel then
                masterLabelH = math.ceil(masterLabel:GetStringHeight() or 0)
            end
            local referenceLabelH = lockLabelH
            if referenceLabelH <= 0 then
                referenceLabelH = masterLabelH
            end
            if referenceLabelH <= 0 and widgets.enableLabel and widgets.enableLabel.GetStringHeight then
                referenceLabelH = widgets.enableLabel:GetStringHeight() or 0
            end
            local U = math.max(1, referenceLabelH)
            local spacingAB = U * TOP_BLOCK.HELPER_GAP_RATIO -- A -> B and C -> D
            local spacingBC = U * TOP_BLOCK.DIVIDER_GAP_RATIO -- B -> C
            local spacingDHeader = U * TOP_BLOCK.PRESET_HEADER_GAP_RATIO -- D -> Destination header
            local useHostedChrome = isPanelUsingCustomSettingsWindowHost(self)
            local lockBtnTextW = 0
            if widgets.lockDock and type(widgets.lockDock.buttons) == "table" then
                for _, btn in ipairs(widgets.lockDock.buttons) do
                    if btn and btn.Text then
                        lockBtnTextW = math.max(lockBtnTextW, math.ceil(btn.Text:GetStringWidth() or 0))
                    end
                end
            end
            lockBtnTextW = math.max(lockBtnTextW, TOP_BLOCK.LOCK_BUTTON_MIN_TEXT_W)
            local lockPerBtnPad = TOP_BLOCK.LOCK_BUTTON_PAD_X
            local lockToggleWFromContent = ((lockBtnTextW + (lockPerBtnPad * 2)) * 2) + TOP_BLOCK.LOCK_SEGMENT_INNER_GAP
            local lockToggleWMax = math.max(
                TOP_BLOCK.LOCK_TOGGLE_MIN_W,
                (contentW - TOP_BLOCK.CONTENT_RIGHT) - (lockRowLeft + lockLabelW + lockLabelToToggleGap + lockToggleToResetGap + resetW)
            )
            local lockToggleW = math.max(TOP_BLOCK.LOCK_TOGGLE_MIN_W, math.min(lockToggleWFromContent, lockToggleWMax))
            local sharedToggleX = (lockLabelW > 0) and (lockLabelW + lockLabelToToggleGap) or 0
            if widgets.dockEnabled and widgets.dockEnabled.Layout then
                widgets.dockEnabled:Layout(math.max(lockToggleW, 150))
            end
            local masterToggleH = (widgets.dockEnabled and widgets.dockEnabled.control and math.floor(widgets.dockEnabled.control:GetHeight() or FIXED_FOOTPRINTS.STANDARD_CONTROL_H)) or FIXED_FOOTPRINTS.STANDARD_CONTROL_H
            local masterRowH = math.max(TOP_BLOCK.LOCK_ROW_FLOOR, masterToggleH, masterLabelH)
            local masterRowGap = 4
            if widgets.lockDock and widgets.lockDock.Layout then
                widgets.lockDock:Layout(lockToggleW)
            end
            local lockToggleH = (widgets.lockDock and widgets.lockDock.control and math.floor(widgets.lockDock.control:GetHeight() or FIXED_FOOTPRINTS.STANDARD_CONTROL_H)) or FIXED_FOOTPRINTS.STANDARD_CONTROL_H
            local lockRowH = math.max(TOP_BLOCK.LOCK_ROW_FLOOR, resetH, lockToggleH, lockLabelH)
            local lockRowW = math.max(1, contentW - TOP_BLOCK.CONTENT_RIGHT - lockRowLeft)
            local lockHelperLineH = math.max(1, (widgets.lockStateHelper and widgets.lockStateHelper.GetStringHeight and widgets.lockStateHelper:GetStringHeight()) or U)
            local topBlockHelperGap = U * TOP_BLOCK.HELPER_GAP_RATIO
            local topBlockDividerGap = U * TOP_BLOCK.DIVIDER_GAP_RATIO
            local topBlockDividerOffset = topBlockDividerGap * TOP_BLOCK.DIVIDER_OFFSET_RATIO
            -- Preserve the accepted handoff below the top block; only the top-block rhythm changes.
            local hostedTopNudge = useHostedChrome and SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE or 0
            local y = (-TOP_BLOCK.TOP_PAD - hostedTopNudge)
                - (useHostedChrome and 0 or TOP_BLOCK.PRESERVED_HEADER_ADVANCE)
                - (useHostedChrome and 0 or (masterRowH + masterRowGap))
                - lockRowH
                - spacingAB
                - lockHelperLineH
                - spacingBC
            local topBlockY = -TOP_BLOCK.TOP_PAD - hostedTopNudge

            if useHostedChrome then
                setDockObjectVisible(widgets.header, false)
                widgets.header:ClearAllPoints()
                widgets.header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                setDockObjectVisible(widgets.sectionDescriptor, false)
                widgets.sectionDescriptor:ClearAllPoints()
                widgets.sectionDescriptor:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                setDockObjectVisible(widgets.masterRowContainer, false)
                widgets.masterRowContainer:ClearAllPoints()
                widgets.masterRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                if masterLabel then
                    setDockObjectVisible(masterLabel, false)
                    masterLabel:ClearAllPoints()
                    masterLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                end
                if widgets.dockEnabled and widgets.dockEnabled.control then
                    setDockObjectVisible(widgets.dockEnabled.control, false)
                    widgets.dockEnabled.control:ClearAllPoints()
                    widgets.dockEnabled.control:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                end
            else
                setDockObjectVisible(widgets.header, true)
                setDockObjectVisible(widgets.sectionDescriptor, true)
                widgets.header:ClearAllPoints()
                widgets.header:SetWidth(math.max(1, contentW - TOP_BLOCK.HEADER_LEFT - TOP_BLOCK.CONTENT_RIGHT))
                widgets.header:SetWordWrap(false)
                if widgets.header.SetMaxLines then
                    widgets.header:SetMaxLines(1)
                end
                if widgets.header.SetJustifyH then
                    widgets.header:SetJustifyH("LEFT")
                end
                local headerH = math.max(
                    TOP_BLOCK.HEADER_FLOOR,
                    math.ceil(tonumber((widgets.header.GetStringHeight and widgets.header:GetStringHeight()) or 0) or 0)
                )
                widgets.header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", TOP_BLOCK.HEADER_LEFT, topBlockY)
                topBlockY = topBlockY - headerH - TOP_BLOCK.HEADER_BOTTOM_GAP
                local topBlockAfterHeaderY = topBlockY
                topBlockY = layoutSettingsSectionDescriptor(
                    widgets.sectionDescriptor,
                    scrollChild,
                    TOP_BLOCK.HEADER_LEFT,
                    topBlockY,
                    math.max(1, contentW - TOP_BLOCK.HEADER_LEFT - TOP_BLOCK.CONTENT_RIGHT)
                )
                y = y - (topBlockAfterHeaderY - topBlockY)

                setDockObjectVisible(widgets.masterRowContainer, true)
                widgets.masterRowContainer:ClearAllPoints()
                widgets.masterRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", lockRowLeft, topBlockY + TOP_BLOCK.LOCK_STACK_NUDGE_Y)
                widgets.masterRowContainer:SetSize(lockRowW, masterRowH)
                if masterLabel then
                    setDockObjectVisible(masterLabel, true)
                    masterLabel:ClearAllPoints()
                    masterLabel:SetPoint("LEFT", widgets.masterRowContainer, "LEFT", 0, 0)
                end
                if widgets.dockEnabled and widgets.dockEnabled.control then
                    setDockObjectVisible(widgets.dockEnabled.control, true)
                    widgets.dockEnabled.control:ClearAllPoints()
                    widgets.dockEnabled.control:SetPoint("LEFT", widgets.masterRowContainer, "LEFT", sharedToggleX, 0)
                end
                topBlockY = topBlockY - masterRowH - masterRowGap
            end

            widgets.lockRowContainer:ClearAllPoints()
            widgets.lockRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", lockRowLeft, topBlockY + TOP_BLOCK.LOCK_STACK_NUDGE_Y)
            widgets.lockRowContainer:SetSize(lockRowW, lockRowH)

            if lockLabel then
                lockLabel:ClearAllPoints()
                lockLabel:SetPoint("LEFT", widgets.lockRowContainer, "LEFT", 0, 0)
            end
            widgets.lockDock.control:ClearAllPoints()
            widgets.lockDock.control:SetPoint("LEFT", widgets.lockRowContainer, "LEFT", sharedToggleX, 0)
            widgets.resetDockAnchor:ClearAllPoints()
            widgets.resetDockAnchor:SetSize(resetW, resetH)
            widgets.resetDockAnchor:SetPoint("LEFT", widgets.lockDock.control, "RIGHT", lockToggleToResetGap, 0)

            topBlockY = topBlockY - lockRowH
            widgets.lockStateHelper:ClearAllPoints()
            if widgets.lockStateHelper.SetJustifyH then
                widgets.lockStateHelper:SetJustifyH("LEFT")
            end
            widgets.lockStateHelper:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", lockRowLeft, topBlockY - topBlockHelperGap + TOP_BLOCK.LOCK_STACK_NUDGE_Y)
            topBlockY = topBlockY - topBlockHelperGap - lockHelperLineH

            widgets.lockDockDivider:ClearAllPoints()
            local lockDockDividerY = topBlockY - topBlockDividerOffset + TOP_BLOCK.LOCK_STACK_NUDGE_Y
            widgets.lockDockDivider:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", dividerLeftX, lockDockDividerY)
            widgets.lockDockDivider:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", -TOP_BLOCK.CONTENT_RIGHT, lockDockDividerY)
            widgets.lockDockDivider:SetHeight(FIXED_FOOTPRINTS.DIVIDER_H)
            topBlockY = topBlockY - topBlockDividerGap

            widgets.dockCustomizationLabel:ClearAllPoints()
            setDockObjectVisible(widgets.dockCustomizationLabel, false)
            widgets.dockCustomizationLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
            widgets.loadoutPresetSegment.label:ClearAllPoints()
            setDockObjectVisible(widgets.loadoutPresetSegment.label, false)
            widgets.loadoutPresetSegment.label:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
            widgets.loadoutPresetSegment.control:ClearAllPoints()
            setDockObjectVisible(widgets.loadoutPresetSegment.control, true)
            local presetRowTopY = y - LOADOUT_ROW_SHIFT_Y
            widgets.loadoutPresetSegment.control:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", tableLeft, presetRowTopY)
            presetDividerReferenceGap = math.max(0, math.floor((lockDockDividerY - presetRowTopY) + 0.5))
            if presetDividerReferenceGap <= 0 then
                presetDividerReferenceGap = PRESET_AND_TABLE.PRESET_DIVIDER_FALLBACK_GAP
            end
            if widgets.loadoutPresetSegment.Layout then
                widgets.loadoutPresetSegment:Layout(loadoutPresetW)
            end
            local presetRowH = math.max(
                1,
                (widgets.loadoutPresetSegment and widgets.loadoutPresetSegment.control and widgets.loadoutPresetSegment.control:GetHeight())
                or FIXED_FOOTPRINTS.STANDARD_CONTROL_H
            )
            widgets.dockCustomizationHelper:ClearAllPoints()
            widgets.dockCustomizationHelper:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", tableLeft, y - presetRowH - spacingAB - LOADOUT_ROW_SHIFT_Y)
            local presetHelperH = math.max(1, (widgets.dockCustomizationHelper and widgets.dockCustomizationHelper.GetStringHeight and widgets.dockCustomizationHelper:GetStringHeight()) or U)

            local matchStatusText = ""
            local showMatchStatus = false
            local matchStatusVariant = nil
            local activePreset = normalizeLoadoutPresetValue(PortalAuthorityDB and PortalAuthorityDB.dockLoadoutPreset)
            if activePreset == "CUSTOM" then
                local matchesSeason01, canonicalOrder = getCustomSeason01MatchState()
                if matchesSeason01 then
                    showMatchStatus = true
                    if canonicalOrder then
                        matchStatusVariant = "season01_exact"
                        matchStatusText = "• Matches Midnight Season 01"
                    else
                        matchStatusVariant = "season01_custom_order"
                        matchStatusText = "• Matches Midnight Season 01 (custom order)"
                    end
                end
            end

            local tableWidth = contentW - tableLeft - right - PRESET_AND_TABLE.LOADOUT_RIGHT_PAD
            local matchStatusGap = PRESET_AND_TABLE.MATCH_STATUS_GAP
            local matchStatusLaneH = math.max(
                1,
                math.floor(
                    (widgets.dockCustomizationHelper and widgets.dockCustomizationHelper.GetStringHeight and widgets.dockCustomizationHelper:GetStringHeight())
                    or U
                )
            )
            if widgets.dockCustomizationMatchStatus then
                local statusLabel = widgets.dockCustomizationMatchStatus
                local originalText = tostring(statusLabel:GetText() or "")
                if statusLabel.SetWidth then
                    statusLabel:SetWidth(math.max(1, tableWidth))
                end
                for _, candidateText in ipairs({
                    "",
                    "• Matches Midnight Season 01",
                    "• Matches Midnight Season 01 (custom order)",
                }) do
                    statusLabel:SetText(candidateText)
                    matchStatusLaneH = math.max(
                        matchStatusLaneH,
                        math.ceil(tonumber((statusLabel.GetStringHeight and statusLabel:GetStringHeight()) or 0) or 0)
                    )
                end
                statusLabel:SetText(originalText)

                local function setMatchStatusTone(variantKey, pulse)
                    if variantKey == "season01_exact" or variantKey == "season01_custom_order" then
                        if pulse then
                            statusLabel:SetTextColor(1.00, 0.90, 0.62, 1.00)
                        else
                            statusLabel:SetTextColor(0.90, 0.78, 0.52, 0.98)
                        end
                    else
                        statusLabel:SetTextColor(0.66, 0.66, 0.66, 0.94)
                    end
                end

                statusLabel:ClearAllPoints()
                statusLabel:SetPoint(
                    "TOPLEFT",
                    scrollChild,
                    "TOPLEFT",
                    tableLeft,
                    y - presetRowH - spacingAB - presetHelperH - matchStatusGap - LOADOUT_ROW_SHIFT_Y
                )
                if statusLabel.SetWidth then
                    statusLabel:SetWidth(math.max(1, tableWidth))
                end
                if showMatchStatus then
                    local shouldPulse = (widgets._dockMatchStatusVisible ~= true) or (widgets._dockMatchStatusVariant ~= matchStatusVariant)
                    statusLabel:SetText(matchStatusText)
                    statusLabel:Show()
                    widgets._dockMatchStatusVisible = true
                    widgets._dockMatchStatusVariant = matchStatusVariant
                    if shouldPulse then
                        local pulseToken = (widgets._dockMatchStatusPulseToken or 0) + 1
                        widgets._dockMatchStatusPulseToken = pulseToken
                        setMatchStatusTone(matchStatusVariant, true)
                        if C_Timer and C_Timer.After then
                            local settleVariant = matchStatusVariant
                            C_Timer.After(0.22, function()
                                if not widgets or not widgets.dockCustomizationMatchStatus then
                                    return
                                end
                                if widgets._dockMatchStatusPulseToken ~= pulseToken then
                                    return
                                end
                                if not widgets.dockCustomizationMatchStatus:IsShown() then
                                    return
                                end
                                setMatchStatusTone(settleVariant, false)
                            end)
                        else
                            setMatchStatusTone(matchStatusVariant, false)
                        end
                    else
                        setMatchStatusTone(matchStatusVariant, false)
                    end
                else
                    statusLabel:SetText("")
                    statusLabel:Hide()
                    widgets._dockMatchStatusVisible = false
                    widgets._dockMatchStatusVariant = nil
                    widgets._dockMatchStatusPulseToken = (widgets._dockMatchStatusPulseToken or 0) + 1
                    setMatchStatusTone(nil, false)
                end
            end

            -- Reserve a fixed match-status lane so the table baseline never depends on label visibility.
            local matchStatusBlockH = matchStatusGap + matchStatusLaneH
            y = y - presetRowH - spacingAB - presetHelperH - matchStatusBlockH - spacingDHeader

            widgets.loadoutDivider:ClearAllPoints()
            setDockObjectVisible(widgets.loadoutDivider, false)
            widgets.loadoutDivider:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
            widgets.loadoutDivider:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
            widgets.loadoutDivider:SetHeight(FIXED_FOOTPRINTS.DIVIDER_H)

            y = y - TABLE_BLOCK_SHIFT_Y

            widgets.portalSlotsLabel:ClearAllPoints()
            setDockObjectVisible(widgets.portalSlotsLabel, false)
            widgets.portalSlotsLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)

            local slotSpellW = PRESET_AND_TABLE.SLOT_SPELL_W
            local slotResultW = PRESET_AND_TABLE.SLOT_RESULT_W
            local slotEnableW = FIXED_FOOTPRINTS.ROW_ENABLE_HOLDER_W
            local slotEnableGap = PRESET_AND_TABLE.SLOT_ENABLE_GAP
            local slotDestW = math.max(PRESET_AND_TABLE.SLOT_DEST_MIN_W, math.floor(tableWidth * PRESET_AND_TABLE.SLOT_DEST_RATIO))
            local slotNameW = math.max(
                PRESET_AND_TABLE.SLOT_NAME_MIN_W,
                tableWidth - slotEnableW - slotEnableGap - slotDestW - slotSpellW - slotResultW - (PRESET_AND_TABLE.TABLE_COLUMN_GAP * 2)
            )

            local colEnableX = tableLeft
            local colDestX = colEnableX + slotEnableW + slotEnableGap
            local colNameX = colDestX + slotDestW + PRESET_AND_TABLE.TABLE_COLUMN_GAP
            local colSpellX = colNameX + slotNameW + PRESET_AND_TABLE.TABLE_COLUMN_GAP
            local colResultX = colSpellX + slotSpellW + PRESET_AND_TABLE.TABLE_COLUMN_GAP

            widgets.slotColStatus:ClearAllPoints()
            setDockObjectVisible(widgets.slotColStatus, false)
            widgets.slotColStatus:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
            widgets.slotColDestination:ClearAllPoints()
            setDockObjectVisible(widgets.slotColDestination, true)
            widgets.slotColDestination:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", colDestX + SLOT_HEADER_TEXT_X_SHIFT, y + DESTINATION_COLUMN_Y_SHIFT)
            widgets.slotColName:ClearAllPoints()
            setDockObjectVisible(widgets.slotColName, true)
            widgets.slotColName:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", colNameX + SLOT_HEADER_TEXT_X_SHIFT, y + NAME_SPELL_COLUMNS_Y_SHIFT)
            widgets.slotColSpellID:ClearAllPoints()
            setDockObjectVisible(widgets.slotColSpellID, true)
            widgets.slotColSpellID:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", colSpellX + SLOT_HEADER_TEXT_X_SHIFT, y + NAME_SPELL_COLUMNS_Y_SHIFT)
            widgets.slotColResult:ClearAllPoints()
            setDockObjectVisible(widgets.slotColResult, true)
            widgets.slotColResult:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", colResultX, y + RESULT_COLUMN_Y_SHIFT)
            y = y - PRESET_AND_TABLE.TABLE_HEADER_BOTTOM_GAP

            for i = 1, 10 do
                local row = slotRows[i]
                row.enabled:ClearAllPoints()
                row.enabled:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", colEnableX, y - PRESET_AND_TABLE.SLOT_ROW_TOP_NUDGE + SLOT_ENABLE_CHECKBOX_Y_SHIFT)
                row.status:ClearAllPoints()
                row.status:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PAGE.OFFSCREEN_X, y + STATUS_TEXT_Y_SHIFT)
                row.destination:ClearAllPoints()
                row.destination:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", colDestX, y - PRESET_AND_TABLE.SLOT_ROW_TOP_NUDGE + DESTINATION_COLUMN_Y_SHIFT)
                row.destination:SetSize(slotDestW, FIXED_FOOTPRINTS.STANDARD_CONTROL_H)
                row.namePill:ClearAllPoints()
                row.namePill:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", colNameX, y - PRESET_AND_TABLE.SLOT_ROW_TOP_NUDGE + NAME_SPELL_COLUMNS_Y_SHIFT)
                row.namePill:SetSize(slotNameW, FIXED_FOOTPRINTS.STANDARD_CONTROL_H)
                row.spellIDPill:ClearAllPoints()
                row.spellIDPill:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", colSpellX, y - PRESET_AND_TABLE.SLOT_ROW_TOP_NUDGE + NAME_SPELL_COLUMNS_Y_SHIFT)
                row.spellIDPill:SetSize(slotSpellW, FIXED_FOOTPRINTS.STANDARD_CONTROL_H)
                row.result:ClearAllPoints()
                row.result:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", colResultX, y - PRESET_AND_TABLE.SLOT_RESULT_TOP_NUDGE + RESULT_COLUMN_Y_SHIFT)
                row.result:SetSize(slotResultW, slotResultW)
                y = y - PRESET_AND_TABLE.SLOT_ROW_STEP
            end

            local lowerBlockBaseY = y + LOWER_SECTIONS_BLOCK_OFFSET_Y
            widgets.lowerSectionsContainer:ClearAllPoints()
            widgets.lowerSectionsContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, lowerBlockBaseY)
            widgets.lowerSectionsContainer:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", 0, lowerBlockBaseY)
            widgets.lowerSectionsContainer:SetHeight(FIXED_FOOTPRINTS.LOWER_SECTIONS_SEED_H)

            local lowerParent = widgets.lowerSectionsContainer
            local lowerY = 0
            local tableToDividerGap = LOWER_SECTIONS.TABLE_TO_DIVIDER_GAP
            local dividerToLayoutGap = LOWER_SECTIONS.DIVIDER_TO_LAYOUT_GAP

            widgets.hideDungeonDivider:ClearAllPoints()
            widgets.hideDungeonDivider:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", dividerLeftX, lowerY - tableToDividerGap)
            widgets.hideDungeonDivider:SetPoint("TOPRIGHT", lowerParent, "TOPRIGHT", -right, lowerY - tableToDividerGap)
            widgets.hideDungeonDivider:SetHeight(FIXED_FOOTPRINTS.DIVIDER_H)
            lowerY = lowerY - tableToDividerGap - dividerToLayoutGap

            local sectionLabelX = leftBase + LABEL_X
            local sectionControlX = leftBase + CONTROL_X
            local segmentedW = math.max(LOWER_SECTIONS.SEGMENTED_MIN_W, math.min(LOWER_SECTIONS.SEGMENTED_MAX_W, contentW - sectionControlX - right - LOWER_SECTIONS.CONTROL_RIGHT_PAD))
            local sliderControlW = math.max(LOWER_SECTIONS.SLIDER_CONTROL_MIN_W, math.min(LOWER_SECTIONS.SLIDER_CONTROL_MAX_W, segmentedW))
            local layoutStepperW = math.max(LOWER_SECTIONS.LAYOUT_STEPPER_MIN_W, math.min(LOWER_SECTIONS.LAYOUT_STEPPER_MAX_W, segmentedW))
            local fontSizeStepperW = math.max(LOWER_SECTIONS.FONT_SIZE_STEPPER_MIN_W, math.min(LOWER_SECTIONS.FONT_SIZE_STEPPER_MAX_W, segmentedW))
            local outlineRowW = math.max(LOWER_SECTIONS.OUTLINE_ROW_MIN_W, math.min(LOWER_SECTIONS.OUTLINE_ROW_MAX_W, segmentedW))
            local fontColorSwatchSize = FIXED_FOOTPRINTS.FONT_COLOR_SWATCH_SIZE

            local function placeSegment(spec, rowY, controlW, anchorFrame)
                local anchorParent = anchorFrame or scrollChild
                spec.label:ClearAllPoints()
                spec.label:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", sectionLabelX, rowY)
                spec.control:ClearAllPoints()
                spec.control:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", sectionControlX, rowY)
                if spec.Layout then
                    spec:Layout(controlW)
                end
                return rowY - LOWER_SECTIONS.ROW_STEP
            end

            local function moveSpecOffscreen(spec, anchorFrame)
                if not spec or not spec.control or not spec.label then
                    return
                end
                local anchorParent = anchorFrame or scrollChild
                setDockObjectVisible(spec.control, false)
                setDockObjectVisible(spec.label, false)
                if spec.valueText then
                    setDockObjectVisible(spec.valueText, false)
                end
                spec.control:ClearAllPoints()
                spec.control:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                spec.label:ClearAllPoints()
                spec.label:SetPoint("TOPLEFT", anchorParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
            end

            local function placeDropdownRow(spec, rowY, controlW, anchorFrame)
                placeControl(spec, sectionLabelX, sectionControlX, rowY, controlW, anchorFrame)
                return rowY - LOWER_SECTIONS.ROW_STEP
            end

            local function placeSliderRow(spec, rowY, controlW, anchorFrame)
                placeControl(spec, sectionLabelX, sectionControlX, rowY, controlW, anchorFrame)
                return rowY - LOWER_SECTIONS.ROW_STEP
            end

            local function placeStepperRow(spec, rowY, controlW, anchorFrame)
                placeControl(spec, sectionLabelX, sectionControlX, rowY, controlW, anchorFrame)
                return rowY - LOWER_SECTIONS.ROW_STEP
            end

            widgets.layoutSectionHeader:ClearAllPoints()
            widgets.layoutSectionHeader:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", leftBase + CHECK_X, lowerY)
            lowerY = lowerY - LOWER_SECTIONS.SECTION_HEADER_STEP

            lowerY = placeSegment(widgets.layoutModeSegment, lowerY, segmentedW, lowerParent)
            local currentLayoutMode = getDockSimpleLayoutModeForSettings((PortalAuthority and PortalAuthority.defaults) or {})
            local showWrap = (currentLayoutMode == "GRID")
            if showWrap then
                setDockObjectVisible(widgets.iconsPerRowGridOnlyHint, true)
                lowerY = placeStepperRow(widgets.iconsPerRow, lowerY, layoutStepperW, lowerParent)
            else
                setDockObjectVisible(widgets.iconsPerRowGridOnlyHint, false)
                if widgets.iconsPerRow and widgets.iconsPerRow.control and widgets.iconsPerRow.label then
                    setDockObjectVisible(widgets.iconsPerRow.control, false)
                    setDockObjectVisible(widgets.iconsPerRow.label, false)
                    widgets.iconsPerRow.control:ClearAllPoints()
                    widgets.iconsPerRow.control:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                    widgets.iconsPerRow.label:ClearAllPoints()
                    widgets.iconsPerRow.label:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                end
            end
            if widgets.iconsPerRowGridOnlyHint and widgets.iconsPerRow and widgets.iconsPerRow.control then
                widgets.iconsPerRowGridOnlyHint:ClearAllPoints()
                widgets.iconsPerRowGridOnlyHint:SetPoint("LEFT", widgets.iconsPerRow.control, "RIGHT", PAGE.CONTROL_PLACEMENT.VALUE_TEXT_GAP, 0)
            end
            lowerY = lowerY + (showWrap and LOWER_SECTIONS.WRAP_PRESENT_TIGHTEN or 0) -- tighten only when wrap row is present
            if widgets.layoutIconSize and widgets.layoutIconSize.Refresh then
                widgets.layoutIconSize.Refresh()
            end
            lowerY = placeSliderRow(widgets.layoutIconSize, lowerY, sliderControlW, lowerParent)
            widgets.layoutSpacingHint:ClearAllPoints()
            widgets.layoutSpacingHint:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", sectionControlX, lowerY + LOWER_SECTIONS.LAYOUT_HINT_TOP_NUDGE)
            lowerY = lowerY - LOWER_SECTIONS.LAYOUT_HINT_STEP

            lowerY = lowerY - LOWER_SECTIONS.SECTION_GAP_TIGHT
            widgets.labelsSectionHeader:ClearAllPoints()
            widgets.labelsSectionHeader:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", leftBase + CHECK_X, lowerY)
            lowerY = lowerY - LOWER_SECTIONS.SECTION_HEADER_STEP

            lowerY = placeSegment(widgets.labelMode, lowerY, segmentedW, lowerParent)
            if widgets.labelSide and widgets.labelSide.control and widgets.labelSide.control:IsShown() then
                lowerY = placeSegment(widgets.labelSide, lowerY, segmentedW, lowerParent)
                moveSpecOffscreen(widgets.labelSideInside, lowerParent)
            elseif widgets.labelSideInside and widgets.labelSideInside.control and widgets.labelSideInside.control:IsShown() then
                lowerY = placeSegment(widgets.labelSideInside, lowerY, segmentedW, lowerParent)
                moveSpecOffscreen(widgets.labelSide, lowerParent)
            else
                moveSpecOffscreen(widgets.labelSide, lowerParent)
                moveSpecOffscreen(widgets.labelSideInside, lowerParent)
            end

            lowerY = lowerY - LOWER_SECTIONS.SECTION_GAP_TIGHT
            widgets.styleSectionHeader:ClearAllPoints()
            widgets.styleSectionHeader:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", leftBase + CHECK_X, lowerY)
            lowerY = lowerY - LOWER_SECTIONS.SECTION_HEADER_STEP

            local labelsEnabled = (getDockLabelModeForSettings((PortalAuthority and PortalAuthority.defaults) or {}) ~= "OFF")
            setLabelStyleRowsVisible(labelsEnabled)

            if labelsEnabled then
                local fontRowY = lowerY
                local fontToSizeGap = LOWER_SECTIONS.FONT_TO_SIZE_GAP
                local sizeToSwatchGap = LOWER_SECTIONS.SIZE_TO_SWATCH_GAP
                local availableForControls = math.max(LOWER_SECTIONS.FONT_ROW_CONTROL_MIN_W, contentW - sectionControlX - right - LOWER_SECTIONS.CONTROL_RIGHT_PAD)
                local reservedForInline = fontSizeStepperW + fontToSizeGap + sizeToSwatchGap + fontColorSwatchSize
                local fontPickerW = math.max(LOWER_SECTIONS.FONT_PICKER_MIN_W, availableForControls - reservedForInline)

                placeControl(widgets.font, sectionLabelX, sectionControlX, fontRowY, fontPickerW, lowerParent)
                local fontRowAnchor = widgets.font.control

                widgets.fontSize.label:ClearAllPoints()
                setDockObjectVisible(widgets.fontSize.label, false)
                widgets.fontSize.label:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                widgets.fontSize.control:ClearAllPoints()
                setDockObjectVisible(widgets.fontSize.control, true)
                widgets.fontSize.control:SetPoint("LEFT", fontRowAnchor, "RIGHT", fontToSizeGap, 0)
                if widgets.fontSize.SetWidth then
                    widgets.fontSize:SetWidth(fontSizeStepperW)
                else
                    widgets.fontSize.control:SetWidth(fontSizeStepperW)
                end

                local sizeAnchor = widgets.fontSize.control

                widgets.color.inlineLabel:ClearAllPoints()
                setDockObjectVisible(widgets.color.inlineLabel, false)
                widgets.color.inlineLabel:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                widgets.color.swatch:ClearAllPoints()
                setDockObjectVisible(widgets.color.swatch, true)
                widgets.color.swatch:SetPoint("LEFT", sizeAnchor, "RIGHT", sizeToSwatchGap, 0)
                widgets.color.swatch:SetSize(fontColorSwatchSize, fontColorSwatchSize)

                lowerY = lowerY - LOWER_SECTIONS.FONT_ROW_STEP
                lowerY = placeSegment(widgets.outlineToggle, lowerY, outlineRowW, lowerParent)
            else
                if widgets.font and widgets.font.control and widgets.font.label then
                    setDockObjectVisible(widgets.font.control, false)
                    setDockObjectVisible(widgets.font.label, false)
                    widgets.font.control:ClearAllPoints()
                    widgets.font.control:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                    widgets.font.label:ClearAllPoints()
                    widgets.font.label:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                end
                if widgets.fontSize and widgets.fontSize.control then
                    setDockObjectVisible(widgets.fontSize.control, false)
                    widgets.fontSize.control:ClearAllPoints()
                    widgets.fontSize.control:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                end
                if widgets.color and widgets.color.swatch then
                    setDockObjectVisible(widgets.color.swatch, false)
                    widgets.color.swatch:ClearAllPoints()
                    widgets.color.swatch:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                end
                if widgets.outlineToggle and widgets.outlineToggle.control and widgets.outlineToggle.label then
                    setDockObjectVisible(widgets.outlineToggle.control, false)
                    setDockObjectVisible(widgets.outlineToggle.label, false)
                    widgets.outlineToggle.control:ClearAllPoints()
                    widgets.outlineToggle.control:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                    widgets.outlineToggle.label:ClearAllPoints()
                    widgets.outlineToggle.label:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                end
            end

            lowerY = placeSegment(widgets.hoverGlowSegment, lowerY, outlineRowW, lowerParent)
            lowerY = lowerY - LOWER_SECTIONS.SECTION_GAP_LOOSE
            widgets.visibilityDivider:ClearAllPoints()
            widgets.visibilityDivider:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", dividerLeftX, lowerY - LOWER_SECTIONS.VISIBILITY_DIVIDER_TOP_GAP)
            widgets.visibilityDivider:SetPoint("TOPRIGHT", lowerParent, "TOPRIGHT", -right, lowerY - LOWER_SECTIONS.VISIBILITY_DIVIDER_TOP_GAP)
            widgets.visibilityDivider:SetHeight(FIXED_FOOTPRINTS.DIVIDER_H)
            lowerY = lowerY - LOWER_SECTIONS.VISIBILITY_DIVIDER_STEP
            lowerY = lowerY - VISIBILITY_BLOCK_SHIFT_Y

            widgets.enableLabel:ClearAllPoints()
            widgets.enableLabel:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", leftBase + CHECK_X, lowerY)
            lowerY = lowerY - LOWER_SECTIONS.VISIBILITY_HEADER_STEP

            local visibilityToggleW = outlineRowW
            local visibilityRows = {
                widgets.hideCombat,
                widgets.hideCity,
                widgets.hideDungeon,
                widgets.gizmoMode,
            }
            for _, spec in ipairs(visibilityRows) do
                placeControl(spec, sectionLabelX, sectionControlX, lowerY, visibilityToggleW, lowerParent)
                if spec and spec.label then
                    spec.label:ClearAllPoints()
                    spec.label:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", sectionLabelX, lowerY - VISIBILITY_LABELS_SHIFT_Y)
                end
                lowerY = lowerY - LOWER_SECTIONS.ROW_STEP
            end
            lowerY = lowerY + math.max(0, LOWER_SECTIONS.ROW_STEP - FIXED_FOOTPRINTS.STANDARD_CONTROL_H)
            if widgets.hideNames and widgets.hideNames.control and widgets.hideNames.label then
                setDockObjectVisible(widgets.hideNames.control, false)
                setDockObjectVisible(widgets.hideNames.label, false)
                widgets.hideNames.control:ClearAllPoints()
                widgets.hideNames.control:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
                widgets.hideNames.label:ClearAllPoints()
                widgets.hideNames.label:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
            end
            widgets.visibilityLabelSpacer:ClearAllPoints()
            setDockObjectVisible(widgets.visibilityLabelSpacer, false)
            widgets.visibilityLabelSpacer:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
            widgets.visibilitySpacer:ClearAllPoints()
            setDockObjectVisible(widgets.visibilitySpacer, false)
            widgets.visibilitySpacer:SetPoint("TOPLEFT", lowerParent, "TOPLEFT", PAGE.OFFSCREEN_X, PAGE.OFFSCREEN_Y)
            local lowerSectionObjects = {
                widgets.layoutSectionHeader,
                widgets.layoutModeSegment and widgets.layoutModeSegment.control or nil,
                widgets.iconsPerRow and widgets.iconsPerRow.control or nil,
                widgets.iconsPerRowGridOnlyHint,
                widgets.layoutIconSize and widgets.layoutIconSize.control or nil,
                widgets.layoutSpacingHint,
                widgets.labelsSectionHeader,
                widgets.labelMode and widgets.labelMode.control or nil,
                widgets.labelSide and widgets.labelSide.control or nil,
                widgets.labelSideInside and widgets.labelSideInside.control or nil,
                widgets.styleSectionHeader,
                widgets.font and widgets.font.control or nil,
                widgets.fontSize and widgets.fontSize.control or nil,
                widgets.color and widgets.color.swatch or nil,
                widgets.outlineToggle and widgets.outlineToggle.control or nil,
                widgets.hoverGlowSegment and widgets.hoverGlowSegment.control or nil,
                widgets.visibilityDivider,
                widgets.enableLabel,
                widgets.hideCombat and widgets.hideCombat.control or nil,
                widgets.hideCombat and widgets.hideCombat.label or nil,
                widgets.hideCity and widgets.hideCity.control or nil,
                widgets.hideCity and widgets.hideCity.label or nil,
                widgets.hideDungeon and widgets.hideDungeon.control or nil,
                widgets.hideDungeon and widgets.hideDungeon.label or nil,
                widgets.gizmoMode and widgets.gizmoMode.control or nil,
                widgets.gizmoMode and widgets.gizmoMode.label or nil,
            }
            local lowerSectionExtent = measureSettingsVisibleContentExtent(lowerParent, lowerSectionObjects)
            local explicitLowerSectionH = math.max(FIXED_FOOTPRINTS.LOWER_SECTIONS_SEED_H, math.ceil(-lowerY))
            local measuredLowerSectionH = lowerSectionExtent and math.ceil(lowerSectionExtent) or nil
            local lowerSectionH = math.max(explicitLowerSectionH, measuredLowerSectionH or 0)
            widgets.lowerSectionsContainer:SetHeight(lowerSectionH)

            y = lowerBlockBaseY - lowerSectionH

            local panelExtentObjects = {
                widgets.header,
                widgets.masterRowContainer,
                widgets.lockRowContainer,
                widgets.lockStateHelper,
                widgets.lockDockDivider,
                widgets.loadoutPresetSegment and widgets.loadoutPresetSegment.control or nil,
                widgets.dockCustomizationHelper,
                widgets.dockCustomizationMatchStatus,
                widgets.slotColDestination,
                widgets.slotColName,
                widgets.slotColSpellID,
                widgets.slotColResult,
                slotRows[10] and slotRows[10].enabled or nil,
                slotRows[10] and slotRows[10].destination or nil,
                slotRows[10] and slotRows[10].namePill or nil,
                slotRows[10] and slotRows[10].spellIDPill or nil,
                slotRows[10] and slotRows[10].result or nil,
                widgets.lowerSectionsContainer,
            }
            local panelMeasuredExtent = measureSettingsVisibleContentExtent(scrollChild, panelExtentObjects)
            local explicitPanelExtent = math.max(0, -y)
            local measuredPanelExtent = (panelMeasuredExtent and math.ceil(panelMeasuredExtent)) or nil
            local used = math.max(explicitPanelExtent, measuredPanelExtent or 0) + PAGE.BOTTOM_PAD
            local contentHeight = math.max(scrollFrame:GetHeight(), used)
            panelFrame._dockScrollLayoutPassToken = (tonumber(panelFrame._dockScrollLayoutPassToken) or 0) + 1
            panelFrame._dockResolvedNativeScrollPassToken = nil
            panelFrame._dockResolvedNativeScrollMax = nil
            panelFrame._dockPendingPostRelayoutSyncPassToken = nil
            scrollChild:SetHeight(contentHeight)
            updateScrollBehavior(scrollFrame, scrollChild)
            ensureDockScrollInteractionBindings()
            self._dockExpectedScrollMax = math.max(0, contentHeight - (scrollFrame:GetHeight() or 0))
            self._dockObservedScrollMax = getDockObservedScrollMax()
            applyDockScrollState(nil, {
                allowFallback = false,
                allowPostRelayoutSync = true,
            })
        end

        self._refresh = function()
            if ensureDatabase then
                ensureDatabase()
            end
            refreshDockXYDisplay()
            relayout()
            applyDockModuleEnabledState()
            if applyDockGizmoVisibilityOverrideState then
                applyDockGizmoVisibilityOverrideState()
            end
            refreshSettingsWindowHeaderAccessoryIfHosted(self)
        end

        PortalAuthority.onDockPositionChanged = function(x, y)
            if widgets.x and widgets.x.SetValue then
                widgets.x:SetValue(x)
            end
            if widgets.y and widgets.y.SetValue then
                widgets.y:SetValue(y)
            end
        end
        PortalAuthority.lockTipText = nil

        self._refreshDockXYDisplay = refreshDockXYDisplay
        self._destinationPicker = widgets.destinationPicker
        self._fontPicker = widgets.font and widgets.font.picker or nil
        self._renamePopover = widgets.renamePopover
        self._spellIDPopover = widgets.spellIDPopover
        self._paCloseFloatingControlsOnScroll = function(panel)
            if panel and panel._renamePopover and panel._renamePopover.IsShown and panel._renamePopover:IsShown() and panel._renamePopover.Close then
                panel._renamePopover:Close(false)
            end
            if panel and panel._spellIDPopover and panel._spellIDPopover.IsShown and panel._spellIDPopover:IsShown() and panel._spellIDPopover.Close then
                panel._spellIDPopover:Close(false)
            end
        end
        self._layout = relayout
        self._forceDockFontUiState = forceDockFontUiState
        self._forceDockFontSizeUiState = forceDockFontSizeUiState
        self._forceStyleToggleUiState = forceStyleToggleUiState
        self._forceDockIconSizeVisual = function()
            if not widgets.layoutIconSize then
                return
            end
            local dbValue = tonumber(PortalAuthorityDB and PortalAuthorityDB.dockIconSize)
            local uiValue = tonumber(PortalAuthorityDB and PortalAuthorityDB.dockIconSizeUI)
            if uiValue == nil and PortalAuthority and PortalAuthority.ApplyDockLayoutSettings and (not InCombatLockdown or not InCombatLockdown()) then
                pcall(function()
                    PortalAuthority:ApplyDockLayoutSettings(false)
                end)
                uiValue = tonumber(PortalAuthorityDB and PortalAuthorityDB.dockIconSizeUI)
            end
            local defaultValue = tonumber(PortalAuthority and PortalAuthority.defaults and PortalAuthority.defaults.dockIconSize) or 36
            local n = math.floor((uiValue or dbValue or defaultValue) + 0.5)
            if n < 16 then n = 16 end
            if n > 72 then n = 72 end
            if PortalAuthorityDB then
                PortalAuthorityDB.dockIconSizeUI = n
            end
            local slider = widgets.layoutIconSize.slider
            if slider then
                slider:SetValue(n)
            end
            if widgets.layoutIconSize.valueEdit then
                widgets.layoutIconSize.valueEdit:SetText(tostring(n))
                widgets.layoutIconSize.valueEdit:Hide()
            end
            if widgets.layoutIconSize.valueText then
                widgets.layoutIconSize.valueText:SetText(tostring(n))
                widgets.layoutIconSize.valueText:Show()
            end
        end

        registerRefreshCallback(function()
            if self._refresh then
                self._refresh()
            end
        end, self)
        scrollFrame:SetScript("OnSizeChanged", function()
            local useHostedFirstOpen = isPanelUsingCustomSettingsWindowHost(self)
            if useHostedFirstOpen and handleSettingsFirstOpenSizeReady(self, "size_changed") then
                return
            end
            if useHostedFirstOpen and shouldSuppressSettingsFirstOpenExternalRefresh(self) then
                return
            end
            relayout()
        end)
        self._settingsFirstOpenKey = "dock"
        self._settingsFirstOpenSizeTarget = scrollFrame
        self._settingsFirstOpenRender = function(panel)
            local selectionToken = tonumber(panel and panel._paFirstOpenSelectionToken) or 0
            if selectionToken ~= (tonumber(panel and panel._dockFirstOpenRenderToken) or 0) then
                panel._dockFirstOpenRenderToken = selectionToken
                panel._dockFirstOpenRenderPasses = 0
            end
            panel._dockFirstOpenRenderPasses = (tonumber(panel._dockFirstOpenRenderPasses) or 0) + 1
            renderDockPanel(panel)
        end
        self._settingsFirstOpenIsReady = function(panel)
            local viewportHeight = tonumber(scrollFrame and scrollFrame:GetHeight()) or 0
            local contentHeight = tonumber(scrollChild and scrollChild:GetHeight()) or 0
            local expectedMax = math.max(0, contentHeight - viewportHeight)
            local observedMax = math.max(
                tonumber(panel and panel._dockObservedScrollMax) or 0,
                getDockObservedScrollMax()
            )
            return isPanelUsingCustomSettingsWindowHost(panel)
                and panelHasSizedViewport(panel and panel._settingsFirstOpenSizeTarget or nil)
                and panel ~= nil
                and panel._initialized == true
                and type(panel._layout) == "function"
                and type(panel._refresh) == "function"
                and (tonumber(panel and panel._dockFirstOpenRenderPasses) or 0) >= 2
                and contentHeight >= math.max(viewportHeight, 1)
                and observedMax >= (expectedMax - 1)
        end
        settingsSearchRuntime.endDescriptorCapture(self)
        self._initialized = true
    end

    ensureDockPanelAnchored = function(self)
        local p = self:GetParent()
        if not p then
            return false
        end
        if self._paAnchorParent ~= p or not self._paAnchored then
            self:ClearAllPoints()
            self:SetAllPoints(p)
            self._paAnchorParent = p
        end
        self._paAnchored = true
        return true
    end

    renderDockPanel = function(self)
        ensureDockPanelAnchored(self)
        if self._refresh then
            self._refresh()
        end
    end

    panel:SetScript("OnShow", function(self)
        debugSettingsLog("OnShow:", self.name)
        if ensureDatabase then
            ensureDatabase()
        end
        self:EnsureBuilt()
        local useHostedFirstOpen = isPanelUsingCustomSettingsWindowHost(self)
        if useHostedFirstOpen and self._paFirstOpenState == "pending" then
            resetSettingsFirstOpenPanelState(self)
        end
        if useHostedFirstOpen and handleSettingsFirstOpenPanelShow(self) then
            return
        end
        withPanelHydration(self, function()
            renderDockPanel(self)
        end)
    end)
    panel:SetScript("OnHide", function(self)
        self._dockPendingPostRelayoutSyncPassToken = nil
        if isPanelUsingCustomSettingsWindowHost(self) or isSettingsFirstOpenSettlePending(self) then
            handleSettingsFirstOpenPanelHide(self)
        end
        if self._destinationPicker and self._destinationPicker.Close then
            self._destinationPicker:Close()
        end
        if self._fontPicker and self._fontPicker.Close then
            self._fontPicker:Close()
        end
        if self._renamePopover and self._renamePopover.Close then
            self._renamePopover:Close(false)
        end
        if self._spellIDPopover and self._spellIDPopover.Close then
            self._spellIDPopover:Close(false)
        end
    end)

    return panel
end


local function createTimersPanel()
    local panel = CreateFrame("Frame")
    panel.name = "Timers"
    panel._paSearchSectionKey = "timers"
    panel._paSearchSectionName = panel.name

    panel.EnsureBuilt = function(self)
        if self._initialized then return end
        self._initialized = true
        resetSettingsFirstOpenPanelState(self)
        ensureDatabase()
        settingsSearchRuntime.beginDescriptorCapture(self)

        local function getModulesApi()
            return PortalAuthority and PortalAuthority.Modules or nil
        end
        local stack = nil
        local widgets = {}
        local pickerSpecs = {}
        self._timersPickerSpecs = pickerSpecs
        local function isModuleAvailable(moduleId)
            return true, nil
        end
        local function getStack()
            local api = getModulesApi()
            if api and api.registry then
                stack = api.registry.timers
            end
            return stack
        end
        local function ensureTimersStorage()
            PortalAuthorityDB = PortalAuthorityDB or {}
            PortalAuthorityDB.modules = PortalAuthorityDB.modules or {}
            PortalAuthorityDB.modules.timers = PortalAuthorityDB.modules.timers or {}
            return PortalAuthorityDB.modules.timers
        end
        local fallbackTimersDb = ensureTimersStorage()
        local function getLegacyTimersDb()
            if PortalAuthorityDB and PortalAuthorityDB.modules and type(PortalAuthorityDB.modules.modules2Stack) == "table" then
                return PortalAuthorityDB.modules.modules2Stack
            end
            return nil
        end
        local function getPersistedTimersDb()
            if PortalAuthorityDB and PortalAuthorityDB.modules and PortalAuthorityDB.modules.timers then
                return PortalAuthorityDB.modules.timers
            end
            return fallbackTimersDb
        end
        local function readTimerSetting(db, key, defaultValue)
            if db and db[key] ~= nil then
                return db[key]
            end
            local persisted = getPersistedTimersDb()
            if persisted and persisted[key] ~= nil then
                return persisted[key]
            end
            local legacy = getLegacyTimersDb()
            if legacy and legacy[key] ~= nil then
                return legacy[key]
            end
            return defaultValue
        end
        local function writeTimerSetting(db, key, value)
            if db then
                db[key] = value
            end
            local persisted = getPersistedTimersDb()
            if persisted then
                persisted[key] = value
            end
        end
        local function getTimersLockedState()
            local activeStack = getStack()
            if activeStack and activeStack.GetDB then
                local db = activeStack:GetDB()
                if db and db.locked ~= nil then
                    return db.locked and true or false
                end
            end

            local persisted = getPersistedTimersDb()
            if persisted and persisted.locked ~= nil then
                return persisted.locked and true or false
            end

            if widgets and widgets.unlock and widgets.unlock.GetChecked then
                return widgets.unlock:GetChecked() and true or false
            end

            return true
        end
        local function getTimersDBSnapshot()
            local activeStack = getStack()
            local db = nil
            if activeStack and activeStack.GetDB then
                db = activeStack:GetDB()
            else
                db = fallbackTimersDb
            end
            return activeStack, db
        end
        local function getTimersDisplayPosition(activeStack, db)
            local fallbackX = math.floor(tonumber(readTimerSetting(db, "x", 0)) or 0)
            local fallbackY = math.floor(tonumber(readTimerSetting(db, "y", 0)) or 0)
            if not activeStack or not activeStack.frame or not activeStack.frame.GetCenter or not UIParent or not UIParent.GetCenter then
                return fallbackX, fallbackY
            end
            local cx, cy = activeStack.frame:GetCenter()
            local ux, uy = UIParent:GetCenter()
            if not cx or not cy or not ux or not uy then
                return fallbackX, fallbackY
            end
            return math.floor((cx - ux) + 0.5), math.floor((cy - uy) + 0.5)
        end

        local scrollFrame, scrollChild = createScrollableChild(self)
        if not scrollFrame or not scrollChild then
            settingsSearchRuntime.endDescriptorCapture(self)
            return
        end
        self._sizingFrame = scrollFrame
        self._kuScrollFrame = scrollFrame
        self._kuScrollChild = scrollChild

        local header = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormalLarge", 14)
        header:SetText("|cffffd100Timers|r")
        header:SetJustifyH("LEFT")
        local headerDescriptor = createSettingsSectionDescriptor(scrollChild, "Configure your M+ timers.")

        local TIMERS_LAYOUT = {
            MIN_CONTENT_W = 560,
            TOP_PAD = 20,
            BOTTOM_PAD = 20,
            HEADER_LEFT = 16,
            CONTENT_LEFT = 20,
            CONTENT_RIGHT = 20,
            HIDDEN_X = -5000,
            HIDDEN_Y = -5000,
            TOGGLE_COL_X = 220,
            APPEAR_CONTROL_SHIFT_X = -12,
            LABEL_TO_CONTROL_GAP = 12,
            LOCK_TOGGLE_TO_RESET_GAP = 12,
            LOCK_TOGGLE_PREF_W = 140,
            LOCK_TOGGLE_MIN_W = 96,
            MODULE_TOGGLE_PREF_W = 150,
            MIN_PICKER_W = 140,
            MIN_SEGMENT_W = 140,
            MAIN_CONTROL_TARGET_W = 202,
            MAIN_CONTROL_MIN_W = 196,
            PICKER_DEFAULT_W = 180,
            ASPECT_PICKER_W = 186,
            PICKER_CONTROL_H = 22,
            LOCK_ROW_SEED_H = 22,
            SLIDER_CONTROL_W = 260,
            SLIDER_VALUE_BUTTON_W = 44,
            SLIDER_VALUE_BUTTON_H = 16,
            SLIDER_VALUE_GAP = 8,
            SLIDER_TRACK_H = 2,
            SLIDER_THUMB_HIT_SIZE = 16,
            SLIDER_THUMB_SIZE = 8,
            SLIDER_GLOW_SIZE = 14,
            ICON_EDGE_SEGMENT_MIN_W = 82,
            RESET_BUTTON_SEED_W = 104,
            RESET_BUTTON_PREF_W = 102,
            RESET_BUTTON_MIN_W = 102,
            BATCH_BUTTON_COMPRESS_MIN_W = 80,
            ACTION_BUTTON_TEXT_PAD_X = 22,
            SEGMENT_BUTTON_TEXT_PAD_X = 20,
            MEASURE_SINGLE_LINE_W = 4096,
            HEADER_FLOOR = 16,
            SECTION_HEADER_FLOOR = 12,
            LABEL_FLOOR = 12,
            HELPER_FLOOR = 10,
            MINI_LABEL_FLOOR = 10,
            CONTROL_FLOOR = 22,
            LOCK_ROW_FLOOR = 22,
            ROW_FLOOR = 36,
            OFFSET_ROW_FLOOR = 56,
            HEADER_BOTTOM_GAP = 14,
            LOCK_HELPER_GAP_RATIO = 0.625,
            LOCK_DIVIDER_GAP_RATIO = 1.25,
            LOCK_DIVIDER_OFFSET_RATIO = 0.5,
            SECTION_HEADER_BOTTOM_GAP = 4,
            MODULE_CARD_TO_ROWS_GAP = 12,
            MODULE_CHILD_INDENT = 16,
            MODULE_CHILD_ROW_GAP = 4,
            MODULE_ROW_TO_HELPER_GAP = 4,
            MODULE_ROW_TO_EXPLAIN_GAP = 4,
            MODULE_HELPER_TO_EXPLAIN_GAP = 4,
            MODULE_EXPLAIN_LINE_GAP = 5,
            MODULE_EXPLAIN_BLOCK_GAP = 12,
            SECTION_TO_NEXT_DIVIDER_GAP = 24,
            CARD_PADDING = 8,
            CARD_LABEL_TO_BUTTONS_GAP = 8,
            CARD_BUTTONS_TO_STATUS_GAP = 4,
            BATCH_BUTTON_GAP = 8,
            BATCH_BUTTON_H = 22,
            BATCH_BUTTON_PREF_W = 156,
            BATCH_BUTTON_MIN_W = 120,
            BATCH_SCOPE_GAP = 6,
            FONT_SIZE_W = 52,
            FONT_SIZE_GAP = 8,
            FONT_STACK_GAP = 4,
            AXIS_LABEL_MIN_W = 10,
            AXIS_TO_CONTROL_GAP = 6,
            AXIS_LINE_GAP = 8,
        }

        widgets.unlock = CreateFrame("CheckButton", nil, scrollChild, "UICheckButtonTemplate")
        widgets.unlock.text:SetText("Lock Position")
        applyGlobalFontToObject(widgets.unlock.text, 12)
        local unlockLabelNormalColor = { widgets.unlock.text:GetTextColor() }
        local function updateUnlockLabelColor(isLocked)
            if isLocked then
                widgets.unlock.text:SetTextColor(unlockLabelNormalColor[1], unlockLabelNormalColor[2], unlockLabelNormalColor[3], unlockLabelNormalColor[4])
            else
                widgets.unlock.text:SetTextColor(1, 0.2, 0.2)
            end
        end
        widgets.unlock:SetScript("OnClick", function(btn)
            local isLocked = not not btn:GetChecked()
            local desiredUnlocked = not isLocked
            local activeStack = getStack()
            local actualUnlocked = not getTimersLockedState()
            if InCombatLockdown and InCombatLockdown() and actualUnlocked ~= nil and desiredUnlocked ~= not not actualUnlocked then
                local actualLocked = not not (not actualUnlocked)
                btn:SetChecked(actualLocked)
                updateUnlockLabelColor(actualLocked)
                return
            end

            -- Force immediate visual response for lock/unlock so frame + drag handle
            -- appear without waiting for external events/tickers.
            activeStack = getStack()
            if activeStack then
                if desiredUnlocked and activeStack.Initialize and not (activeStack.frame or activeStack.mainFrame) then
                    activeStack:Initialize()
                end
                if activeStack.SetUnlocked then
                    activeStack:SetUnlocked(desiredUnlocked)
                end
                if activeStack.ApplyPosition then
                    activeStack:ApplyPosition()
                end
                if activeStack.EvaluateVisibility and (activeStack.frame or activeStack.mainFrame) then
                    activeStack:EvaluateVisibility("options-lock-toggle")
                end
                if desiredUnlocked and activeStack.Tick then
                    activeStack:Tick()
                end
            end

            local authoritativeLocked = getTimersLockedState()
            btn:SetChecked(authoritativeLocked)
            updateUnlockLabelColor(authoritativeLocked)
            if self._refresh then self._refresh() end
        end)

        local applyStackSettings

        local function mkCheck(parent, text, key)
            local c = CreateFrame("CheckButton", nil, parent, "UICheckButtonTemplate")
            c.text:SetText(text)
            applyGlobalFontToObject(c.text, 12)
            c.text:SetTextColor(1, 0.82, 0, 1)
            c:SetScript("OnClick", function(btn)
                local activeStack = getStack()
                if not activeStack then return end
                activeStack:GetDB()[key] = not not btn:GetChecked()
                activeStack:ApplySettings()
                local api = getModulesApi()
                if api and api.timersTestMode then
                    if activeStack.EvaluateVisibility then
                        activeStack:EvaluateVisibility()
                    end
                    if activeStack.Tick then
                        activeStack:Tick()
                    end
                end
                if self._refresh then self._refresh() end
            end)
            return c
        end

        local function mkPickerButton(parent, opts)
            opts = type(opts) == "table" and opts or {}
            local optionsProvider = type(opts.optionsProvider) == "function" and opts.optionsProvider or function() return {} end
            local getter = type(opts.getter) == "function" and opts.getter or function() return "" end
            local setter = type(opts.setter) == "function" and opts.setter or function() end
            local onApply = type(opts.onApply) == "function" and opts.onApply or nil
            local fallbackLabel = type(opts.fallbackLabel) == "function" and opts.fallbackLabel or nil

            local button = CreateFrame("Button", nil, parent, "BackdropTemplate")
            button:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
            button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
            button:SetHeight(TIMERS_LAYOUT.PICKER_CONTROL_H)
            button:SetWidth(math.max(0, tonumber(opts.width) or TIMERS_LAYOUT.PICKER_DEFAULT_W))

            local text = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 11)
            text:SetPoint("LEFT", button, "LEFT", 8, 0)
            text:SetPoint("RIGHT", button, "RIGHT", -18, 0)
            text:SetJustifyH("LEFT")
            text:SetTextColor(0.92, 0.92, 0.92, 1)

            local caret = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 10)
            caret:SetPoint("RIGHT", button, "RIGHT", -7, 0)
            caret:SetText("v")
            caret:SetTextColor(0.76, 0.76, 0.78, 1)

            local spec = { kind = "picker_button", control = button, text = text, caret = caret }
            local picker = CreatePicker(UIParent, {}, function(value)
                local selectedValue = tostring(value or "")
                setter(selectedValue)
                if onApply then
                    onApply()
                end
                if spec.Refresh then
                    spec.Refresh()
                end
            end, {
                title = tostring(opts.title or "Select Option"),
                searchHint = tostring(opts.searchHint or "Search"),
                width = tonumber(opts.pickerWidth) or 420,
                height = tonumber(opts.pickerHeight) or 360,
                showSecondary = opts.showSecondary and true or false,
                useOptionFontPreview = opts.useOptionFontPreview and true or false,
                previewFontSize = tonumber(opts.previewFontSize) or 12,
                rowHeight = tonumber(opts.rowHeight) or 26,
                showClearButton = false,
                noSearch = opts.noSearch and true or false,
                hideTitle = opts.hideTitle and true or false,
                hideScrollBar = opts.hideScrollBar and true or false,
            })
            spec.picker = picker

            local function applyVisual(hovered)
                if hovered then
                    button:SetBackdropColor(0.16, 0.17, 0.20, 0.95)
                    button:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                    caret:SetTextColor(0.88, 0.88, 0.90, 1)
                else
                    button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
                    button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                    caret:SetTextColor(0.76, 0.76, 0.78, 1)
                end
            end

            button:SetScript("OnEnter", function()
                applyVisual(true)
            end)
            button:SetScript("OnLeave", function()
                applyVisual(false)
            end)

            local function buildPickerOptions()
                local built = {}
                for _, option in ipairs(optionsProvider() or {}) do
                    local value = tostring(option.value or "")
                    built[#built + 1] = {
                        value = value,
                        label = tostring(option.label or value),
                        buttonLabel = tostring(option.buttonLabel or option.label or value),
                        secondary = tostring(option.secondary or ""),
                        previewFontPath = option.previewFontPath,
                        aliases = option.aliases,
                    }
                end
                if #built == 0 then
                    built[1] = { value = "", label = "None", buttonLabel = "None", secondary = "" }
                end
                return built
            end

            local function resolveSelection(rawValue, options)
                local selected = tostring(rawValue or "")
                local selectedLabel = nil
                for _, option in ipairs(options or {}) do
                    if tostring(option.value or "") == selected then
                        selected = tostring(option.value or "")
                        selectedLabel = tostring(option.buttonLabel or option.label or selected)
                        break
                    end
                end
                if not selectedLabel then
                    if fallbackLabel then
                        selectedLabel = tostring(fallbackLabel(selected) or "")
                    end
                    if selectedLabel == "" then
                        local first = options and options[1] or nil
                        if first then
                            selected = tostring(first.value or "")
                            selectedLabel = tostring(first.buttonLabel or first.label or selected)
                            setter(selected)
                        else
                            selectedLabel = "None"
                        end
                    end
                end
                return selected, selectedLabel
            end

            spec.SetWidth = function(_, newWidth)
                button:SetWidth(math.max(0, math.floor(tonumber(newWidth) or opts.width or TIMERS_LAYOUT.PICKER_DEFAULT_W)))
            end
            spec.ClosePicker = function()
                if picker and picker.IsShown and picker:IsShown() then
                    picker:Close()
                end
            end

            spec.Refresh = function()
                local options = buildPickerOptions()
                picker:SetOptions(options)
                local selectedValue, selectedLabel = resolveSelection(getter(), options)
                picker:SetSelectedValue(selectedValue)
                text:SetText(selectedLabel ~= "" and selectedLabel or "None")
            end

            button:SetScript("OnClick", function()
                if picker and picker.IsShown and picker:IsShown() then
                    picker:Close()
                    return
                end
                spec.Refresh()
                picker:Open(button)
            end)

            pickerSpecs[#pickerSpecs + 1] = spec
            spec.Refresh()
            return spec
        end

        local function mkFontDropdown(parent, getter, setter)
            local function fontFallbackLabel(path)
                local value = trim(tostring(path or ""))
                if value == "" then
                    return "Global UI Font"
                end
                value = value:gsub("/", "\\")
                return value:match("([^\\]+)$") or value
            end
            return mkPickerButton(parent, {
                width = TIMERS_LAYOUT.PICKER_DEFAULT_W,
                title = "Select Font Face",
                searchHint = "Search fonts by name",
                pickerWidth = 420,
                pickerHeight = 380,
                showSecondary = false,
                useOptionFontPreview = true,
                previewFontSize = 13,
                rowHeight = 26,
                optionsProvider = buildSharedFontPickerChoices,
                getter = function()
                    return tostring(getter() or "")
                end,
                setter = function(v)
                    setter(v or "")
                end,
                onApply = function()
                    applyStackSettings()
                end,
                fallbackLabel = fontFallbackLabel,
            })
        end

        local function mkNumeric(parent, onApply)
            local e = CreateFrame("EditBox", nil, parent)
            e:SetAutoFocus(false)
            e:SetMultiLine(false)
            e:SetTextInsets(8, 8, 0, 0)
            e:SetTextColor(1,1,1,1)
            e:SetHighlightColor(1,1,1,0.25)
            applyGlobalFontToObject(e, 11)
            e:SetJustifyH("CENTER")

            if not e._paTimersBg then
                e._paTimersBg = e:CreateTexture(nil, "ARTWORK")
                e._paTimersBg:SetAllPoints(e)
                e._paTimersBg:SetTexture("Interface\\Buttons\\WHITE8x8")
                e._paTimersBg:SetVertexColor(0.10, 0.11, 0.14, 0.95)

                e._paTimersBorder = CreateFrame("Frame", nil, e, "BackdropTemplate")
                e._paTimersBorder:SetPoint("TOPLEFT", e, "TOPLEFT", -1, 1)
                e._paTimersBorder:SetPoint("BOTTOMRIGHT", e, "BOTTOMRIGHT", 1, -1)
                e._paTimersBorder:SetBackdrop({
                    edgeFile = "Interface\\Buttons\\WHITE8x8",
                    edgeSize = 1,
                })
                e._paTimersBorder:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
            end

            local function hideTemplateChrome()
                local left = e.Left
                local mid = e.Middle
                local right = e.Right
                if left then left:SetAlpha(0) end
                if mid then mid:SetAlpha(0) end
                if right then right:SetAlpha(0) end
            end

            local function applyEditVisual()
                hideTemplateChrome()
                if e:HasFocus() then
                    e._paTimersBg:SetVertexColor(0.12, 0.13, 0.17, 0.95)
                    e._paTimersBorder:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                else
                    e._paTimersBg:SetVertexColor(0.10, 0.11, 0.14, 0.95)
                    e._paTimersBorder:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                end
            end

            e:SetScript("OnShow", function()
                applyEditVisual()
            end)
            e:SetScript("OnEditFocusGained", function()
                applyEditVisual()
            end)
            e:SetScript("OnEditFocusLost", function(edit)
                applyEditVisual()
                if onApply then
                    onApply(edit)
                end
            end)
            e:SetScript("OnEnterPressed", function(edit)
                if onApply then
                    onApply(edit)
                end
                edit:ClearFocus()
            end)
            e:SetScript("OnEscapePressed", function(edit)
                edit:ClearFocus()
            end)
            return e
        end

        local function setReadableNumericText(edit)
            if not edit then return end
            edit:SetTextColor(1, 1, 1, 1)
            edit:SetCursorPosition(0)
        end

        applyStackSettings = function()
            local activeStack = getStack()
            if not activeStack then return end
            activeStack:ApplySettings()
            local api = getModulesApi()
            if api and api.timersTestMode then
                if activeStack.EvaluateVisibility then
                    activeStack:EvaluateVisibility()
                end
                if activeStack.Tick then
                    activeStack:Tick()
                end
            end
        end

        local fontLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        fontLabel:SetText("Font / Size")
        fontLabel:SetJustifyH("LEFT")
        local fontDropdown = mkFontDropdown(scrollChild, function()
            local activeStack = getStack()
            return activeStack and activeStack:GetDB().fontPath or ""
        end, function(v)
            local activeStack = getStack()
            if activeStack then activeStack:GetDB().fontPath = v end
        end)

        local sizeLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        sizeLabel:SetText("")
        local sizeEdit = nil
        local sizeStepper = nil
        if type(createCanonicalDockFontSizeStepperControl) == "function" then
            sizeStepper = createCanonicalDockFontSizeStepperControl(
                scrollChild,
                "",
                8,
                48,
                1,
                "fontSize",
                52,
                function()
                    applyStackSettings()
                end,
                nil,
                {
                    micro = true,
                    shiftMultiplier = 5,
                    getValue = function()
                        local activeStack = getStack()
                        local db = activeStack and activeStack:GetDB() or nil
                        local raw = tonumber(db and db.fontSize) or 12
                        return math.floor(math.min(48, math.max(8, raw)))
                    end,
                    setValue = function(v)
                        local activeStack = getStack()
                        if not activeStack then
                            return
                        end
                        local db = activeStack:GetDB()
                        local raw = tonumber(v)
                        if raw == nil then
                            raw = tonumber(db.fontSize) or 12
                        end
                        db.fontSize = math.floor(math.min(48, math.max(8, raw)))
                    end,
                }
            )
            if sizeStepper and sizeStepper.label then
                sizeStepper.label:SetText("")
                sizeStepper.label:Hide()
            end
        else
            sizeEdit = mkNumeric(scrollChild, function(edit)
                local activeStack = getStack()
                if not activeStack then return end
                local db = activeStack:GetDB()
                local text = trim(edit:GetText() or "")
                local v = tonumber(text)
                if v ~= nil then
                    db.fontSize = math.floor(math.min(48, math.max(8, v)))
                end
                applyStackSettings()
                edit:SetText(tostring(db.fontSize))
                edit:SetTextColor(1, 1, 1, 1)
            end)
            setReadableNumericText(sizeEdit)
            sizeEdit:SetNumeric(true)
            sizeEdit:HookScript("OnShow", function(edit) edit:SetTextColor(1, 1, 1, 1) end)
            sizeEdit:HookScript("OnEditFocusLost", function(edit) edit:SetTextColor(1, 1, 1, 1) end)
        end

        local iconSizeLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        iconSizeLabel:SetText("Icon Size")
        iconSizeLabel:SetJustifyH("LEFT")
        local iconSizeEdit = mkNumeric(scrollChild, function(edit)
            local activeStack = getStack()
            if not activeStack then return end
            local db = activeStack:GetDB()
            local v = tonumber(trim(edit:GetText() or ""))
            db.iconSize = math.floor(math.min(64, math.max(12, v or db.iconSize or 18)))
            applyStackSettings()
            edit:SetText(tostring(db.iconSize))
            edit:SetTextColor(1, 1, 1, 1)
        end)
        setReadableNumericText(iconSizeEdit)
        iconSizeEdit:HookScript("OnShow", function(edit) edit:SetTextColor(1, 1, 1, 1) end)
        iconSizeEdit:HookScript("OnEditFocusLost", function(edit) edit:SetTextColor(1, 1, 1, 1) end)

        local iconOffsetXLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        iconOffsetXLabel:SetText("Icon Offset X")
        iconOffsetXLabel:SetJustifyH("LEFT")
        local iconOffsetXEdit = mkNumeric(scrollChild, function(edit)
            local activeStack = getStack()
            if not activeStack then return end
            local db = activeStack:GetDB()
            local v = tonumber(trim(edit:GetText() or ""))
            if v == nil then
                edit:SetText(tostring(math.floor(tonumber(db.iconOffsetX) or 0)))
                edit:SetTextColor(1, 1, 1, 1)
                return
            end
            local nextValue = math.floor(math.min(50, math.max(-50, v)))
            local currentValue = math.floor(tonumber(db.iconOffsetX) or 0)
            if nextValue ~= currentValue then
                db.iconOffsetX = nextValue
                applyStackSettings()
            end
            local displayValue = math.floor(tonumber(db.iconOffsetX) or currentValue)
            edit:SetText(tostring(displayValue))
            edit:SetTextColor(1, 1, 1, 1)
        end)
        setReadableNumericText(iconOffsetXEdit)
        iconOffsetXEdit:HookScript("OnShow", function(edit) edit:SetTextColor(1, 1, 1, 1) end)
        iconOffsetXEdit:HookScript("OnEditFocusLost", function(edit) edit:SetTextColor(1, 1, 1, 1) end)

        local iconOffsetYLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        iconOffsetYLabel:SetText("Icon Offset Y")
        iconOffsetYLabel:SetJustifyH("LEFT")
        local iconOffsetYEdit = mkNumeric(scrollChild, function(edit)
            local activeStack = getStack()
            if not activeStack then return end
            local db = activeStack:GetDB()
            local v = tonumber(trim(edit:GetText() or ""))
            if v == nil then
                edit:SetText(tostring(math.floor(tonumber(db.iconOffsetY) or 0)))
                edit:SetTextColor(1, 1, 1, 1)
                return
            end
            local nextValue = math.floor(math.min(50, math.max(-50, v)))
            local currentValue = math.floor(tonumber(db.iconOffsetY) or 0)
            if nextValue ~= currentValue then
                db.iconOffsetY = nextValue
                applyStackSettings()
            end
            local displayValue = math.floor(tonumber(db.iconOffsetY) or currentValue)
            edit:SetText(tostring(displayValue))
            edit:SetTextColor(1, 1, 1, 1)
        end)
        setReadableNumericText(iconOffsetYEdit)
        iconOffsetYEdit:HookScript("OnShow", function(edit) edit:SetTextColor(1, 1, 1, 1) end)
        iconOffsetYEdit:HookScript("OnEditFocusLost", function(edit) edit:SetTextColor(1, 1, 1, 1) end)

        local iconOffsetPairLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        iconOffsetPairLabel:SetText("Icon Offset")
        iconOffsetPairLabel:SetJustifyH("LEFT")
        local iconOffsetAxisXMini = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        iconOffsetAxisXMini:SetText("X")
        iconOffsetAxisXMini:SetTextColor(0.76, 0.76, 0.78, 0.92)
        iconOffsetAxisXMini:SetJustifyH("LEFT")
        local iconOffsetAxisYMini = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        iconOffsetAxisYMini:SetText("Y")
        iconOffsetAxisYMini:SetTextColor(0.76, 0.76, 0.78, 0.92)
        iconOffsetAxisYMini:SetJustifyH("LEFT")
        local fontRowContainer = CreateFrame("Frame", nil, scrollChild)
        local iconOffsetRowContainer = CreateFrame("Frame", nil, scrollChild)

        local iconEdgeLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        iconEdgeLabel:SetText("Icon Edge")
        iconEdgeLabel:SetJustifyH("LEFT")
        local iconEdgeControl = createPremiumSegmentedChoice(
            scrollChild,
            "",
            nil,
            {
                { label = "Sharp", value = "Sharp (Zoomed)" },
                { label = "Square", value = "Square (Full)" },
            },
            function()
                applyStackSettings()
            end,
            {
                semantic = "selection",
                controlHeight = 22,
                textSize = 11,
                segmentGap = 0,
                segmentMinWidth = TIMERS_LAYOUT.ICON_EDGE_SEGMENT_MIN_W,
                textEllipsis = true,
                getValue = function()
                    local activeStack = getStack()
                    local db = activeStack and activeStack:GetDB() or nil
                    local value = trim(tostring(db and db.iconEdgeStyle or "Sharp (Zoomed)"))
                    if value ~= "Sharp (Zoomed)" and value ~= "Square (Full)" then
                        return "Sharp (Zoomed)"
                    end
                    return value
                end,
                setValue = function(v)
                    local activeStack = getStack()
                    if not activeStack then
                        return
                    end
                    local db = activeStack:GetDB()
                    local value = trim(tostring(v or "Sharp (Zoomed)"))
                    if value ~= "Square (Full)" then
                        value = "Sharp (Zoomed)"
                    end
                    db.iconEdgeStyle = value
                end,
            }
        )
        if iconEdgeControl and iconEdgeControl.label then
            iconEdgeControl.label:SetText("")
            iconEdgeControl.label:Hide()
        end

        local aspectChoices = {
            { label = "1:1 (Default)", value = "1:1" },
            { label = "16:9 (Wide)", value = "16:9" },
            { label = "4:3", value = "4:3" },
            { label = "3:4", value = "3:4" },
            { label = "9:16 (Tall)", value = "9:16" },
            { label = "2:1", value = "2:1" },
            { label = "1:2", value = "1:2" },
        }
        local aspectLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        aspectLabel:SetText("Aspect Ratio")
        aspectLabel:SetJustifyH("LEFT")
        local aspectDropdown = mkPickerButton(scrollChild, {
            width = TIMERS_LAYOUT.ASPECT_PICKER_W,
            title = "Select Icon Aspect Ratio",
            searchHint = "Search aspect ratios",
            pickerWidth = 360,
            pickerHeight = 300,
            noSearch = true,
            hideTitle = true,
            hideScrollBar = true,
            optionsProvider = function()
                return aspectChoices
            end,
            getter = function()
                local activeStack = getStack()
                return activeStack and activeStack:GetDB().iconAspect or "1:1"
            end,
            setter = function(v)
                local activeStack = getStack()
                if activeStack then
                    activeStack:GetDB().iconAspect = trim(v or "1:1")
                end
            end,
            onApply = function()
                applyStackSettings()
            end,
        })

        local brezEnable = mkCheck(scrollChild, "Battle Rez Timer", "brezEnabled")
        local lustEnable = mkCheck(scrollChild, "Bloodlust Timer", "lustEnabled")
        local healerEnable = mkCheck(scrollChild, "Healer Status", "healerEnabled")
        local cooldownSweepEnable = mkCheck(scrollChild, "Cooldown Sweep", "cooldownSweepEnabled")
        local enableLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        enableLabel:SetText("Enable")
        local divider = scrollChild:CreateTexture(nil, "ARTWORK")
        divider:SetColorTexture(1, 1, 1, 0.15)
        local dividerFont = scrollChild:CreateTexture(nil, "ARTWORK")
        dividerFont:SetColorTexture(1, 1, 1, 0.15)
        local TIMER_HELPER_R, TIMER_HELPER_G, TIMER_HELPER_B, TIMER_HELPER_A = 0.58, 0.58, 0.58, 0.92
        local function applyHelperTone(fs)
            if fs and fs.SetTextColor then
                fs:SetTextColor(TIMER_HELPER_R, TIMER_HELPER_G, TIMER_HELPER_B, TIMER_HELPER_A)
            end
        end
        local function setTimerSingleLineEllipsis(fs, fullText, maxWidth)
            if not fs then
                return
            end
            local text = tostring(fullText or "")
            fs:SetWordWrap(false)
            if fs.SetMaxLines then
                fs:SetMaxLines(1)
            end
            if maxWidth and maxWidth > 0 then
                fs:SetWidth(maxWidth)
            end
            fs:SetText(text)
            if not maxWidth or maxWidth <= 0 or not fs.GetStringWidth then
                return
            end
            if fs:GetStringWidth() <= maxWidth then
                return
            end
            local suffix = "..."
            local low, high = 0, #text
            local best = suffix
            while low <= high do
                local mid = math.floor((low + high) / 2)
                local candidate = text:sub(1, mid) .. suffix
                fs:SetText(candidate)
                if fs:GetStringWidth() <= maxWidth then
                    best = candidate
                    low = mid + 1
                else
                    high = mid - 1
                end
            end
            fs:SetText(best)
        end


        local function parkTimersControl(control)
            if not control then
                return
            end
            if control.Hide then
                control:Hide()
            end
            control:ClearAllPoints()
            control:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", TIMERS_LAYOUT.HIDDEN_X, TIMERS_LAYOUT.HIDDEN_Y)
        end

        local function showTimersControl(control)
            if control and control.Show then
                control:Show()
            end
        end

        local function rememberTimersText(fs, text)
            if not fs then
                return
            end
            if text == nil then
                text = (fs.GetText and fs:GetText()) or ""
            end
            fs._paTimersRawText = tostring(text or "")
        end

        local function setTimersText(fs, text)
            if not fs then
                return
            end
            local value = tostring(text or "")
            fs._paTimersRawText = value
            fs:SetText(value)
        end

        local function getTimersText(fs)
            if not fs then
                return ""
            end
            local raw = fs._paTimersRawText
            if raw == nil then
                raw = (fs.GetText and fs:GetText()) or ""
                fs._paTimersRawText = tostring(raw or "")
            end
            return tostring(raw or "")
        end

        local function isTimersTextActive(fs)
            return trim(getTimersText(fs)) ~= ""
        end

        local function applyTimersSingleLine(fs, width)
            if not fs then
                return
            end
            local clampedWidth = math.max(1, math.floor(tonumber(width) or 0))
            setTimerSingleLineEllipsis(fs, getTimersText(fs), clampedWidth)
        end

        local function measureTimersSingleLineHeight(fs, width, floorValue, isActive)
            if not fs or isActive == false then
                return 0
            end
            applyTimersSingleLine(fs, width)
            return math.max(
                math.floor(tonumber(floorValue) or 0),
                math.ceil(tonumber((fs.GetStringHeight and fs:GetStringHeight()) or 0) or 0)
            )
        end

        local function measureTimersSingleLineWidth(fs, floorValue, isActive)
            if not fs or isActive == false then
                return 0
            end
            local raw = getTimersText(fs)
            fs:SetWordWrap(false)
            if fs.SetMaxLines then
                fs:SetMaxLines(1)
            end
            fs:SetWidth(TIMERS_LAYOUT.MEASURE_SINGLE_LINE_W)
            fs:SetText(raw)
            return math.max(
                math.floor(tonumber(floorValue) or 0),
                math.ceil(tonumber((fs.GetStringWidth and fs:GetStringWidth()) or 0) or 0)
            )
        end

        local function computeTimersLockRhythm(labelHeight)
            local T = TIMERS_LAYOUT
            local measuredLabelH = math.max(1, tonumber(labelHeight) or 0)
            local helperGap = math.max(1, math.floor((measuredLabelH * T.LOCK_HELPER_GAP_RATIO) + 0.5))
            local dividerGap = math.max(1, math.floor((measuredLabelH * T.LOCK_DIVIDER_GAP_RATIO) + 0.5))
            local dividerOffset = math.max(1, math.floor((dividerGap * T.LOCK_DIVIDER_OFFSET_RATIO) + 0.5))
            return helperGap, dividerGap, dividerOffset
        end
        local function measureTimersWrappedTextHeight(fs, width, floorValue, isActive)
            if not fs or isActive == false then
                return 0
            end
            local clampedWidth = math.max(1, math.floor(tonumber(width) or 0))
            fs:SetWidth(clampedWidth)
            fs:SetText(getTimersText(fs))
            return math.max(
                math.floor(tonumber(floorValue) or 0),
                math.ceil(tonumber((fs.GetStringHeight and fs:GetStringHeight()) or 0) or 0)
            )
        end

        local function measureTimersControlHeight(control, floorValue, isActive)
            if not control or isActive == false then
                return 0
            end
            return math.max(
                math.floor(tonumber(floorValue) or 0),
                math.ceil(tonumber((control.GetHeight and control:GetHeight()) or 0) or 0)
            )
        end

        local function measureTimersButtonLabelWidth(button)
            if not button or not button.Text or not button.Text.GetStringWidth then
                return 0
            end
            return math.ceil(tonumber(button.Text:GetStringWidth() or 0) or 0)
        end

        local function computeTimersSegmentWidth(spec, preferredWidth, availableWidth, perButtonPad, minWidth)
            local widestText = 0
            if spec and spec.offBtn then
                widestText = math.max(widestText, measureTimersButtonLabelWidth(spec.offBtn))
            end
            if spec and spec.onBtn then
                widestText = math.max(widestText, measureTimersButtonLabelWidth(spec.onBtn))
            end
            widestText = math.max(widestText, 36)
            local pad = math.max(0, tonumber(perButtonPad) or 0)
            local desiredWidth = ((widestText + (pad * 2)) * 2) + 4
            local preferred = math.max(math.floor(tonumber(minWidth) or 0), math.floor(tonumber(preferredWidth) or desiredWidth))
            local maxWidth = math.max(math.floor(tonumber(minWidth) or 0), math.floor(tonumber(availableWidth) or 0))
            return math.max(math.floor(tonumber(minWidth) or 0), math.min(maxWidth, math.max(desiredWidth, preferred)))
        end

        local function computeTimersActionButtonWidth(button, preferredWidth, availableWidth, minWidth)
            local desiredWidth = measureTimersButtonLabelWidth(button) + (TIMERS_LAYOUT.ACTION_BUTTON_TEXT_PAD_X * 2)
            local preferred = math.max(math.floor(tonumber(minWidth) or 0), math.floor(tonumber(preferredWidth) or desiredWidth))
            local maxWidth = math.max(math.floor(tonumber(minWidth) or 0), math.floor(tonumber(availableWidth) or 0))
            return math.max(math.floor(tonumber(minWidth) or 0), math.min(maxWidth, math.max(desiredWidth, preferred)))
        end

        local function computeTimersGeometry(contentW)
            local T = TIMERS_LAYOUT
            local G = {}
            G.contentW = math.max(math.floor(tonumber(contentW) or 0), T.MIN_CONTENT_W)
            G.contentLeft = T.CONTENT_LEFT
            G.contentRight = G.contentW - T.CONTENT_RIGHT
            G.contentSpan = math.max(1, G.contentRight - G.contentLeft)
            G.labelColX = G.contentLeft
            G.toggleColX = T.TOGGLE_COL_X
            G.helperColX = G.labelColX
            G.settingsLabelX = G.labelColX
            G.settingsControlX = G.toggleColX
            G.appearanceControlX = G.settingsControlX + T.APPEAR_CONTROL_SHIFT_X
            return G
        end

        local function computeTimersLockRowGeometry(G, lockRowRef, resetButton)
            local T = TIMERS_LAYOUT
            local L = {}
            local labelWidth = measureTimersSingleLineWidth(lockRowRef and lockRowRef.label or nil, 0, lockRowRef and lockRowRef.label ~= nil)
            L.labelX = G.labelColX
            L.labelW = math.max(1, labelWidth)
            L.controlX = L.labelX + L.labelW + T.LABEL_TO_CONTROL_GAP
            L.resetH = T.CONTROL_FLOOR
            L.resetW = T.RESET_BUTTON_PREF_W
            local toggleAvailW = math.max(T.LOCK_TOGGLE_MIN_W, G.contentRight - L.controlX - T.LOCK_TOGGLE_TO_RESET_GAP - L.resetW)
            L.controlW = computeTimersSegmentWidth(lockRowRef, T.LOCK_TOGGLE_PREF_W, toggleAvailW, T.SEGMENT_BUTTON_TEXT_PAD_X, T.LOCK_TOGGLE_MIN_W)
            L.resetX = L.controlX + L.controlW + T.LOCK_TOGGLE_TO_RESET_GAP
            L.rowW = math.max(1, G.contentRight - G.labelColX)
            return L
        end

        local function computeTimersModuleGeometry(G, sampleRow)
            local T = TIMERS_LAYOUT
            local M = {}
            M.labelX = G.labelColX
            M.labelW = math.max(1, G.toggleColX - G.labelColX - T.LABEL_TO_CONTROL_GAP)
            M.controlX = G.toggleColX
            M.helperX = G.helperColX
            M.helperW = math.max(1, G.contentRight - G.helperColX)
            local toggleAvailW = math.max(0, G.contentRight - M.controlX)
            M.controlW = computeTimersSegmentWidth(sampleRow, T.MODULE_TOGGLE_PREF_W, toggleAvailW, T.SEGMENT_BUTTON_TEXT_PAD_X, T.MIN_SEGMENT_W)
            return M
        end

        local function computeTimersBatchCardGeometry(G, batchScopeRef, batchEnableRef, batchDisableRef)
            local T = TIMERS_LAYOUT
            local B = {}
            B.cardX = G.labelColX
            B.cardW = G.contentSpan
            B.innerW = math.max(1, B.cardW - (T.CARD_PADDING * 2))
            local scopeText = getTimersText(batchScopeRef)
            if trim(scopeText) ~= "" then
                batchScopeRef:SetText(scopeText)
                B.scopeW = math.min(B.innerW, math.ceil(tonumber((batchScopeRef.GetStringWidth and batchScopeRef:GetStringWidth()) or 0) or 0))
            else
                B.scopeW = 0
            end
            B.scopeX = T.CARD_PADDING + math.max(0, B.innerW - B.scopeW)
            B.titleW = math.max(1, B.innerW - B.scopeW - ((B.scopeW > 0) and T.BATCH_SCOPE_GAP or 0))
            local perButtonAvailW = math.max(T.BATCH_BUTTON_MIN_W, math.floor((B.innerW - T.BATCH_BUTTON_GAP) / 2))
            local desiredButtonW = math.max(
                computeTimersActionButtonWidth(batchEnableRef, T.BATCH_BUTTON_PREF_W, perButtonAvailW, T.BATCH_BUTTON_MIN_W),
                computeTimersActionButtonWidth(batchDisableRef, T.BATCH_BUTTON_PREF_W, perButtonAvailW, T.BATCH_BUTTON_MIN_W)
            )
            B.buttonW = math.max(T.BATCH_BUTTON_MIN_W, math.min(perButtonAvailW, desiredButtonW))
            if ((B.buttonW * 2) + T.BATCH_BUTTON_GAP) > B.innerW then
                B.buttonW = math.max(T.BATCH_BUTTON_COMPRESS_MIN_W, math.floor((B.innerW - T.BATCH_BUTTON_GAP) / 2))
            end
            B.buttonsLeft = T.CARD_PADDING + math.max(0, B.innerW - ((B.buttonW * 2) + T.BATCH_BUTTON_GAP))
            B.enableX = B.buttonsLeft
            B.disableX = B.enableX + B.buttonW + T.BATCH_BUTTON_GAP
            B.statusW = B.innerW
            return B
        end

        local function computeTimersAppearanceGeometry(G, axisXMini, axisYMini)
            local T = TIMERS_LAYOUT
            local A = {}
            A.labelX = G.settingsLabelX
            A.labelW = math.max(1, G.appearanceControlX - G.settingsLabelX - T.LABEL_TO_CONTROL_GAP)
            A.controlX = G.appearanceControlX
            A.controlAvailW = math.max(0, G.contentRight - A.controlX)
            if A.controlAvailW >= T.MAIN_CONTROL_MIN_W then
                A.mainControlW = math.min(T.MAIN_CONTROL_TARGET_W, A.controlAvailW)
            else
                A.mainControlW = A.controlAvailW
            end
            A.valueColX = A.controlX + A.mainControlW
            A.rowContainerW = math.max(1, G.contentRight - G.settingsLabelX)
            A.fontPickerW = math.max(0, A.mainControlW - T.FONT_SIZE_W - T.FONT_SIZE_GAP)
            A.fontDropSizeBelow = (A.fontPickerW < T.MIN_PICKER_W)
            if A.fontDropSizeBelow then
                A.fontPickerW = A.mainControlW
            end
            A.fontSizeW = T.FONT_SIZE_W
            A.fontSizeX = A.controlX + (A.fontDropSizeBelow and 0 or (A.fontPickerW + T.FONT_SIZE_GAP))
            local axisTextW = math.max(
                math.ceil(tonumber((axisXMini and axisXMini.GetStringWidth and axisXMini:GetStringWidth()) or 0) or 0),
                math.ceil(tonumber((axisYMini and axisYMini.GetStringWidth and axisYMini:GetStringWidth()) or 0) or 0)
            )
            A.axisLabelW = math.max(T.AXIS_LABEL_MIN_W, axisTextW)
            A.offsetSliderX = A.controlX + A.axisLabelW + T.AXIS_TO_CONTROL_GAP
            A.offsetSliderW = math.max(0, A.valueColX - A.offsetSliderX)
            return A
        end

        local brezExplain = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        brezExplain:SetText("|cffffb347[Mythic+ Only]|r Battle Rez Timer shows charges and MM:SS recharge while charges recover.")
        brezExplain:SetJustifyH("LEFT")
        applyHelperTone(brezExplain)
        local lustExplain = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        lustExplain:SetText("Bloodlust Timer shows local Active/Sated plus party Ready or Next Lust.")
        lustExplain:SetJustifyH("LEFT")
        applyHelperTone(lustExplain)
        local healerExplain = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        healerExplain:SetText("Healer Status shows party healer state: |cff33ff33OK|r, |cffff3333OFFLINE|r, |cffff3333DEAD|r, |cffffd100OUTSIDE|r.")
        healerExplain:SetJustifyH("LEFT")
        applyHelperTone(healerExplain)
        local cooldownSweepExplain = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        cooldownSweepExplain:SetText("Shows a radial cooldown animation over the timer icons while a countdown is running.")
        cooldownSweepExplain:SetJustifyH("LEFT")
        applyHelperTone(cooldownSweepExplain)
        local brezStatus = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        brezStatus:SetText("")
        brezStatus:SetJustifyH("LEFT")
        brezStatus:SetWordWrap(false)
        applyHelperTone(brezStatus)
        local lustStatus = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        lustStatus:SetText("")
        lustStatus:SetJustifyH("LEFT")
        lustStatus:SetWordWrap(false)
        applyHelperTone(lustStatus)
        local healerStatus = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        healerStatus:SetText("")
        healerStatus:SetJustifyH("LEFT")
        healerStatus:SetWordWrap(false)
        applyHelperTone(healerStatus)
        local cooldownSweepStatus = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        cooldownSweepStatus:SetText("")
        cooldownSweepStatus:SetJustifyH("LEFT")
        cooldownSweepStatus:SetWordWrap(false)
        applyHelperTone(cooldownSweepStatus)

        local lockRowContainer = CreateFrame("Frame", nil, scrollChild)
        lockRowContainer:SetSize(1, TIMERS_LAYOUT.LOCK_ROW_SEED_H)

        local coordsLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        coordsLabel:SetText("Coordinates")
        coordsLabel:SetJustifyH("LEFT")
        local function normalizeTimersCoordsEdit(edit)
            if not edit then
                return
            end
            edit:SetJustifyH("CENTER")
            if edit.HasFocus and edit:HasFocus() then
                edit:SetTextColor(1, 1, 1, 1)
                edit:SetAlpha(1)
            else
                edit:SetTextColor(0.86, 0.86, 0.88, 1)
                edit:SetAlpha(0.90)
            end
            if edit.SetCursorPosition and not (edit.HasFocus and edit:HasFocus()) then
                edit:SetCursorPosition(0)
            end
            if edit.HighlightText and not (edit.HasFocus and edit:HasFocus()) then
                edit:HighlightText(0, 0)
            end
        end
        local function setTimersCoordsDisplay(edit, x, y)
            if not edit then
                return
            end
            edit:SetText(string.format("%d,%d", math.floor(tonumber(x) or 0), math.floor(tonumber(y) or 0)))
            normalizeTimersCoordsEdit(edit)
        end
        local function placeTimersCoordsCursorAtEnd(edit)
            if not edit or not edit.SetCursorPosition then
                return
            end
            edit:SetCursorPosition(string.len(tostring(edit:GetText() or "")))
        end
        local function queueTimersCoordsCursorAtEnd(edit)
            local function applyIfFocused()
                if edit and edit.HasFocus and edit:HasFocus() then
                    placeTimersCoordsCursorAtEnd(edit)
                end
            end
            applyIfFocused()
            if C_Timer and C_Timer.After then
                C_Timer.After(0, applyIfFocused)
                C_Timer.After(0.02, applyIfFocused)
            end
        end
        local coords = mkNumeric(scrollChild, function(edit)
            local activeStack = getStack()
            if not activeStack then return end
            local db = activeStack:GetDB()
            local text = trim(edit:GetText() or "")
            local xText, yText = text:match("^([%+%-]?%d+)%s*,%s*([%+%-]?%d+)$")
            if xText and yText then
                db.x = math.floor(tonumber(xText) or db.x or 0)
                db.y = math.floor(tonumber(yText) or db.y or 0)
                if not InCombatLockdown or not InCombatLockdown() then activeStack:ApplySettings() end
            end
            setTimersCoordsDisplay(edit, db.x or 0, db.y or 0)
        end)
        coords:SetTextColor(0.86, 0.86, 0.88, 1)
        coords:SetAlpha(0.90)
        coords:SetNumeric(false)
        setReadableNumericText(coords)
        coords:HookScript("OnEditFocusGained", function(edit)
            edit:SetJustifyH("CENTER")
            normalizeTimersCoordsEdit(edit)
            queueTimersCoordsCursorAtEnd(edit)
        end)
        coords:HookScript("OnMouseUp", function(edit)
            queueTimersCoordsCursorAtEnd(edit)
        end)
        coords:HookScript("OnShow", function(edit) normalizeTimersCoordsEdit(edit) end)
        coords:HookScript("OnEditFocusLost", function(edit) normalizeTimersCoordsEdit(edit) end)

        local resetAnchorButton = createActionButton(scrollChild, "Reset Anchor", function()
            local activeStack = getStack()
            if not activeStack then return end
            if activeStack.Initialize and not (activeStack.frame or activeStack.mainFrame) then
                activeStack:Initialize()
            end
            if activeStack.SetUnlocked then
                activeStack:SetUnlocked(true)
            end

            if activeStack.ResetPositionToCenter then
                activeStack:ResetPositionToCenter()
            else
                local db = activeStack:GetDB()
                db.x = 0
                db.y = 0
                if activeStack.ApplyPosition then
                    activeStack:ApplyPosition()
                end
                if activeStack.EvaluateVisibility then
                    activeStack:EvaluateVisibility("reset-anchor-fallback")
                elseif activeStack.Tick then
                    activeStack:Tick()
                end
            end

            if activeStack.frame then
                activeStack.frame:SetFrameStrata("HIGH")
                activeStack.frame:Raise()
            end

            if self._refresh then
                self._refresh()
            end
        end, TIMERS_LAYOUT.RESET_BUTTON_SEED_W)

        styleSecondaryActionButtonShared(resetAnchorButton, {
            baseBg = { 0.06, 0.07, 0.09, 0.95 },
            hoverBg = { 0.08, 0.09, 0.11, 0.95 },
            pressedBg = { 0.05, 0.06, 0.08, 0.96 },
            baseBorder = { 0.21, 0.24, 0.28, 0.62 },
            hoverBorder = { 0.25, 0.28, 0.33, 0.68 },
            pressedBorder = { 0.23, 0.26, 0.30, 0.66 },
            textColor = { 0.82, 0.83, 0.86, 1 },
        })
        local function createTimersToggleRow(parent, labelText, opts)
            opts = type(opts) == "table" and opts or {}
            local semantic = tostring(opts.semantic or "toggle")
            local onChanged = type(opts.onChanged) == "function" and opts.onChanged or nil
            local rowValue = false

            local row = createPremiumSegmentedChoice(parent, labelText, nil, {
                { label = tostring(opts.offLabel or "Off"), value = false, toggleState = "off" },
                { label = tostring(opts.onLabel or "On"), value = true, toggleState = "on" },
            }, function(selectedValue)
                local nextValue = PA_SafeBool(selectedValue)
                rowValue = nextValue
                if onChanged then
                    onChanged(nextValue)
                end
            end, {
                semantic = (semantic == "meta") and "selection" or "toggle",
                selectionVariant = (semantic == "meta") and "lock_meta" or "",
                textEllipsis = true,
                normalizeValue = function(v)
                    return PA_SafeBool(v)
                end,
                getValue = function()
                    return rowValue
                end,
                setValue = function(v)
                    rowValue = PA_SafeBool(v)
                end,
            })

            row.value = false
            row.enabled = true
            if row.label then
                row.label:SetJustifyH("LEFT")
            end
            row.offBtn = row.buttons and row.buttons[1] or nil
            row.onBtn = row.buttons and row.buttons[2] or nil

            local baseSetEnabled = row.SetEnabled
            row.SetEnabled = function(self, enabled)
                self.enabled = enabled and true or false
                if baseSetEnabled then
                    baseSetEnabled(self, self.enabled)
                end
            end

            local baseLayout = row.Layout
            row.Layout = function(self, width)
                if baseLayout then
                    baseLayout(self, math.max(TIMERS_LAYOUT.MIN_SEGMENT_W, tonumber(width) or TIMERS_LAYOUT.LOCK_TOGGLE_PREF_W))
                end
            end

            if row.offBtn then
                row.offBtn:SetScript("OnClick", function()
                    if not row.enabled or not rowValue then
                        return
                    end
                    row:SetSelectedValue(false, true)
                end)
            end
            if row.onBtn then
                row.onBtn:SetScript("OnClick", function()
                    if not row.enabled or rowValue then
                        return
                    end
                    row:SetSelectedValue(true, true)
                end)
            end

            row.SetValue = function(self, v, trigger)
                local nextValue = PA_SafeBool(v)
                rowValue = nextValue
                self.value = nextValue
                self:SetVisualSelectedValue(nextValue)
                if trigger and onChanged then
                    onChanged(nextValue)
                end
            end
            row.GetValue = function()
                return rowValue
            end

            row:SetValue(false, false)
            return row
        end

        local function createTimersPremiumSlider(parent, labelText, minV, maxV, stepV, onApplyValue)
            local spec = {}
            local sliderMin = tonumber(minV) or 0
            local sliderMax = tonumber(maxV) or 100
            if sliderMax < sliderMin then
                sliderMin, sliderMax = sliderMax, sliderMin
            end
            local stepValue = tonumber(stepV) or 1
            if stepValue <= 0 then
                stepValue = 1
            end

            spec.label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
            spec.label:SetText(labelText or "")
            spec.label:SetJustifyH("LEFT")
            spec.control = CreateFrame("Frame", nil, parent)
            spec.control:SetHeight(TIMERS_LAYOUT.CONTROL_FLOOR)
            spec.control:SetWidth(TIMERS_LAYOUT.SLIDER_CONTROL_W)

            local valueButton = CreateFrame("Button", nil, spec.control)
            valueButton:SetSize(TIMERS_LAYOUT.SLIDER_VALUE_BUTTON_W, TIMERS_LAYOUT.SLIDER_VALUE_BUTTON_H)
            valueButton:SetPoint("RIGHT", spec.control, "RIGHT", 0, 0)

            local valueText = createStyledFontString(valueButton, "ARTWORK", "GameFontHighlightSmall", 11)
            valueText:SetPoint("RIGHT", valueButton, "RIGHT", 0, 0)
            valueText:SetJustifyH("RIGHT")
            valueText:SetTextColor(0.76, 0.76, 0.78, 1)

            local valueEdit = CreateFrame("EditBox", nil, valueButton)
            valueEdit:SetAllPoints(valueButton)
            valueEdit:SetAutoFocus(false)
            valueEdit:SetJustifyH("RIGHT")
            valueEdit:SetTextInsets(0, 0, 0, 0)
            valueEdit:SetTextColor(1, 1, 1, 1)
            valueEdit:SetHighlightColor(1, 1, 1, 0.25)
            valueEdit:SetNumeric(false)
            applyGlobalFontToObject(valueEdit, 11)
            valueEdit:Hide()

            spec.slider = CreateFrame("Slider", nil, spec.control)
            spec.slider:SetPoint("TOPLEFT", spec.control, "TOPLEFT", 0, 0)
            spec.slider:SetPoint("BOTTOMRIGHT", valueButton, "BOTTOMLEFT", -TIMERS_LAYOUT.SLIDER_VALUE_GAP, 0)
            spec.slider:SetMinMaxValues(sliderMin, sliderMax)
            spec.slider:SetValueStep(stepValue)
            if spec.slider.SetObeyStepOnDrag then
                spec.slider:SetObeyStepOnDrag(true)
            end
            spec.slider:SetThumbTexture("Interface\\Buttons\\WHITE8x8")
            local inputThumb = spec.slider:GetThumbTexture()
            if inputThumb then
                inputThumb:SetSize(16, 16)
                inputThumb:SetVertexColor(1, 1, 1, 0.01)
            end
            spec.slider:EnableMouse(true)
            spec.slider:SetOrientation("HORIZONTAL")

            local trackBg = spec.slider:CreateTexture(nil, "BACKGROUND")
            trackBg:SetTexture("Interface\\Buttons\\WHITE8x8")
            trackBg:SetPoint("LEFT", spec.slider, "LEFT", 0, 0)
            trackBg:SetPoint("RIGHT", spec.slider, "RIGHT", 0, 0)
            trackBg:SetHeight(2)
            trackBg:SetVertexColor(0.18, 0.18, 0.19, 0.95)

            local trackActive = spec.slider:CreateTexture(nil, "ARTWORK")
            trackActive:SetTexture("Interface\\Buttons\\WHITE8x8")
            trackActive:SetPoint("LEFT", spec.slider, "LEFT", 0, 0)
            trackActive:SetHeight(2)
            trackActive:SetWidth(0)
            trackActive:SetVertexColor(1.0, 0.82, 0.0, 0.75)

            local thumb = spec.slider:CreateTexture(nil, "OVERLAY")
            thumb:SetTexture("Interface\\Buttons\\WHITE8x8")
            thumb:SetSize(8, 8)
            thumb:SetVertexColor(1.0, 0.84, 0.08, 0.98)
            if thumb.SetMask then
                thumb:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask")
            end

            local thumbGlow = spec.slider:CreateTexture(nil, "ARTWORK")
            thumbGlow:SetTexture("Interface\\Buttons\\WHITE8x8")
            thumbGlow:SetSize(14, 14)
            thumbGlow:SetVertexColor(1.0, 0.82, 0.0, 0)
            if thumbGlow.SetMask then
                thumbGlow:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask")
            end
            thumbGlow:SetBlendMode("ADD")

            local suppress = false
            local controlEnabled = true
            local currentValue = nil
            local dragging = false
            local hovering = false
            local editingValue = false
            local dragLeft = nil
            local dragRight = nil
            local dragScale = nil
            local lastDragCursorX = nil

            local function resetDragTracking()
                dragLeft = nil
                dragRight = nil
                dragScale = nil
                lastDragCursorX = nil
            end

            local function captureDragBounds()
                dragLeft = spec.slider:GetLeft()
                dragRight = spec.slider:GetRight()
                dragScale = spec.slider:GetEffectiveScale() or 1
                lastDragCursorX = nil
                if not dragLeft or not dragRight or dragRight <= dragLeft or dragScale <= 0 then
                    resetDragTracking()
                end
            end

            local function normalize(n)
                local v = tonumber(n) or sliderMin
                if v < sliderMin then v = sliderMin end
                if v > sliderMax then v = sliderMax end
                v = sliderMin + (math.floor(((v - sliderMin) / stepValue) + 0.5) * stepValue)
                if v < sliderMin then v = sliderMin end
                if v > sliderMax then v = sliderMax end
                return math.floor(v + 0.5)
            end

            local function applyVisualState()
                local minVNow, maxVNow = spec.slider:GetMinMaxValues()
                local value = normalize(spec.slider:GetValue())
                local span = math.max(0.0001, (maxVNow - minVNow))
                local pct = (value - minVNow) / span
                if pct < 0 then pct = 0 end
                if pct > 1 then pct = 1 end
                local widthNow = spec.slider:GetWidth() or 0
                local x = pct * widthNow

                thumb:ClearAllPoints()
                thumb:SetPoint("CENTER", spec.slider, "LEFT", x, 0)
                thumbGlow:ClearAllPoints()
                thumbGlow:SetPoint("CENTER", thumb, "CENTER", 0, 0)

                trackActive:ClearAllPoints()
                trackActive:SetPoint("LEFT", spec.slider, "LEFT", 0, 0)
                trackActive:SetPoint("RIGHT", thumb, "CENTER", 0, 0)

                local glowAlpha = 0
                if not controlEnabled then
                    trackActive:SetVertexColor(0.48, 0.48, 0.50, 0.35)
                    thumb:SetVertexColor(0.62, 0.62, 0.64, 0.65)
                elseif dragging then
                    glowAlpha = 0.34
                    trackActive:SetVertexColor(1.0, 0.86, 0.16, 0.9)
                    thumb:SetVertexColor(1.0, 0.9, 0.22, 1)
                elseif hovering then
                    glowAlpha = 0.22
                    trackActive:SetVertexColor(1.0, 0.85, 0.12, 0.85)
                    thumb:SetVertexColor(1.0, 0.88, 0.18, 1)
                else
                    trackActive:SetVertexColor(1.0, 0.82, 0.0, 0.75)
                    thumb:SetVertexColor(1.0, 0.84, 0.08, 0.98)
                end
                thumbGlow:SetVertexColor(1.0, 0.82, 0.0, glowAlpha)
                spec.label:SetAlpha(controlEnabled and 1 or 0.55)
                spec.control:SetAlpha(controlEnabled and 1 or 0.55)
            end

            local function setValueVisualOnly(v, keepCurrentValue)
                local n = normalize(v)
                if not keepCurrentValue then
                    currentValue = n
                end
                suppress = true
                spec.slider:SetValue(n)
                suppress = false
                valueText:SetText(tostring(n))
                if valueEdit:IsShown() then
                    valueEdit:SetText(tostring(n))
                end
                applyVisualState()
            end

            local function applyValue(v)
                local n = normalize(v)
                if currentValue == n then
                    valueText:SetText(tostring(n))
                    applyVisualState()
                    return
                end
                currentValue = n
                valueText:SetText(tostring(n))
                if valueEdit:IsShown() then
                    valueEdit:SetText(tostring(n))
                end
                if onApplyValue then
                    onApplyValue(n)
                end
                applyVisualState()
            end

            local function beginEdit()
                editingValue = true
                valueText:Hide()
                valueEdit:SetText(tostring(normalize(currentValue or spec.slider:GetValue())))
                valueEdit:Show()
                valueEdit:SetFocus()
                valueEdit:HighlightText()
            end

            local function endEdit(commit)
                if not editingValue then
                    return
                end
                editingValue = false
                if commit then
                    local parsed = tonumber(trim(valueEdit:GetText() or ""))
                    if parsed ~= nil then
                        local n = normalize(parsed)
                        setValueVisualOnly(n, true)
                        applyValue(n)
                    else
                        setValueVisualOnly(currentValue or spec.slider:GetValue())
                    end
                end
                valueEdit:Hide()
                valueText:Show()
                valueEdit:ClearFocus()
                valueText:SetText(tostring(normalize(currentValue or spec.slider:GetValue())))
            end

            local function setValueFromCursor()
                local left = (dragging and dragLeft) or spec.slider:GetLeft()
                local right = (dragging and dragRight) or spec.slider:GetRight()
                if not left or not right or right <= left then
                    return
                end
                local cx = GetCursorPosition()
                local scale = (dragging and dragScale) or (spec.slider:GetEffectiveScale() or 1)
                if not cx or scale <= 0 then
                    return
                end
                cx = cx / scale
                if dragging and lastDragCursorX ~= nil and math.abs(cx - lastDragCursorX) < 0.25 then
                    return
                end
                if dragging then
                    lastDragCursorX = cx
                end
                local pct = (cx - left) / (right - left)
                if pct < 0 then pct = 0 end
                if pct > 1 then pct = 1 end
                local raw = sliderMin + ((sliderMax - sliderMin) * pct)
                local n = normalize(raw)
                if currentValue == n then
                    applyVisualState()
                    return
                end
                setValueVisualOnly(n, true)
                applyValue(n)
            end

            spec.slider:SetScript("OnValueChanged", function(selfSlider, value)
                local n = normalize(value)
                if selfSlider:GetValue() ~= n then
                    suppress = true
                    selfSlider:SetValue(n)
                    suppress = false
                end
                valueText:SetText(tostring(n))
                applyVisualState()
                if suppress or isControlHydrating(selfSlider) then
                    return
                end
                applyValue(n)
            end)
            spec.slider:SetScript("OnMouseDown", function()
                if not controlEnabled then
                    return
                end
                dragging = true
                captureDragBounds()
                setValueFromCursor()
                spec.slider:SetScript("OnUpdate", function()
                    if dragging then
                        setValueFromCursor()
                    end
                end)
                applyVisualState()
            end)
            spec.slider:SetScript("OnMouseUp", function()
                dragging = false
                resetDragTracking()
                spec.slider:SetScript("OnUpdate", nil)
                applyVisualState()
            end)
            spec.slider:SetScript("OnEnter", function()
                if not controlEnabled then
                    return
                end
                hovering = true
                applyVisualState()
            end)
            spec.slider:SetScript("OnLeave", function()
                hovering = false
                dragging = false
                resetDragTracking()
                spec.slider:SetScript("OnUpdate", nil)
                applyVisualState()
            end)

            valueButton:SetScript("OnClick", function()
                if not controlEnabled then
                    return
                end
                beginEdit()
            end)
            valueEdit:SetScript("OnEnterPressed", function(edit)
                endEdit(true)
                edit:ClearFocus()
            end)
            valueEdit:SetScript("OnEscapePressed", function(edit)
                endEdit(false)
                edit:ClearFocus()
            end)
            valueEdit:SetScript("OnEditFocusLost", function()
                endEdit(true)
            end)

            function spec:SetVisualValue(v)
                setValueVisualOnly(v)
            end
            function spec:Refresh(v)
                setValueVisualOnly(v)
            end
            function spec:IsInteracting()
                return dragging or editingValue
            end
            function spec:SetWidth(newWidth)
                local fullW = math.max(0, math.floor(tonumber(newWidth) or TIMERS_LAYOUT.SLIDER_CONTROL_W))
                self.control:SetWidth(fullW)
                applyVisualState()
            end
            function spec:SetEnabled(enabled)
                controlEnabled = enabled and true or false
                if not controlEnabled then
                    dragging = false
                    hovering = false
                    endEdit(false)
                    resetDragTracking()
                    spec.slider:SetScript("OnUpdate", nil)
                end
                spec.slider:EnableMouse(controlEnabled)
                valueButton:EnableMouse(controlEnabled)
                valueEdit:EnableMouse(controlEnabled)
                applyVisualState()
            end
            spec.control:SetScript("OnSizeChanged", function()
                applyVisualState()
            end)

            spec.valueButton = valueButton
            spec.valueText = valueText
            spec.valueEdit = valueEdit
            setValueVisualOnly(sliderMin)
            return spec
        end

        local lockRow = createTimersToggleRow(scrollChild, "Lock Position", {
            semantic = "meta",
            offLabel = "Unlocked",
            onLabel = "Locked",
            onChanged = function(locked)
                widgets.unlock:SetChecked(locked and true or false)
                local clickHandler = widgets.unlock:GetScript("OnClick")
                if clickHandler then
                    clickHandler(widgets.unlock)
                end
            end,
        })
        local masterRowContainer = CreateFrame("Frame", nil, scrollChild)
        masterRowContainer:SetSize(1, TIMERS_LAYOUT.LOCK_ROW_SEED_H)
        local masterEnabledRow = createTimersToggleRow(scrollChild, "Module", {
            semantic = "toggle",
            offLabel = "Off",
            onLabel = "On",
            onChanged = function(enabled)
                local activeStack, db = getTimersDBSnapshot()
                writeTimerSetting(db, "enabled", PA_SafeBool(enabled))
                if activeStack and activeStack.ApplySettings then
                    applyStackSettings()
                end
                if self._refresh then
                    self._refresh()
                end
            end,
        })
        self._settingsWindowHeaderToggleSource = masterEnabledRow
        local modulesHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        modulesHeader:SetText("Modules")
        modulesHeader:SetJustifyH("LEFT")
        local appearanceLayoutHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        appearanceLayoutHeader:SetText("Appearance & Layout")
        appearanceLayoutHeader:SetJustifyH("LEFT")
        local SECTION_HEADER_R, SECTION_HEADER_G, SECTION_HEADER_B, SECTION_HEADER_A = 1, 0.82, 0, 1
        modulesHeader:SetTextColor(SECTION_HEADER_R, SECTION_HEADER_G, SECTION_HEADER_B, SECTION_HEADER_A)
        appearanceLayoutHeader:SetTextColor(SECTION_HEADER_R, SECTION_HEADER_G, SECTION_HEADER_B, SECTION_HEADER_A)
        local lockStateHelper = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        lockStateHelper:SetText("")
        applyHelperTone(lockStateHelper)
        lockStateHelper:SetWordWrap(false)
        lockStateHelper:SetJustifyH("LEFT")
        local clearBatchStatusFeedback = function() end

        local function commitModuleToggle(moduleId, dbKey, value)
            clearBatchStatusFeedback()
            local available = isModuleAvailable(moduleId)
            if not available then
                return
            end
            local activeStack, db = getTimersDBSnapshot()
            writeTimerSetting(db, dbKey, PA_SafeBool(value))
            if activeStack and activeStack.ApplySettings then
                applyStackSettings()
            end
            if self._refresh then
                self._refresh()
            end
        end

        local brezRow = createTimersToggleRow(scrollChild, "Battle Rez Timer", {
            semantic = "toggle",
            onChanged = function(v)
                commitModuleToggle("brez", "brezEnabled", v)
            end,
        })
        local lustRow = createTimersToggleRow(scrollChild, "Bloodlust Timer", {
            semantic = "toggle",
            onChanged = function(v)
                commitModuleToggle("lust", "lustEnabled", v)
            end,
        })
        local lustSoundRow = createTimersToggleRow(scrollChild, "Play sound when Sated ends", {
            semantic = "toggle",
            onChanged = function(v)
                clearBatchStatusFeedback()
                local activeStack, db = getTimersDBSnapshot()
                writeTimerSetting(db, "lustSatedEndSound", PA_SafeBool(v))
                if activeStack and activeStack.ApplySettings then
                    applyStackSettings()
                end
                if self._refresh then
                    self._refresh()
                end
            end,
        })
        local healerRow = createTimersToggleRow(scrollChild, "Healer Status", {
            semantic = "toggle",
            onChanged = function(v)
                commitModuleToggle("healer", "healerEnabled", v)
            end,
        })
        local cooldownSweepRow = createTimersToggleRow(scrollChild, "Cooldown Sweep", {
            semantic = "toggle",
            onChanged = function(v)
                commitModuleToggle("cooldownSweep", "cooldownSweepEnabled", v)
            end,
        })
        local BATCH_STATUS_BASELINE_TEXT = "Applies to available modules only."
        local BATCH_STATUS_NONE_AVAILABLE_TEXT = "No available modules."
        local batchStatusMode = "baseline"
        local batchStatusFeedbackText = ""
        local batchAvailableCount = 0
        local batchStatusMaxWidth = 0
        local applyBatchModules = nil

        local batchActionsCard = CreateFrame("Frame", nil, scrollChild, "BackdropTemplate")
        batchActionsCard:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
            insets = { left = 0, right = 0, top = 0, bottom = 0 },
        })
        batchActionsCard:SetBackdropColor(0.06, 0.07, 0.09, 0.42)
        batchActionsCard:SetBackdropBorderColor(0.20, 0.23, 0.29, 0.50)

        local batchActionsTitle = createStyledFontString(batchActionsCard, "ARTWORK", "GameFontHighlight", 12)
        batchActionsTitle:SetText("Batch Actions")
        batchActionsTitle:SetTextColor(1, 0.82, 0, 1)
        batchActionsTitle:SetJustifyH("LEFT")

        local batchActionsScope = createStyledFontString(batchActionsCard, "ARTWORK", "GameFontHighlightSmall", 10)
        batchActionsScope:SetText("")
        batchActionsScope:SetJustifyH("LEFT")
        applyHelperTone(batchActionsScope)
        batchActionsScope:SetWordWrap(false)
        if batchActionsScope.SetMaxLines then
            batchActionsScope:SetMaxLines(1)
        end

        local batchEnableButton = createActionButton(batchActionsCard, "Enable all modules", function()
            clearBatchStatusFeedback()
            local changedCount = applyBatchModules and applyBatchModules(true) or 0
            batchStatusMode = "feedback"
            batchStatusFeedbackText = string.format("Enabled %d modules.", math.max(0, changedCount))
            if self._refresh then
                self._refresh()
            end
        end, 156)
        local batchDisableButton = createActionButton(batchActionsCard, "Disable all modules", function()
            clearBatchStatusFeedback()
            local changedCount = applyBatchModules and applyBatchModules(false) or 0
            batchStatusMode = "feedback"
            batchStatusFeedbackText = string.format("Disabled %d modules.", math.max(0, changedCount))
            if self._refresh then
                self._refresh()
            end
        end, 156)
        local batchButtonStyle = {
            baseBg = { 0.06, 0.07, 0.09, 0.95 },
            hoverBg = { 0.08, 0.09, 0.11, 0.95 },
            pressedBg = { 0.05, 0.06, 0.08, 0.96 },
            baseBorder = { 0.21, 0.24, 0.28, 0.62 },
            hoverBorder = { 0.25, 0.28, 0.33, 0.68 },
            pressedBorder = { 0.23, 0.26, 0.30, 0.66 },
            textColor = { 0.82, 0.83, 0.86, 1 },
        }
        styleSecondaryActionButtonShared(batchEnableButton, batchButtonStyle)
        styleSecondaryActionButtonShared(batchDisableButton, batchButtonStyle)

        local batchStatus = createStyledFontString(batchActionsCard, "ARTWORK", "GameFontHighlightSmall", 10)
        batchStatus:SetText(BATCH_STATUS_BASELINE_TEXT)
        batchStatus:SetJustifyH("LEFT")
        batchStatus:SetWordWrap(false)
        if batchStatus.SetMaxLines then
            batchStatus:SetMaxLines(1)
        end
        applyHelperTone(batchStatus)

        local function resolveBatchStatusText()
            if batchAvailableCount <= 0 then
                return BATCH_STATUS_NONE_AVAILABLE_TEXT
            end
            if batchStatusMode == "feedback" and batchStatusFeedbackText ~= "" then
                return batchStatusFeedbackText
            end
            return BATCH_STATUS_BASELINE_TEXT
        end

        local function refreshBatchStatusLine()
            local text = resolveBatchStatusText()
            setTimersText(batchStatus, text)
            if batchStatusMaxWidth and batchStatusMaxWidth > 0 then
                setTimerSingleLineEllipsis(batchStatus, text, batchStatusMaxWidth)
            else
                batchStatus:SetText(text)
            end
        end

        clearBatchStatusFeedback = function()
            if batchStatusMode ~= "baseline" or batchStatusFeedbackText ~= "" then
                batchStatusMode = "baseline"
                batchStatusFeedbackText = ""
                refreshBatchStatusLine()
            end
        end

        local moduleRows = {
            {
                id = "brez",
                key = "brezEnabled",
                check = brezEnable,
                row = brezRow,
                unavailableHelper = brezStatus,
                explainers = { brezExplain },
            },
            {
                id = "lust",
                key = "lustEnabled",
                check = lustEnable,
                row = lustRow,
                unavailableHelper = lustStatus,
                explainBeforeChildren = true,
                explainBlockGap = 6,
                explainers = { lustExplain },
            },
            {
                id = "lustSound",
                key = "lustSatedEndSound",
                row = lustSoundRow,
                excludeFromBatch = true,
                visibilityOverride = function(db)
                    return PA_SafeBool(readTimerSetting(db, "lustEnabled", true))
                end,
            },
            {
                id = "healer",
                key = "healerEnabled",
                check = healerEnable,
                row = healerRow,
                unavailableHelper = healerStatus,
                explainers = { healerExplain },
            },
            {
                id = "cooldownSweep",
                key = "cooldownSweepEnabled",
                check = cooldownSweepEnable,
                row = cooldownSweepRow,
                unavailableHelper = cooldownSweepStatus,
                explainers = { cooldownSweepExplain },
            },
        }
        for i = 1, #moduleRows do
            local row = moduleRows[i]
            if row and row.row then
                local extraRefs = {}
                if frameIsAlive(row.unavailableHelper) then
                    extraRefs[#extraRefs + 1] = row.unavailableHelper
                end
                if type(row.explainers) == "table" then
                    for j = 1, #row.explainers do
                        if frameIsAlive(row.explainers[j]) then
                            extraRefs[#extraRefs + 1] = row.explainers[j]
                        end
                    end
                end
                if #extraRefs > 0 then
                    settingsSearchRuntime.attachExtraSearchRefs(row.row, extraRefs)
                end
            end
        end

        local staticTimersTextFields = {
            header,
            modulesHeader,
            appearanceLayoutHeader,
            batchActionsTitle,
            batchActionsScope,
            batchStatus,
            lockRow and lockRow.label or nil,
            brezRow and brezRow.label or nil,
            lustRow and lustRow.label or nil,
            lustSoundRow and lustSoundRow.label or nil,
            healerRow and healerRow.label or nil,
            cooldownSweepRow and cooldownSweepRow.label or nil,
            brezExplain,
            lustExplain,
            healerExplain,
            cooldownSweepExplain,
            fontLabel,
            coordsLabel,
            iconSizeSlider and iconSizeSlider.label or nil,
            iconOffsetPairLabel,
            iconOffsetAxisXMini,
            iconOffsetAxisYMini,
            iconEdgeLabel,
            aspectLabel,
        }
        for _, fs in ipairs(staticTimersTextFields) do
            rememberTimersText(fs)
        end

        for _, module in ipairs(moduleRows) do
            if module and module.row and module.row.control and module.row.control.HookScript then
                module.row.control:HookScript("OnMouseDown", function()
                    clearBatchStatusFeedback()
                end)
            end
        end

        applyBatchModules = function(desiredEnabled)
            local activeStack, db = getTimersDBSnapshot()
            if not db then
                return 0
            end
            local targetValue = PA_SafeBool(desiredEnabled)
            local changedCount = 0
            for _, module in ipairs(moduleRows) do
                if not module.excludeFromBatch then
                local available = isModuleAvailable(module.id)
                if available then
                    local currentValue = PA_SafeBool(readTimerSetting(db, module.key, true))
                    if currentValue ~= targetValue then
                        writeTimerSetting(db, module.key, targetValue)
                        changedCount = changedCount + 1
                    end
                end
                end
            end
            if changedCount > 0 and activeStack and activeStack.ApplySettings then
                applyStackSettings()
            end
            return changedCount
        end

        local iconSizeSlider = createTimersPremiumSlider(scrollChild, "Icon Size", 12, 64, 1, function(v)
            local activeStack = getStack()
            if not activeStack then return end
            local db = activeStack:GetDB()
            db.iconSize = math.floor(math.min(64, math.max(12, tonumber(v) or db.iconSize or 18)))
            applyStackSettings()
        end)
        local iconOffsetXSlider = createTimersPremiumSlider(scrollChild, "Icon Offset X", -50, 50, 1, function(v)
            local activeStack = getStack()
            if not activeStack then return end
            local db = activeStack:GetDB()
            db.iconOffsetX = math.floor(math.min(50, math.max(-50, tonumber(v) or db.iconOffsetX or 0)))
            applyStackSettings()
        end)
        local iconOffsetYSlider = createTimersPremiumSlider(scrollChild, "Icon Offset Y", -50, 50, 1, function(v)
            local activeStack = getStack()
            if not activeStack then return end
            local db = activeStack:GetDB()
            db.iconOffsetY = math.floor(math.min(50, math.max(-50, tonumber(v) or db.iconOffsetY or 0)))
            applyStackSettings()
        end)

        local function syncModuleVisuals(db)
            local availableCount = 0
            for _, module in ipairs(moduleRows) do
                local visibilityOverride = module.visibilityOverride
                local isVisible = (type(visibilityOverride) ~= "function") or visibilityOverride(db)
                local available, unavailableReason = isModuleAvailable(module.id)
                if visibilityOverride then
                    available = available and isVisible
                    if not isVisible then
                        unavailableReason = nil
                    end
                end
                local defaultValue = (module.key == "lustSatedEndSound") and false or true
                local moduleValue = PA_SafeBool(readTimerSetting(db, module.key, defaultValue))
                if module.check then
                    module.check:SetChecked(moduleValue)
                    if available then
                        module.check:Enable()
                        if module.check.text then
                            module.check.text:SetTextColor(1, 0.82, 0, 1)
                        end
                    else
                        module.check:Disable()
                        if module.check.text then
                            module.check.text:SetTextColor(0.6, 0.6, 0.6, 1)
                        end
                    end
                end
                if module.row then
                    module.row:SetEnabled(available)
                    module.row:SetValue(moduleValue, false)
                end
                if module.unavailableHelper then
                    setTimersText(module.unavailableHelper, available and "" or tostring(unavailableReason or "Unavailable"))
                end
                if module.row and visibilityOverride and not isVisible then
                    parkTimersControl(module.row.label)
                    parkTimersControl(module.row.control)
                end
                for _, child in ipairs(module.childRows or {}) do
                    local childValue = PA_SafeBool(readTimerSetting(db, child.key, false))
                    local childEnabled = available and (not child.isVisible or child.isVisible(db))
                    if child.row then
                        child.row:SetEnabled(childEnabled)
                        child.row:SetValue(childValue, false)
                    end
                end
                if available and not module.excludeFromBatch then
                    availableCount = availableCount + 1
                end
            end
            batchAvailableCount = availableCount
            local hasAvailable = availableCount > 0
            if batchEnableButton then
                batchEnableButton:SetEnabled(hasAvailable)
                batchEnableButton:SetAlpha(hasAvailable and 1 or 0.55)
            end
            if batchDisableButton then
                batchDisableButton:SetEnabled(hasAvailable)
                batchDisableButton:SetAlpha(hasAvailable and 1 or 0.55)
            end
            refreshBatchStatusLine()
        end

        local function syncLockStateHelperText(isLocked, moduleEnabled)
            if not lockStateHelper then
                return
            end
            if not moduleEnabled then
                setTimersText(lockStateHelper, "Timers are disabled. Re-enable to edit settings.")
            elseif isLocked then
                setTimersText(lockStateHelper, "Timers are locked.")
            else
                setTimersText(lockStateHelper, "Timers are unlocked - drag to reposition.")
            end
        end

        local function applyTimersModuleEnabledState(moduleEnabled)
            setSettingsControlEnabled(widgets.unlock, moduleEnabled)
            if lockRow then
                lockRow:SetEnabled(moduleEnabled)
            end
            setSettingsControlEnabled(resetAnchorButton, moduleEnabled)

            for _, module in ipairs(moduleRows) do
                if module and module.row and not moduleEnabled then
                    module.row:SetEnabled(false)
                end
                for _, child in ipairs(module and module.childRows or {}) do
                    if child and child.row and not moduleEnabled then
                        child.row:SetEnabled(false)
                    end
                end
            end

            if not moduleEnabled then
                if batchEnableButton then
                    batchEnableButton:SetEnabled(false)
                    batchEnableButton:SetAlpha(0.55)
                end
                if batchDisableButton then
                    batchDisableButton:SetEnabled(false)
                    batchDisableButton:SetAlpha(0.55)
                end
            end

            setSettingsControlEnabled(fontDropdown, moduleEnabled)
            setSettingsControlEnabled(aspectDropdown, moduleEnabled)
            setSettingsControlEnabled(iconEdgeControl, moduleEnabled)
            setSettingsControlEnabled(sizeStepper or sizeEdit, moduleEnabled)
            setSettingsControlEnabled(coords, moduleEnabled)
            setSettingsControlEnabled(iconSizeSlider, moduleEnabled)
            setSettingsControlEnabled(iconOffsetXSlider, moduleEnabled)
            setSettingsControlEnabled(iconOffsetYSlider, moduleEnabled)

            if lockRowContainer and lockRowContainer.SetAlpha then
                lockRowContainer:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if batchActionsCard and batchActionsCard.SetAlpha then
                batchActionsCard:SetAlpha(moduleEnabled and 1 or 0.55)
            end

            for _, textWidget in ipairs({
                modulesHeader,
                appearanceLayoutHeader,
                batchActionsTitle,
                batchActionsScope,
                batchStatus,
                fontLabel,
                coordsLabel,
                iconEdgeLabel,
                aspectLabel,
                iconOffsetPairLabel,
                iconOffsetAxisXMini,
                iconOffsetAxisYMini,
                brezExplain,
                lustExplain,
                healerExplain,
                cooldownSweepExplain,
            }) do
                setSettingsTextEnabled(textWidget, moduleEnabled)
            end
        end

        local function refresh()
            local activeStack, db = getTimersDBSnapshot()
            local isLocked = getTimersLockedState()
            local moduleEnabled = PA_SafeBool(readTimerSetting(db, "enabled", true))
            widgets.unlock:SetChecked(isLocked)
            updateUnlockLabelColor(isLocked)
            if masterEnabledRow then
                masterEnabledRow:SetValue(moduleEnabled, false)
            end
            if lockRow then
                lockRow:SetValue(isLocked, false)
            end
            syncLockStateHelperText(isLocked, moduleEnabled)

            syncModuleVisuals(db)
            local fontSizeValue = math.floor(tonumber(readTimerSetting(db, "fontSize", 12)) or 12)
            local iconSizeValue = math.floor(tonumber(readTimerSetting(db, "iconSize", 18)) or 18)
            local iconOffsetXValue = math.floor(tonumber(readTimerSetting(db, "iconOffsetX", 0)) or 0)
            local iconOffsetYValue = math.floor(tonumber(readTimerSetting(db, "iconOffsetY", 0)) or 0)
            if fontDropdown.Refresh then fontDropdown.Refresh() end
            if iconEdgeControl and iconEdgeControl.Refresh then iconEdgeControl:Refresh() end
            if aspectDropdown.Refresh then aspectDropdown.Refresh() end
            if sizeStepper and sizeStepper.SetVisualValue then
                local fontSizeEditing = sizeStepper.valueEdit and sizeStepper.valueEdit.IsShown and sizeStepper.valueEdit:IsShown()
                if not fontSizeEditing then
                    sizeStepper:SetVisualValue(fontSizeValue)
                end
            elseif sizeEdit and not sizeEdit:HasFocus() then
                sizeEdit:SetText(tostring(fontSizeValue))
            end
            if not iconSizeEdit:HasFocus() then iconSizeEdit:SetText(tostring(iconSizeValue)) end
            if not iconOffsetXEdit:HasFocus() then iconOffsetXEdit:SetText(tostring(iconOffsetXValue)) end
            if not iconOffsetYEdit:HasFocus() then iconOffsetYEdit:SetText(tostring(iconOffsetYValue)) end
            local liveX, liveY = getTimersDisplayPosition(activeStack, db)
            if not coords:HasFocus() then setTimersCoordsDisplay(coords, liveX, liveY) else normalizeTimersCoordsEdit(coords) end
            if iconSizeSlider and (not iconSizeSlider.IsInteracting or not iconSizeSlider:IsInteracting()) then
                iconSizeSlider:Refresh(iconSizeValue)
            end
            if iconOffsetXSlider and (not iconOffsetXSlider.IsInteracting or not iconOffsetXSlider:IsInteracting()) then
                iconOffsetXSlider:Refresh(iconOffsetXValue)
            end
            if iconOffsetYSlider and (not iconOffsetYSlider.IsInteracting or not iconOffsetYSlider:IsInteracting()) then
                iconOffsetYSlider:Refresh(iconOffsetYValue)
            end
            applyTimersModuleEnabledState(moduleEnabled)
            if self._layout then self._layout() end
            refreshSettingsWindowHeaderAccessoryIfHosted(self)
        end
        local function syncTimersLiveFields()
            local activeStack, db = getTimersDBSnapshot()
            local isLocked = getTimersLockedState()
            local moduleEnabled = PA_SafeBool(readTimerSetting(db, "enabled", true))
            widgets.unlock:SetChecked(isLocked)
            updateUnlockLabelColor(isLocked)
            syncModuleVisuals(db)
            if masterEnabledRow then
                masterEnabledRow:SetValue(moduleEnabled, false)
            end
            if lockRow then
                lockRow:SetValue(isLocked, false)
            end
            syncLockStateHelperText(isLocked, moduleEnabled)

            local fontSizeValue = math.floor(tonumber(readTimerSetting(db, "fontSize", 12)) or 12)
            local iconSizeValue = math.floor(tonumber(readTimerSetting(db, "iconSize", 18)) or 18)
            local iconOffsetXValue = math.floor(tonumber(readTimerSetting(db, "iconOffsetX", 0)) or 0)
            local iconOffsetYValue = math.floor(tonumber(readTimerSetting(db, "iconOffsetY", 0)) or 0)
            if sizeStepper and sizeStepper.SetVisualValue then
                local fontSizeEditing = sizeStepper.valueEdit and sizeStepper.valueEdit.IsShown and sizeStepper.valueEdit:IsShown()
                if not fontSizeEditing then
                    sizeStepper:SetVisualValue(fontSizeValue)
                end
            elseif sizeEdit and not sizeEdit:HasFocus() then
                sizeEdit:SetText(tostring(fontSizeValue))
            end
            if not iconSizeEdit:HasFocus() then iconSizeEdit:SetText(tostring(iconSizeValue)) end
            if not iconOffsetXEdit:HasFocus() then iconOffsetXEdit:SetText(tostring(iconOffsetXValue)) end
            if not iconOffsetYEdit:HasFocus() then iconOffsetYEdit:SetText(tostring(iconOffsetYValue)) end
            local liveX, liveY = getTimersDisplayPosition(activeStack, db)
            if not coords:HasFocus() then setTimersCoordsDisplay(coords, liveX, liveY) else normalizeTimersCoordsEdit(coords) end
            if iconSizeSlider and (not iconSizeSlider.IsInteracting or not iconSizeSlider:IsInteracting()) then
                iconSizeSlider:SetVisualValue(iconSizeValue)
            end
            if iconOffsetXSlider and (not iconOffsetXSlider.IsInteracting or not iconOffsetXSlider:IsInteracting()) then
                iconOffsetXSlider:SetVisualValue(iconOffsetXValue)
            end
            if iconOffsetYSlider and (not iconOffsetYSlider.IsInteracting or not iconOffsetYSlider:IsInteracting()) then
                iconOffsetYSlider:SetVisualValue(iconOffsetYValue)
            end
            applyTimersModuleEnabledState(moduleEnabled)
        end

        self._refresh = refresh
        self._syncTimersLiveFields = syncTimersLiveFields

        local timersLayoutRefs = {
            widgetsUnlock = widgets.unlock,
            brezEnable = brezEnable,
            lustEnable = lustEnable,
            healerEnable = healerEnable,
            cooldownSweepEnable = cooldownSweepEnable,
            enableLabel = enableLabel,
            sizeLabel = sizeLabel,
            iconSizeLabel = iconSizeLabel,
            iconOffsetXLabel = iconOffsetXLabel,
            iconOffsetYLabel = iconOffsetYLabel,
            iconSizeEdit = iconSizeEdit,
            iconOffsetXEdit = iconOffsetXEdit,
            iconOffsetYEdit = iconOffsetYEdit,
            header = header,
            masterRow = masterEnabledRow,
            masterRowContainer = masterRowContainer,
            lockRow = lockRow,
            lockRowContainer = lockRowContainer,
            resetAnchorButton = resetAnchorButton,
            lockStateHelper = lockStateHelper,
            divider = divider,
            modulesHeader = modulesHeader,
            batchActionsCard = batchActionsCard,
            batchActionsTitle = batchActionsTitle,
            batchActionsScope = batchActionsScope,
            batchEnableButton = batchEnableButton,
            batchDisableButton = batchDisableButton,
            batchStatus = batchStatus,
            dividerFont = dividerFont,
            appearanceLayoutHeader = appearanceLayoutHeader,
            fontDropdown = fontDropdown,
            aspectDropdown = aspectDropdown,
            iconEdgeControl = iconEdgeControl,
            sizeStepper = sizeStepper,
            sizeEdit = sizeEdit,
            coords = coords,
            coordsLabel = coordsLabel,
            fontRowContainer = fontRowContainer,
            fontLabel = fontLabel,
            iconSizeSlider = iconSizeSlider,
            iconOffsetXSlider = iconOffsetXSlider,
            iconOffsetYSlider = iconOffsetYSlider,
            lustSoundRow = lustSoundRow,
            cooldownSweepRow = cooldownSweepRow,
            iconOffsetPairLabel = iconOffsetPairLabel,
            iconOffsetAxisXMini = iconOffsetAxisXMini,
            iconOffsetAxisYMini = iconOffsetAxisYMini,
            iconOffsetRowContainer = iconOffsetRowContainer,
            iconEdgeLabel = iconEdgeLabel,
            aspectLabel = aspectLabel,
        }

        local function layout()
            local R = timersLayoutRefs
            local T = TIMERS_LAYOUT
            local _, layoutDb = getTimersDBSnapshot()
            local contentW = math.max((scrollFrame:GetWidth() or 0) - 8, T.MIN_CONTENT_W)
            local useHostedChrome = isPanelUsingCustomSettingsWindowHost(self)
            local G = computeTimersGeometry(contentW)
            local lockG = computeTimersLockRowGeometry(G, R.lockRow, R.resetAnchorButton)
            local moduleG = computeTimersModuleGeometry(G, R.cooldownSweepRow or R.lockRow)
            local batchG = computeTimersBatchCardGeometry(G, R.batchActionsScope, R.batchEnableButton, R.batchDisableButton)
            local appearanceG = computeTimersAppearanceGeometry(G, R.iconOffsetAxisXMini, R.iconOffsetAxisYMini)
            scrollChild:SetWidth(G.contentW)

            for _, control in ipairs({
                R.header,
                R.masterRowContainer,
                R.masterRow and R.masterRow.label or nil,
                R.masterRow and R.masterRow.control or nil,
                R.lockRowContainer,
                R.lockRow and R.lockRow.label or nil,
                R.lockRow and R.lockRow.control or nil,
                R.resetAnchorButton,
                R.lockStateHelper,
                R.divider,
                R.modulesHeader,
                R.batchActionsCard,
                R.batchActionsTitle,
                R.batchActionsScope,
                R.batchEnableButton,
                R.batchDisableButton,
                R.batchStatus,
                R.dividerFont,
                R.appearanceLayoutHeader,
                R.fontRowContainer,
                R.fontLabel,
                R.fontDropdown and R.fontDropdown.control or nil,
                (R.sizeStepper and R.sizeStepper.control) or R.sizeEdit,
                R.coordsLabel,
                R.coords,
                R.iconSizeSlider and R.iconSizeSlider.label or nil,
                R.iconSizeSlider and R.iconSizeSlider.control or nil,
                R.iconOffsetRowContainer,
                R.iconOffsetPairLabel,
                R.iconOffsetAxisXMini,
                R.iconOffsetXSlider and R.iconOffsetXSlider.control or nil,
                R.iconOffsetAxisYMini,
                R.iconOffsetYSlider and R.iconOffsetYSlider.control or nil,
                R.iconEdgeLabel,
                R.iconEdgeControl and R.iconEdgeControl.control or nil,
                R.aspectLabel,
                R.aspectDropdown and R.aspectDropdown.control or nil,
            }) do
                showTimersControl(control)
            end
            for _, module in ipairs(moduleRows) do
                if module and module.row then
                    showTimersControl(module.row.label)
                    showTimersControl(module.row.control)
                end
                for _, child in ipairs(module and module.childRows or {}) do
                    if child and child.row then
                        showTimersControl(child.row.label)
                        showTimersControl(child.row.control)
                    end
                end
                showTimersControl(module and module.unavailableHelper or nil)
                for _, fs in ipairs(module and module.explainers or {}) do
                    showTimersControl(fs)
                end
            end

            local function setPickerWidth(picker, width)
                local w = math.max(0, math.floor(tonumber(width) or 0))
                if picker and picker.SetWidth then
                    picker:SetWidth(w)
                elseif picker and picker.control then
                    picker.control:SetWidth(w)
                end
            end

            parkTimersControl(R.widgetsUnlock)
            parkTimersControl(R.brezEnable)
            parkTimersControl(R.lustEnable)
            parkTimersControl(R.healerEnable)
            parkTimersControl(R.cooldownSweepEnable)
            parkTimersControl(R.enableLabel)
            parkTimersControl(R.sizeLabel)
            parkTimersControl(R.iconSizeLabel)
            parkTimersControl(R.iconOffsetXLabel)
            parkTimersControl(R.iconOffsetYLabel)
            parkTimersControl(R.iconSizeEdit)
            parkTimersControl(R.iconOffsetXEdit)
            parkTimersControl(R.iconOffsetYEdit)

            local y = -T.TOP_PAD
            if useHostedChrome then
                y = y - SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE
            end

            if useHostedChrome then
                parkTimersControl(R.header)
                parkTimersControl(headerDescriptor)
                parkTimersControl(R.masterRowContainer)
                parkTimersControl(R.masterRow and R.masterRow.label or nil)
                parkTimersControl(R.masterRow and R.masterRow.control or nil)
            else
                showTimersControl(R.header)
                showTimersControl(headerDescriptor)
                showTimersControl(R.masterRowContainer)
                showTimersControl(R.masterRow and R.masterRow.label or nil)
                showTimersControl(R.masterRow and R.masterRow.control or nil)
                R.header:ClearAllPoints()
                R.header:SetWidth(math.max(1, G.contentRight - T.HEADER_LEFT))
                R.header:SetWordWrap(false)
                if R.header.SetMaxLines then
                    R.header:SetMaxLines(1)
                end
                R.header:SetText(getTimersText(R.header))
                local headerH = math.max(T.HEADER_FLOOR, math.ceil(tonumber((R.header.GetStringHeight and R.header:GetStringHeight()) or 0) or 0))
                R.header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.HEADER_LEFT, y)
                y = y - headerH - T.HEADER_BOTTOM_GAP
                y = layoutSettingsSectionDescriptor(headerDescriptor, scrollChild, T.HEADER_LEFT, y, math.max(1, G.contentRight - T.HEADER_LEFT))

                R.masterRow:Layout(math.max(T.MODULE_TOGGLE_PREF_W, lockG.controlW))
                local masterLabelH = measureTimersSingleLineHeight(R.masterRow.label, lockG.labelW, T.LABEL_FLOOR, true)
                local masterToggleH = measureTimersControlHeight(R.masterRow.control, T.CONTROL_FLOOR, true)
                local masterRowH = math.max(T.LOCK_ROW_FLOOR or T.CONTROL_FLOOR, masterLabelH, masterToggleH)
                R.masterRowContainer:ClearAllPoints()
                R.masterRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", lockG.labelX, y)
                R.masterRowContainer:SetSize(lockG.rowW, masterRowH)
                R.masterRow.label:ClearAllPoints()
                R.masterRow.label:SetPoint("LEFT", R.masterRowContainer, "LEFT", 0, 0)
                R.masterRow.control:ClearAllPoints()
                R.masterRow.control:SetPoint("LEFT", R.masterRow.label, "RIGHT", T.LABEL_TO_CONTROL_GAP, 0)
                y = y - masterRowH - T.SECTION_HEADER_BOTTOM_GAP
            end

            R.lockRow:Layout(lockG.controlW)
            R.resetAnchorButton:SetSize(lockG.resetW, lockG.resetH)
            local lockLabelH = measureTimersSingleLineHeight(R.lockRow.label, lockG.labelW, T.LABEL_FLOOR, true)
            local lockToggleH = measureTimersControlHeight(R.lockRow.control, T.CONTROL_FLOOR, true)
            local lockRowH = math.max(T.LOCK_ROW_FLOOR or T.CONTROL_FLOOR, lockLabelH, lockToggleH, lockG.resetH)
            local lockHelperGap, lockDividerGap, lockDividerOffset = computeTimersLockRhythm(lockLabelH)

            R.lockRowContainer:ClearAllPoints()
            R.lockRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", lockG.labelX, y)
            R.lockRowContainer:SetSize(lockG.rowW, lockRowH)
            R.lockRow.label:ClearAllPoints()
            R.lockRow.label:SetPoint("LEFT", R.lockRowContainer, "LEFT", 0, 0)
            R.lockRow.control:ClearAllPoints()
            R.lockRow.control:SetPoint("LEFT", R.lockRow.label, "RIGHT", T.LABEL_TO_CONTROL_GAP, 0)
            R.resetAnchorButton:ClearAllPoints()
            R.resetAnchorButton:SetPoint("LEFT", R.lockRow.control, "RIGHT", T.LOCK_TOGGLE_TO_RESET_GAP, 0)
            y = y - lockRowH

            if isTimersTextActive(R.lockStateHelper) then
                local lockHelperH = measureTimersSingleLineHeight(R.lockStateHelper, G.contentSpan, T.HELPER_FLOOR, true)
                y = y - lockHelperGap
                R.lockStateHelper:ClearAllPoints()
                R.lockStateHelper:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", G.labelColX, y)
                y = y - lockHelperH
            else
                parkTimersControl(R.lockStateHelper)
            end

            local dividerY = y - lockDividerOffset
            R.divider:ClearAllPoints()
            R.divider:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", G.labelColX, dividerY)
            R.divider:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", -T.CONTENT_RIGHT, dividerY)
            R.divider:SetHeight(1)
            R.divider:SetColorTexture(0.24, 0.27, 0.32, 0.10)
            y = y - lockDividerGap

            local modulesHeaderH = measureTimersSingleLineHeight(R.modulesHeader, G.contentSpan, T.SECTION_HEADER_FLOOR, true)
            R.modulesHeader:ClearAllPoints()
            R.modulesHeader:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", G.labelColX, y)
            y = y - modulesHeaderH - T.SECTION_HEADER_BOTTOM_GAP

            R.batchEnableButton:SetSize(batchG.buttonW, T.BATCH_BUTTON_H)
            R.batchDisableButton:SetSize(batchG.buttonW, T.BATCH_BUTTON_H)
            batchStatusMaxWidth = batchG.statusW
            local batchTitleH = measureTimersSingleLineHeight(R.batchActionsTitle, batchG.titleW, T.SECTION_HEADER_FLOOR, true)
            local batchScopeActive = isTimersTextActive(R.batchActionsScope)
            local batchScopeH = measureTimersSingleLineHeight(R.batchActionsScope, math.max(1, batchG.scopeW), T.HELPER_FLOOR, batchScopeActive)
            local batchTitleRowH = math.max(batchTitleH, batchScopeH)
            local batchStatusActive = isTimersTextActive(R.batchStatus)
            local batchStatusH = measureTimersSingleLineHeight(R.batchStatus, batchG.statusW, T.HELPER_FLOOR, batchStatusActive)
            local batchStatusGap = batchStatusActive and T.CARD_BUTTONS_TO_STATUS_GAP or 0
            local batchCardH = T.CARD_PADDING + batchTitleRowH + T.CARD_LABEL_TO_BUTTONS_GAP + T.BATCH_BUTTON_H + batchStatusGap + batchStatusH + T.CARD_PADDING
            local batchButtonsTop = T.CARD_PADDING + batchTitleRowH + T.CARD_LABEL_TO_BUTTONS_GAP

            R.batchActionsCard:ClearAllPoints()
            R.batchActionsCard:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", batchG.cardX, y)
            R.batchActionsCard:SetSize(batchG.cardW, batchCardH)
            R.batchActionsTitle:ClearAllPoints()
            R.batchActionsTitle:SetPoint("TOPLEFT", R.batchActionsCard, "TOPLEFT", T.CARD_PADDING, -T.CARD_PADDING)
            if batchScopeActive then
                R.batchActionsScope:ClearAllPoints()
                R.batchActionsScope:SetPoint("TOPLEFT", R.batchActionsCard, "TOPLEFT", batchG.scopeX, -T.CARD_PADDING)
            else
                parkTimersControl(R.batchActionsScope)
            end
            R.batchEnableButton:ClearAllPoints()
            R.batchEnableButton:SetPoint("TOPLEFT", R.batchActionsCard, "TOPLEFT", batchG.enableX, -batchButtonsTop)
            R.batchDisableButton:ClearAllPoints()
            R.batchDisableButton:SetPoint("TOPLEFT", R.batchActionsCard, "TOPLEFT", batchG.disableX, -batchButtonsTop)
            if batchStatusActive then
                R.batchStatus:ClearAllPoints()
                R.batchStatus:SetPoint("TOPLEFT", R.batchActionsCard, "TOPLEFT", T.CARD_PADDING, -(batchButtonsTop + T.BATCH_BUTTON_H + batchStatusGap))
            else
                parkTimersControl(R.batchStatus)
            end
            y = y - batchCardH - T.MODULE_CARD_TO_ROWS_GAP

            local function layoutModuleRow(spec, topY)
                if not spec or not spec.row then
                    return topY
                end
                if type(spec.visibilityOverride) == "function" and not spec.visibilityOverride(layoutDb) then
                    parkTimersControl(spec.row.label)
                    parkTimersControl(spec.row.control)
                    if spec.unavailableHelper then
                        parkTimersControl(spec.unavailableHelper)
                    end
                    for _, fs in ipairs(spec.explainers or {}) do
                        parkTimersControl(fs)
                    end
                    return topY
                end

                spec.row:Layout(moduleG.controlW)
                local labelH = measureTimersSingleLineHeight(spec.row.label, moduleG.labelW, T.LABEL_FLOOR, true)
                local controlH = measureTimersControlHeight(spec.row.control, T.CONTROL_FLOOR, true)
                local rowH = math.max(T.ROW_FLOOR, labelH, controlH)
                local labelTop = math.floor((rowH - labelH) / 2)
                local controlTop = math.floor((rowH - controlH) / 2)

                spec.row.label:ClearAllPoints()
                spec.row.label:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", moduleG.labelX, topY - labelTop)
                spec.row.control:ClearAllPoints()
                spec.row.control:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", moduleG.controlX, topY - controlTop)

                local nextY = topY - rowH

                local function layoutExplainersBlock(startY, gapBefore)
                    local activeExplainers = {}
                    for _, fs in ipairs(spec.explainers or {}) do
                        if isTimersTextActive(fs) then
                            activeExplainers[#activeExplainers + 1] = fs
                        else
                            parkTimersControl(fs)
                        end
                    end
                    if #activeExplainers == 0 then
                        return startY
                    end

                    local nextExplainerY = startY - math.max(0, tonumber(gapBefore) or 0)
                    for idx, fs in ipairs(activeExplainers) do
                        local explainH = measureTimersWrappedTextHeight(fs, moduleG.helperW, T.HELPER_FLOOR, true)
                        fs:ClearAllPoints()
                        fs:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", moduleG.helperX, nextExplainerY)
                        nextExplainerY = nextExplainerY - explainH
                        if idx < #activeExplainers then
                            nextExplainerY = nextExplainerY - T.MODULE_EXPLAIN_LINE_GAP
                        end
                    end

                    return nextExplainerY - math.max(0, tonumber(spec.explainBlockGap) or T.MODULE_EXPLAIN_BLOCK_GAP)
                end

                if spec.explainBeforeChildren then
                    nextY = layoutExplainersBlock(nextY, T.MODULE_ROW_TO_EXPLAIN_GAP)
                end

                local childRowsLaidOut = 0
                for _, child in ipairs(spec.childRows or {}) do
                    local childVisible = child.row and (not child.isVisible or child.isVisible(layoutDb))
                    if childVisible then
                        child.row:Layout(moduleG.controlW)
                        local childLabelW = math.max(1, moduleG.labelW - T.MODULE_CHILD_INDENT)
                        local childLabelH = measureTimersSingleLineHeight(child.row.label, childLabelW, T.LABEL_FLOOR, true)
                        local childControlH = measureTimersControlHeight(child.row.control, T.CONTROL_FLOOR, true)
                        local childRowH = math.max(T.ROW_FLOOR, childLabelH, childControlH)
                        local childLabelTop = math.floor((childRowH - childLabelH) / 2)
                        local childControlTop = math.floor((childRowH - childControlH) / 2)

                        nextY = nextY - T.MODULE_CHILD_ROW_GAP
                        child.row.label:ClearAllPoints()
                        child.row.label:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", moduleG.labelX + T.MODULE_CHILD_INDENT, nextY - childLabelTop)
                        child.row.control:ClearAllPoints()
                        child.row.control:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", moduleG.controlX, nextY - childControlTop)
                        nextY = nextY - childRowH
                        childRowsLaidOut = childRowsLaidOut + 1
                    elseif child.row then
                        parkTimersControl(child.row.label)
                        parkTimersControl(child.row.control)
                    end
                end
                if childRowsLaidOut > 0 then
                    nextY = nextY - T.MODULE_CHILD_ROW_GAP
                end
                local helperActive = isTimersTextActive(spec.unavailableHelper)
                if helperActive then
                    local helperH = measureTimersSingleLineHeight(spec.unavailableHelper, moduleG.helperW, T.HELPER_FLOOR, true)
                    nextY = nextY - T.MODULE_ROW_TO_HELPER_GAP
                    spec.unavailableHelper:ClearAllPoints()
                    spec.unavailableHelper:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", moduleG.helperX, nextY)
                    nextY = nextY - helperH
                elseif spec.unavailableHelper then
                    parkTimersControl(spec.unavailableHelper)
                end

                if not spec.explainBeforeChildren then
                    nextY = layoutExplainersBlock(
                        nextY,
                        helperActive and T.MODULE_HELPER_TO_EXPLAIN_GAP or T.MODULE_ROW_TO_EXPLAIN_GAP
                    )
                end
                return nextY
            end

            for _, module in ipairs(moduleRows) do
                y = layoutModuleRow(module, y)
            end

            R.dividerFont:ClearAllPoints()
            R.dividerFont:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", G.labelColX, y)
            R.dividerFont:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", -T.CONTENT_RIGHT, y)
            R.dividerFont:SetHeight(1)
            R.dividerFont:SetColorTexture(0.24, 0.27, 0.32, 0.58)
            y = y - T.SECTION_TO_NEXT_DIVIDER_GAP

            local appearanceHeaderH = measureTimersSingleLineHeight(R.appearanceLayoutHeader, G.contentSpan, T.SECTION_HEADER_FLOOR, true)
            R.appearanceLayoutHeader:ClearAllPoints()
            R.appearanceLayoutHeader:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", G.labelColX, y)
            y = y - appearanceHeaderH - T.SECTION_HEADER_BOTTOM_GAP

            setPickerWidth(R.fontDropdown, appearanceG.fontPickerW)
            setPickerWidth(R.aspectDropdown, appearanceG.mainControlW)
            if R.iconEdgeControl and R.iconEdgeControl.Layout then
                R.iconEdgeControl:Layout(appearanceG.mainControlW)
            end
            if R.sizeStepper and R.sizeStepper.SetWidth then
                R.sizeStepper:SetWidth(appearanceG.fontSizeW)
            elseif R.sizeEdit then
                R.sizeEdit:SetSize(appearanceG.fontSizeW, T.CONTROL_FLOOR)
            end
            R.iconSizeSlider:SetWidth(appearanceG.mainControlW)
            R.iconOffsetXSlider:SetWidth(appearanceG.offsetSliderW)
            R.iconOffsetYSlider:SetWidth(appearanceG.offsetSliderW)
            R.iconOffsetAxisXMini:SetWidth(appearanceG.axisLabelW)
            R.iconOffsetAxisYMini:SetWidth(appearanceG.axisLabelW)
            R.coords:SetSize(appearanceG.mainControlW, T.CONTROL_FLOOR)

            local fontLabelH = measureTimersSingleLineHeight(R.fontLabel, appearanceG.labelW, T.LABEL_FLOOR, true)
            local fontPickerH = measureTimersControlHeight(R.fontDropdown.control, T.CONTROL_FLOOR, true)
            local fontSizeControl = (R.sizeStepper and R.sizeStepper.control) or R.sizeEdit
            local fontSizeH = measureTimersControlHeight(fontSizeControl, T.CONTROL_FLOOR, fontSizeControl ~= nil)
            local fontStackH = appearanceG.fontDropSizeBelow and (fontPickerH + T.FONT_STACK_GAP + fontSizeH) or math.max(fontPickerH, fontSizeH)
            local fontRowH = math.max(T.ROW_FLOOR, fontLabelH, fontStackH)
            local fontLabelTop = math.floor((fontRowH - fontLabelH) / 2)
            local fontStackTop = appearanceG.fontDropSizeBelow and math.floor((fontRowH - fontStackH) / 2) or 0
            local fontControlTop = appearanceG.fontDropSizeBelow and fontStackTop or math.floor((fontRowH - fontPickerH) / 2)
            local fontSizeTop = appearanceG.fontDropSizeBelow and (fontStackTop + fontPickerH + T.FONT_STACK_GAP) or math.floor((fontRowH - fontSizeH) / 2)

            R.fontRowContainer:ClearAllPoints()
            R.fontRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.labelX, y)
            R.fontRowContainer:SetSize(appearanceG.rowContainerW, fontRowH)
            R.fontLabel:ClearAllPoints()
            R.fontLabel:SetPoint("TOPLEFT", R.fontRowContainer, "TOPLEFT", 0, -fontLabelTop)
            R.fontDropdown.control:ClearAllPoints()
            R.fontDropdown.control:SetPoint("TOPLEFT", R.fontRowContainer, "TOPLEFT", appearanceG.controlX - appearanceG.labelX, -fontControlTop)
            if fontSizeControl then
                fontSizeControl:ClearAllPoints()
                fontSizeControl:SetPoint("TOPLEFT", R.fontRowContainer, "TOPLEFT", appearanceG.fontSizeX - appearanceG.labelX, -fontSizeTop)
            end
            y = y - fontRowH

            local coordsLabelH = measureTimersSingleLineHeight(R.coordsLabel, appearanceG.labelW, T.LABEL_FLOOR, true)
            local coordsH = measureTimersControlHeight(R.coords, T.CONTROL_FLOOR, true)
            local coordsRowH = math.max(T.ROW_FLOOR, coordsLabelH, coordsH)
            local coordsLabelTop = math.floor((coordsRowH - coordsLabelH) / 2)
            local coordsTop = math.floor((coordsRowH - coordsH) / 2)
            R.coordsLabel:ClearAllPoints()
            R.coordsLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.labelX, y - coordsLabelTop)
            R.coords:ClearAllPoints()
            R.coords:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.controlX, y - coordsTop)
            y = y - coordsRowH

            local iconSizeLabelH = measureTimersSingleLineHeight(R.iconSizeSlider.label, appearanceG.labelW, T.LABEL_FLOOR, true)
            local iconSizeControlH = measureTimersControlHeight(R.iconSizeSlider.control, T.CONTROL_FLOOR, true)
            local iconSizeRowH = math.max(T.ROW_FLOOR, iconSizeLabelH, iconSizeControlH)
            local iconSizeLabelTop = math.floor((iconSizeRowH - iconSizeLabelH) / 2)
            local iconSizeControlTop = math.floor((iconSizeRowH - iconSizeControlH) / 2)
            R.iconSizeSlider.label:ClearAllPoints()
            R.iconSizeSlider.label:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.labelX, y - iconSizeLabelTop)
            R.iconSizeSlider.control:ClearAllPoints()
            R.iconSizeSlider.control:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.controlX, y - iconSizeControlTop)
            y = y - iconSizeRowH

            parkTimersControl(R.iconOffsetXSlider.label)
            parkTimersControl(R.iconOffsetYSlider.label)
            local offsetPairLabelH = measureTimersSingleLineHeight(R.iconOffsetPairLabel, appearanceG.labelW, T.LABEL_FLOOR, true)
            local axisXH = measureTimersSingleLineHeight(R.iconOffsetAxisXMini, appearanceG.axisLabelW, T.MINI_LABEL_FLOOR, true)
            local axisYH = measureTimersSingleLineHeight(R.iconOffsetAxisYMini, appearanceG.axisLabelW, T.MINI_LABEL_FLOOR, true)
            local offsetXControlH = measureTimersControlHeight(R.iconOffsetXSlider.control, T.CONTROL_FLOOR, true)
            local offsetYControlH = measureTimersControlHeight(R.iconOffsetYSlider.control, T.CONTROL_FLOOR, true)
            local offsetLine1H = math.max(axisXH, offsetXControlH)
            local offsetLine2H = math.max(axisYH, offsetYControlH)
            local offsetStackH = offsetLine1H + T.AXIS_LINE_GAP + offsetLine2H
            local offsetRowH = math.max(T.OFFSET_ROW_FLOOR, offsetPairLabelH, offsetStackH)
            local offsetLabelTop = math.floor((offsetRowH - offsetPairLabelH) / 2)
            local offsetStackTop = math.floor((offsetRowH - offsetStackH) / 2)
            local offsetLine2Top = offsetStackTop + offsetLine1H + T.AXIS_LINE_GAP

            R.iconOffsetRowContainer:ClearAllPoints()
            R.iconOffsetRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.labelX, y)
            R.iconOffsetRowContainer:SetSize(appearanceG.rowContainerW, offsetRowH)
            R.iconOffsetPairLabel:ClearAllPoints()
            R.iconOffsetPairLabel:SetPoint("TOPLEFT", R.iconOffsetRowContainer, "TOPLEFT", 0, -offsetLabelTop)
            R.iconOffsetAxisXMini:ClearAllPoints()
            R.iconOffsetAxisXMini:SetPoint("TOPLEFT", R.iconOffsetRowContainer, "TOPLEFT", appearanceG.controlX - appearanceG.labelX, -(offsetStackTop + math.floor((offsetLine1H - axisXH) / 2)))
            R.iconOffsetXSlider.control:ClearAllPoints()
            R.iconOffsetXSlider.control:SetPoint("TOPLEFT", R.iconOffsetRowContainer, "TOPLEFT", appearanceG.offsetSliderX - appearanceG.labelX, -(offsetStackTop + math.floor((offsetLine1H - offsetXControlH) / 2)))
            R.iconOffsetAxisYMini:ClearAllPoints()
            R.iconOffsetAxisYMini:SetPoint("TOPLEFT", R.iconOffsetRowContainer, "TOPLEFT", appearanceG.controlX - appearanceG.labelX, -(offsetLine2Top + math.floor((offsetLine2H - axisYH) / 2)))
            R.iconOffsetYSlider.control:ClearAllPoints()
            R.iconOffsetYSlider.control:SetPoint("TOPLEFT", R.iconOffsetRowContainer, "TOPLEFT", appearanceG.offsetSliderX - appearanceG.labelX, -(offsetLine2Top + math.floor((offsetLine2H - offsetYControlH) / 2)))
            y = y - offsetRowH

            local iconEdgeLabelH = measureTimersSingleLineHeight(R.iconEdgeLabel, appearanceG.labelW, T.LABEL_FLOOR, true)
            local iconEdgeControlH = measureTimersControlHeight(R.iconEdgeControl and R.iconEdgeControl.control or nil, T.CONTROL_FLOOR, R.iconEdgeControl and R.iconEdgeControl.control ~= nil)
            local iconEdgeRowH = math.max(T.ROW_FLOOR, iconEdgeLabelH, iconEdgeControlH)
            local iconEdgeLabelTop = math.floor((iconEdgeRowH - iconEdgeLabelH) / 2)
            local iconEdgeControlTop = math.floor((iconEdgeRowH - iconEdgeControlH) / 2)
            R.iconEdgeLabel:ClearAllPoints()
            R.iconEdgeLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.labelX, y - iconEdgeLabelTop)
            if R.iconEdgeControl and R.iconEdgeControl.control then
                R.iconEdgeControl.control:ClearAllPoints()
                R.iconEdgeControl.control:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.controlX, y - iconEdgeControlTop)
            end
            y = y - iconEdgeRowH

            local aspectLabelH = measureTimersSingleLineHeight(R.aspectLabel, appearanceG.labelW, T.LABEL_FLOOR, true)
            local aspectControlH = measureTimersControlHeight(R.aspectDropdown.control, T.CONTROL_FLOOR, true)
            local aspectRowH = math.max(T.ROW_FLOOR, aspectLabelH, aspectControlH)
            local aspectLabelTop = math.floor((aspectRowH - aspectLabelH) / 2)
            local aspectControlTop = math.floor((aspectRowH - aspectControlH) / 2)
            R.aspectLabel:ClearAllPoints()
            R.aspectLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.labelX, y - aspectLabelTop)
            R.aspectDropdown.control:ClearAllPoints()
            R.aspectDropdown.control:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", appearanceG.controlX, y - aspectControlTop)
            y = y - aspectRowH

            local extentObjects = {
                R.header,
                R.masterRowContainer,
                R.lockRowContainer,
                R.lockStateHelper,
                R.divider,
                R.modulesHeader,
                R.batchActionsCard,
                R.dividerFont,
                R.appearanceLayoutHeader,
                R.fontRowContainer,
                R.coordsLabel,
                R.coords,
                R.iconSizeSlider and R.iconSizeSlider.label or nil,
                R.iconSizeSlider and R.iconSizeSlider.control or nil,
                R.iconOffsetRowContainer,
                R.iconEdgeLabel,
                R.iconEdgeControl and R.iconEdgeControl.control or nil,
                R.aspectLabel,
                R.aspectDropdown and R.aspectDropdown.control or nil,
            }
            for _, module in ipairs(moduleRows) do
                if module and module.row then
                    extentObjects[#extentObjects + 1] = module.row.label
                    extentObjects[#extentObjects + 1] = module.row.control
                end
                for _, child in ipairs(module and module.childRows or {}) do
                    if child and child.row then
                        extentObjects[#extentObjects + 1] = child.row.label
                        extentObjects[#extentObjects + 1] = child.row.control
                    end
                end
                if module and module.unavailableHelper then
                    extentObjects[#extentObjects + 1] = module.unavailableHelper
                end
                for _, fs in ipairs(module and module.explainers or {}) do
                    extentObjects[#extentObjects + 1] = fs
                end
            end
            local measuredExtent = measureSettingsVisibleContentExtent(scrollChild, extentObjects)
            local visibleExtent = (measuredExtent and math.ceil(measuredExtent)) or nil
            local fallbackExtent = math.abs(y)
            local used = (visibleExtent or fallbackExtent) + T.BOTTOM_PAD
            local contentHeight = math.max(scrollFrame:GetHeight(), used)
            scrollChild:SetHeight(contentHeight)
            updateScrollBehavior(scrollFrame, scrollChild)
        end

        self._layout = layout

        local registeredHooksApi = nil
        local function ensureOptionsHooksRegistered()
            local hooksApi = getModulesApi()
            if not hooksApi or not hooksApi.RegisterOptionsHooks then
                return
            end
            if registeredHooksApi == hooksApi then
                return
            end

            hooksApi:RegisterOptionsHooks({
                onTimersPositionChanged = function(x, y)
                    if coords and not coords:HasFocus() then
                        setTimersCoordsDisplay(coords, x, y)
                    end
                end,
            })
            registeredHooksApi = hooksApi
        end

        ensureOptionsHooksRegistered()
        self._ensureOptionsHooksRegistered = ensureOptionsHooksRegistered

        registerRefreshCallback(function()
            if shouldSuppressSettingsFirstOpenExternalRefresh(self) then
                return
            end
            if self._refresh then
                self._refresh()
            end
        end, self)
        scrollFrame:SetScript("OnSizeChanged", function()
            if handleSettingsFirstOpenSizeReady(self, "size_changed") then
                return
            end
            if shouldSuppressSettingsFirstOpenExternalRefresh(self) then
                return
            end
            if self._layout then self._layout() end
        end)
        self._settingsFirstOpenKey = "timers"
        self._settingsFirstOpenSizeTarget = scrollFrame
        self._settingsFirstOpenRender = function(panel)
            if panel._ensureOptionsHooksRegistered then
                panel._ensureOptionsHooksRegistered()
            end
            if panel._layout then
                panel._layout()
            end
            if panel._refresh then
                panel._refresh()
            end
        end
        self._settingsFirstOpenIsReady = function(panel)
            local sizeControl = (sizeStepper and sizeStepper.control) or sizeEdit
            local useHostedChrome = isPanelUsingCustomSettingsWindowHost(panel)
            return panelHasSizedViewport(scrollFrame)
                and header ~= nil
                and (useHostedChrome or header:IsShown())
                and lockRowContainer ~= nil and lockRowContainer:IsShown()
                and batchActionsCard ~= nil and batchActionsCard:IsShown()
                and sizeControl ~= nil and sizeControl:IsShown()
                and coords ~= nil and coords:IsShown()
                and (tonumber(scrollChild:GetHeight()) or 0) >= math.max(tonumber(scrollFrame:GetHeight()) or 0, 1)
        end
        settingsSearchRuntime.endDescriptorCapture(self)
        refresh()
    end

    panel:SetScript("OnShow", function(self)
        ensureSettingsCanvasPanelAnchored(self)
        self:EnsureBuilt()
        if not handleSettingsFirstOpenPanelShow(self) then
            withPanelHydration(self, function()
                if self._ensureOptionsHooksRegistered then
                    self._ensureOptionsHooksRegistered()
                end
                if self._layout then self._layout() end
                if self._refresh then self._refresh() end
            end)
        end
        self._timersLiveSyncElapsed = 0
    end)
    panel:HookScript("OnHide", function(self)
        handleSettingsFirstOpenPanelHide(self)
    end)
    panel:HookScript("OnUpdate", function(self, elapsed)
        if not self:IsShown() then return end
        self._timersLiveSyncElapsed = (self._timersLiveSyncElapsed or 0) + (elapsed or 0)
        if self._timersLiveSyncElapsed < 0.15 then
            return
        end
        self._timersLiveSyncElapsed = 0
        if self._syncTimersLiveFields then
            self._syncTimersLiveFields()
        end
    end)

    return panel
end

local function createInterruptTrackerPanel()
    local panel = CreateFrame("Frame")
    panel.name = "Interrupt Tracker"
    panel._paSearchSectionKey = "interrupt"
    panel._paSearchSectionName = panel.name
    local INTERRUPT_FIRST_OPEN_DEFERRED_DELAYS = { 0, 0.05 }

    local function interruptTrackerHasFullContent(self)
        if not self then
            return false
        end
        local scrollFrame = self._interruptTrackerScrollFrame
        local scrollChild = self._interruptTrackerScrollChild
        local widgets = self._interruptTrackerWidgets
        if not scrollFrame or not scrollChild or not widgets then
            return false
        end
        if not panelHasSizedViewport(scrollFrame) then
            return false
        end

        local appearanceCard = widgets.appearanceCard
        local guidedPreviewCard = widgets.guidedPreviewCard
        local alertCard = widgets.alertCard
        local widthLabel = widgets.widthLabel
        local widthControl = widgets.widthStepper and widgets.widthStepper.control or nil
        local guidedPreviewSample = widgets.guidedPreviewSample
        local guidedPreviewLegend = widgets.guidedPreviewLegend
        local guidedPreviewRow = widgets.guidedPreviewRows and widgets.guidedPreviewRows[1] or nil
        local alertSoundControl = widgets.alertSound and widgets.alertSound.control or nil
        local alertScopeControl = widgets.alertScope and widgets.alertScope.control or nil
        if not appearanceCard or not guidedPreviewCard or not alertCard or not widthLabel or not widthControl or not guidedPreviewSample or not guidedPreviewLegend or not guidedPreviewRow or not alertSoundControl or not alertScopeControl then
            return false
        end
        if not appearanceCard:IsShown() or not guidedPreviewCard:IsShown() or not alertCard:IsShown() then
            return false
        end
        if not widthLabel:IsShown() or not widthControl:IsShown() or not guidedPreviewSample:IsShown() or not guidedPreviewLegend:IsShown() or not guidedPreviewRow:IsShown() or not alertSoundControl:IsShown() or not alertScopeControl:IsShown() then
            return false
        end

        local appearanceH = tonumber(appearanceCard:GetHeight()) or 0
        local guidedH = tonumber(guidedPreviewCard:GetHeight()) or 0
        local alertH = tonumber(alertCard:GetHeight()) or 0
        local lockRowH = tonumber(widgets.lockRowContainer and widgets.lockRowContainer:GetHeight()) or 0
        local contentH = tonumber(scrollChild:GetHeight()) or 0
        local viewportH = tonumber(scrollFrame:GetHeight()) or 0
        local requiredContentH = appearanceH + guidedH + alertH + lockRowH

        if appearanceH <= 1 or guidedH <= 1 or alertH <= 1 or lockRowH <= 1 then
            return false
        end
        if contentH < math.max(viewportH, requiredContentH) then
            return false
        end

        local appearanceBottom = tonumber(appearanceCard:GetBottom()) or 0
        local guidedTop = tonumber(guidedPreviewCard:GetTop()) or 0
        local guidedBottom = tonumber(guidedPreviewCard:GetBottom()) or 0
        local alertTop = tonumber(alertCard:GetTop()) or 0
        local alertBottom = tonumber(alertCard:GetBottom()) or 0
        if appearanceBottom <= 0 or guidedTop <= 0 or guidedBottom <= 0 or alertTop <= 0 or alertBottom <= 0 then
            return false
        end
        if appearanceBottom <= guidedTop then
            return false
        end
        if guidedBottom <= alertTop then
            return false
        end

        return true
    end

    local function setInterruptTrackerBootstrapActive(state)
        if PortalAuthority and PortalAuthority.SetSettingsBootstrapActive then
            PortalAuthority:SetSettingsBootstrapActive(state)
        end
    end

    local function getInterruptTrackerFirstOpenGeneration(self)
        return math.max(0, tonumber(self and self._interruptFirstOpenGeneration) or 0)
    end

    local function resetInterruptTrackerFirstOpenState(self)
        if not self then
            return 0
        end
        if self.StopGuidedPreviewTicker then
            self:StopGuidedPreviewTicker()
        end
        local generation = getInterruptTrackerFirstOpenGeneration(self) + 1
        self._interruptFirstOpenGeneration = generation
        self._interruptFirstOpenState = "idle"
        self._interruptQueuedPreviewReason = nil
        self._interruptPreviewRefreshPending = nil
        self._interruptPreviewRefreshToken = (tonumber(self._interruptPreviewRefreshToken) or 0) + 1
        setInterruptTrackerBootstrapActive("none")
        return generation
    end

    local function completeInterruptTrackerFirstOpen(self, generation, ready)
        if not self then
            return false
        end
        if self._interruptFirstOpenState ~= "pending" then
            return false
        end
        if getInterruptTrackerFirstOpenGeneration(self) ~= generation then
            return false
        end
        self._interruptFirstOpenState = ready and "ready" or "idle"
        self._interruptFirstOpenGeneration = generation + 1
        setInterruptTrackerBootstrapActive("none")
        return true
    end

    local function interruptTrackerBootstrapShouldBail(self, generation)
        if not self then
            return true
        end
        if getInterruptTrackerFirstOpenGeneration(self) ~= generation then
            return true
        end
        if self._interruptFirstOpenState ~= "pending" then
            return true
        end
        if self._interruptClosing then
            resetInterruptTrackerFirstOpenState(self)
            return true
        end
        if not self.IsShown or not self:IsShown() then
            resetInterruptTrackerFirstOpenState(self)
            return true
        end
        return false
    end

    local function runInterruptTrackerFirstOpenPass(self, generation, source)
        if interruptTrackerBootstrapShouldBail(self, generation) then
            return false
        end

        if self._runInterruptTrackerVisibleFullLayout then
            withPanelHydration(self, function()
                self._runInterruptTrackerVisibleFullLayout(source or "on_show")
            end)
        elseif self._routeInterruptTrackerRefresh then
            withPanelHydration(self, function()
                self._routeInterruptTrackerRefresh(source or "on_show")
            end)
        end

        return interruptTrackerHasFullContent(self)
    end

    local function queueInterruptTrackerFirstOpenFollowUp(self, generation, passIndex)
        local attemptIndex = math.max(0, tonumber(passIndex) or 0)
        local delay = INTERRUPT_FIRST_OPEN_DEFERRED_DELAYS[attemptIndex + 1]
        if delay == nil then
            completeInterruptTrackerFirstOpen(self, generation, false)
            return
        end

        local function run()
            if interruptTrackerBootstrapShouldBail(self, generation) then
                return
            end

            local sized = panelHasSizedViewport(self and self._interruptTrackerScrollFrame)
            local ready = runInterruptTrackerFirstOpenPass(self, generation, sized and "size_changed" or "on_show")
            if ready then
                completeInterruptTrackerFirstOpen(self, generation, true)
                return
            end

            queueInterruptTrackerFirstOpenFollowUp(self, generation, attemptIndex + 1)
        end

        if C_Timer and C_Timer.After then
            C_Timer.After(delay, run)
        else
            run()
        end
    end

    local function startInterruptTrackerFirstOpenBootstrap(self)
        if not self then
            return
        end
        if self._interruptFirstOpenState == "ready" or self._interruptFirstOpenState == "pending" then
            return
        end

        local generation = getInterruptTrackerFirstOpenGeneration(self) + 1
        self._interruptFirstOpenGeneration = generation
        self._interruptFirstOpenState = "pending"
        setInterruptTrackerBootstrapActive("interrupt")
        if runInterruptTrackerFirstOpenPass(self, generation, "on_show") then
            completeInterruptTrackerFirstOpen(self, generation, true)
            return
        end
        queueInterruptTrackerFirstOpenFollowUp(self, generation, 0)
    end

    panel.EnsureBuilt = function(self)
        if self._initialized and self._layout and self._refresh then
            return
        end

        resetInterruptTrackerFirstOpenState(self)
        resetSettingsFirstOpenPanelState(self)
        ensureDatabase()
        settingsSearchRuntime.beginDescriptorCapture(self)
        local scrollFrame, scrollChild = createScrollableChild(self)
        self._sizingFrame = scrollFrame
        self._interruptTrackerScrollFrame = scrollFrame
        self._interruptTrackerScrollChild = scrollChild
        if not scrollFrame or not scrollChild then
            settingsSearchRuntime.endDescriptorCapture(self)
            return
        end

        local widgets = {}
        self._interruptTrackerWidgets = widgets
        local panelRef = self
        local INTERRUPT_ROUTE_HIDDEN_FULL = "hidden_full_refresh"
        local INTERRUPT_ROUTE_VISIBLE_FULL = "visible_full_layout"
        local INTERRUPT_ROUTE_PASSIVE = "passive_sync"
        local GUIDED_PREVIEW_TICK_INTERVAL = 0.1
        local INTERRUPT_RUNTIME_BG_BAR = { 0.09, 0.10, 0.13 }
        local INTERRUPT_TRIGGER_ROUTE_MAP = {
            on_show = { visible = INTERRUPT_ROUTE_VISIBLE_FULL, hidden = INTERRUPT_ROUTE_HIDDEN_FULL },
            apply_setting = { visible = INTERRUPT_ROUTE_VISIBLE_FULL, hidden = INTERRUPT_ROUTE_HIDDEN_FULL },
            apply_visual_setting = { visible = INTERRUPT_ROUTE_PASSIVE, hidden = INTERRUPT_ROUTE_HIDDEN_FULL },
            size_changed = { visible = INTERRUPT_ROUTE_VISIBLE_FULL, hidden = INTERRUPT_ROUTE_HIDDEN_FULL },
            registered_refresh = { visible = INTERRUPT_ROUTE_VISIBLE_FULL, hidden = INTERRUPT_ROUTE_HIDDEN_FULL },
            passive_tick = { visible = INTERRUPT_ROUTE_PASSIVE, hidden = nil },
            hidden_refresh = { visible = INTERRUPT_ROUTE_HIDDEN_FULL, hidden = INTERRUPT_ROUTE_HIDDEN_FULL },
            guided_preview_relayout = { visible = INTERRUPT_ROUTE_VISIBLE_FULL, hidden = INTERRUPT_ROUTE_HIDDEN_FULL },
            guided_preview_repaint = { visible = INTERRUPT_ROUTE_PASSIVE, hidden = INTERRUPT_ROUTE_HIDDEN_FULL },
        }
        local refreshInterruptTrackerPanel = nil
        local layoutInterruptTrackerPanel = nil
        local passiveSyncInterruptTrackerPanel = nil
        local routeInterruptTrackerRefresh = nil
        local previewInterruptTrackerBackgroundOpacity = nil

        -- Module / DB adapter
        local moduleAdapter = {}

        function moduleAdapter:GetModule()
            return PortalAuthority and PortalAuthority.Modules and PortalAuthority.Modules.registry and PortalAuthority.Modules.registry.interruptTracker or nil
        end

        function moduleAdapter:GetDB()
            local module = self:GetModule()
            local shared = module and module._shared or nil
            if shared and shared.EnsureDB then
                local ok, moduleDb = pcall(shared.EnsureDB)
                if ok and type(moduleDb) == "table" then
                    return moduleDb
                end
            end
            if module and module.GetDB then
                local ok, moduleDb = pcall(module.GetDB, module)
                if ok and type(moduleDb) == "table" then
                    return moduleDb
                end
            end
            PortalAuthorityDB = PortalAuthorityDB or {}
            PortalAuthorityDB.modules = PortalAuthorityDB.modules or {}
            PortalAuthorityDB.modules.interruptTracker = PortalAuthorityDB.modules.interruptTracker or {}
            return PortalAuthorityDB.modules.interruptTracker
        end

        function moduleAdapter:EnsureModule(initialize)
            local module = self:GetModule()
            if module and initialize and module.Initialize and not module.frame then
                local ok, err = pcall(module.Initialize, module)
                if not ok then
                    if type(debugSettingsLog) == "function" then
                        debugSettingsLog("interrupt tracker module init failed:", tostring(err))
                    end
                    return nil
                end
            end
            return module
        end

        function moduleAdapter:ApplySettings(refreshSource)
            refreshSource = tostring(refreshSource or "apply_setting")
            local module = self:EnsureModule(true)
            if module then
                if module.ApplySettings then
                    pcall(module.ApplySettings, module)
                elseif module.EvaluateVisibility then
                    pcall(module.EvaluateVisibility, module, "options-apply")
                end
            end
            if routeInterruptTrackerRefresh then
                routeInterruptTrackerRefresh(refreshSource)
            end
        end

        local function getModule()
            return moduleAdapter:GetModule()
        end

        local function getDB()
            return moduleAdapter:GetDB()
        end

        local function ensureModule(initialize)
            return moduleAdapter:EnsureModule(initialize)
        end

        local function applyModuleSettings(refreshSource)
            moduleAdapter:ApplySettings(refreshSource)
        end

        local function previewInterruptTrackerAlertSoundValue(value)
            local selected = normalizeSoundChoiceValue(value)
            if selected == nil or selected == "" then
                return
            end

            local soundFile = selected
            local media = getPortalMedia()
            if media and media.ResolveSoundFile then
                soundFile = media.ResolveSoundFile(selected)
            end
            if type(soundFile) == "string" then
                local asNum = tonumber(soundFile)
                if asNum then
                    soundFile = asNum
                end
            end
            if not soundFile or soundFile == "" then
                return
            end

            if type(soundFile) == "number" and PlaySound then
                PlaySound(soundFile, "Master")
            elseif PlaySoundFile then
                PlaySoundFile(soundFile, "Master")
            end
        end

        local function createPickerButton(parent, labelText, optionsProvider, getter, setter, onApplyCallback, pickerOpts)
            pickerOpts = type(pickerOpts) == "table" and pickerOpts or {}
            local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
            label:SetText(labelText or "")

            local button = CreateFrame("Button", nil, parent, "BackdropTemplate")
            button:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
            button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
            button:SetHeight(22)
            button:SetWidth(math.max(132, math.floor(tonumber(pickerOpts.width) or 180)))
            button:EnableMouse(true)
            if type(pickerOpts.onRightClick) == "function" then
                button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
            else
                button:RegisterForClicks("LeftButtonUp")
            end
            button:SetFrameStrata(parent and parent.GetFrameStrata and parent:GetFrameStrata() or "MEDIUM")
            button:SetFrameLevel((parent and parent.GetFrameLevel and parent:GetFrameLevel() or 0) + 10)

            local text = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 11)
            text:SetPoint("LEFT", button, "LEFT", 8, 0)
            text:SetPoint("RIGHT", button, "RIGHT", -18, 0)
            text:SetJustifyH("LEFT")
            text:SetTextColor(0.92, 0.92, 0.92, 1)

            local caret = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 10)
            caret:SetPoint("RIGHT", button, "RIGHT", -7, 0)
            caret:SetText("v")
            caret:SetTextColor(0.76, 0.76, 0.78, 1)
            button._paSelectEnabled = true
            local setVisualSelectedValue = nil

            local picker = CreatePicker(UIParent, {}, function(value)
                local selectedValue = value == nil and "" or value
                if setter then
                    setter(selectedValue)
                end
                setVisualSelectedValue(selectedValue)
                if onApplyCallback then
                    onApplyCallback()
                end
            end, {
                title = tostring(pickerOpts.title or "Select Option"),
                searchHint = tostring(pickerOpts.searchHint or "Search"),
                width = tonumber(pickerOpts.pickerWidth) or 420,
                height = tonumber(pickerOpts.pickerHeight) or 360,
                showSecondary = false,
                useOptionFontPreview = pickerOpts.useOptionFontPreview and true or false,
                useOptionTexturePreview = pickerOpts.useOptionTexturePreview and true or false,
                previewFontSize = tonumber(pickerOpts.previewFontSize) or 12,
                onOptionRightClick = pickerOpts.onOptionRightClick,
                showClearButton = false,
                footerHint = tostring(pickerOpts.footerHint or ""),
            })

            local currentLabel = ""
            local function setButtonLabel(labelTextValue)
                currentLabel = tostring(labelTextValue or "")
                text:SetWordWrap(false)
                if text.SetMaxLines then
                    text:SetMaxLines(1)
                end
                local maxWidth = math.max(20, (button:GetWidth() or 0) - 26)
                text:SetWidth(maxWidth)
                text:SetText(currentLabel)
                if pickerOpts and pickerOpts.ellipsis == false then
                    return
                end
                if text:GetStringWidth() <= maxWidth then
                    return
                end
                local cut = string.len(currentLabel)
                while cut > 0 do
                    local candidate = string.sub(currentLabel, 1, cut) .. "..."
                    text:SetText(candidate)
                    if text:GetStringWidth() <= maxWidth then
                        return
                    end
                    cut = cut - 1
                end
                text:SetText("...")
            end

            local function applyVisual(hovered)
                applySettingsWindowSelectButtonChrome(
                    button,
                    text,
                    caret,
                    hovered,
                    false,
                    button._paSelectEnabled ~= false,
                    function()
                        if hovered then
                            button:SetBackdropColor(0.16, 0.17, 0.20, 0.95)
                            button:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                            caret:SetTextColor(0.88, 0.88, 0.90, 1)
                        else
                            button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
                            button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                            caret:SetTextColor(0.76, 0.76, 0.78, 1)
                        end
                    end
                )
            end

            local function buildOptions()
                local built = {}
                for _, option in ipairs(optionsProvider and optionsProvider() or {}) do
                    local value = option.value
                    if value == nil then
                        value = ""
                    end
                    built[#built + 1] = {
                        value = value,
                        label = tostring(option.label or value),
                        buttonLabel = tostring(option.buttonLabel or option.label or value),
                        secondary = tostring(option.secondary or ""),
                        previewFontPath = option.previewFontPath,
                        previewTexturePath = option.previewTexturePath or option.path,
                        aliases = option.aliases,
                    }
                end
                if #built == 0 then
                    built[1] = { value = "", label = "None", buttonLabel = "None", secondary = "" }
                end
                return built
            end

            local function resolveSelection(rawValue, options, allowRepair)
                if allowRepair == nil then
                    allowRepair = true
                end
                local selected = rawValue
                if selected == nil then
                    selected = ""
                end
                local selectedKey = tostring(selected)
                local selectedLabel = nil
                local emptyFallbackLabel = tostring(pickerOpts.emptyLabel or "None")
                for _, option in ipairs(options or {}) do
                    if tostring(option.value or "") == selectedKey then
                        selected = option.value
                        selectedLabel = tostring(option.buttonLabel or option.label or selectedKey)
                        break
                    end
                end
                if not selectedLabel then
                    if selectedKey == "" then
                        selected = ""
                        selectedLabel = emptyFallbackLabel
                    else
                        local first = options and options[1] or nil
                        if first then
                            selected = first.value
                            selectedLabel = tostring(first.buttonLabel or first.label or tostring(selected or ""))
                            if allowRepair and setter then
                                setter(selected)
                            end
                        else
                            selected = ""
                            selectedLabel = "None"
                        end
                    end
                end
                return selected, selectedLabel
            end

            setVisualSelectedValue = function(rawValue)
                local options = buildOptions()
                local selectedValue, labelTextValue = resolveSelection(rawValue, options, false)
                picker:SetSelectedValue(selectedValue)
                setButtonLabel(labelTextValue)
            end

            button:SetScript("OnEnter", function()
                applyVisual(true)
            end)
            button:SetScript("OnLeave", function()
                applyVisual(false)
            end)
            button:SetScript("OnClick", function(_, mouseButton)
                if mouseButton == "RightButton" then
                    if type(pickerOpts.onRightClick) == "function" then
                        pickerOpts.onRightClick(getter and getter() or "")
                    end
                    return
                end
                if picker and picker.IsShown and picker:IsShown() then
                    picker:Close()
                    return
                end
                local options = buildOptions()
                picker:SetOptions(options)
                picker:SetSelectedValue(getter and getter() or "")
                picker:Open(button)
            end)
            button:HookScript("OnShow", function()
                local options = buildOptions()
                local _, labelTextValue = resolveSelection(getter and getter() or "", options, false)
                setButtonLabel(labelTextValue)
            end)
            button:HookScript("OnSizeChanged", function()
                setButtonLabel(currentLabel)
            end)
            registerSettingsWindowVisualRefresh(button, function()
                applyVisual(button.IsMouseOver and button:IsMouseOver() or false)
            end)

            return {
                label = label,
                control = button,
                picker = picker,
                SetVisualSelectedValue = function(_, value)
                    setVisualSelectedValue(value)
                end,
                SetEnabled = function(_, enabled)
                    local allow = enabled and true or false
                    button._paSelectEnabled = allow
                    button:EnableMouse(allow)
                    button:SetAlpha(allow and 1 or 0.6)
                    text:SetAlpha(allow and 1 or 0.65)
                    caret:SetAlpha(allow and 1 or 0.65)
                    applyVisual(false)
                end,
                Refresh = function()
                    local options = buildOptions()
                    picker:SetOptions(options)
                    local selectedValue, labelTextValue = resolveSelection(getter and getter() or "", options, true)
                    picker:SetSelectedValue(selectedValue)
                    setButtonLabel(labelTextValue)
                end,
            }
        end

        local function createToggleRow(parent, labelText, getter, setter, refreshSource)
            return createPremiumSegmentedChoice(parent, labelText, nil, {
                { label = "Off", value = false, toggleState = "off" },
                { label = "On", value = true, toggleState = "on" },
            }, function(value)
                setter(value)
                applyModuleSettings(refreshSource or "apply_setting")
            end, {
                semantic = "toggle",
                normalizeValue = function(value)
                    return value and true or false
                end,
                getValue = getter,
                setValue = setter,
            })
        end

        local function createLockRow(parent, getter, setter, refreshSource)
            return createPremiumSegmentedChoice(parent, "Lock Position", nil, {
                { label = "Unlocked", value = false },
                { label = "Locked", value = true },
            }, function(value)
                setter(value)
                local module = ensureModule(true)
                if module and module.SetUnlocked then
                    pcall(module.SetUnlocked, module, not value)
                end
                applyModuleSettings(refreshSource or "apply_setting")
            end, {
                semantic = "selection",
                selectionVariant = "lock_meta",
                normalizeValue = function(value)
                    return value and true or false
                end,
                getValue = getter,
                setValue = setter,
            })
        end

        local function createStepper(parent, minValue, maxValue, getter, setter, onApplyCallback)
            if type(createCanonicalDockFontSizeStepperControl) == "function" then
                local control = createCanonicalDockFontSizeStepperControl(
                    parent,
                    "",
                    minValue,
                    maxValue,
                    1,
                    nil,
                    58,
                    onApplyCallback,
                    nil,
                    {
                        micro = true,
                        shiftMultiplier = 5,
                        getValue = function()
                            return getter()
                        end,
                        setValue = function(value)
                            setter(value)
                        end,
                    }
                )
                if control and control.label then
                    control.label:SetText("")
                    control.label:Hide()
                end
                return control
            end

            local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
            label:SetText("")
            label:Hide()

            local container = CreateFrame("Frame", nil, parent)
            container:SetHeight(22)
            container:SetWidth(58)

            local function createStepperButton(symbol)
                local button = CreateFrame("Button", nil, container)
                button:SetSize(10, 16)

                local text = createStyledFontString(button, "ARTWORK", "GameFontHighlight", 12)
                text:SetPoint("CENTER", button, "CENTER", 0, 0)
                text:SetText(symbol)
                text:SetTextColor(0.74, 0.74, 0.76, 1)
                button._text = text
                button._hovered = false
                button._pressed = false

                local function applyVisual(selfBtn)
                    if selfBtn._pressed then
                        selfBtn._text:SetTextColor(0.95, 0.95, 0.98, 1)
                        selfBtn:SetAlpha(0.82)
                    elseif selfBtn._hovered then
                        selfBtn._text:SetTextColor(0.95, 0.95, 0.98, 1)
                        selfBtn:SetAlpha(1)
                    else
                        selfBtn._text:SetTextColor(0.74, 0.74, 0.76, 1)
                        selfBtn:SetAlpha(1)
                    end
                end

                button:SetScript("OnEnter", function(selfBtn)
                    selfBtn._hovered = true
                    applyVisual(selfBtn)
                end)
                button:SetScript("OnLeave", function(selfBtn)
                    selfBtn._hovered = false
                    selfBtn._pressed = false
                    applyVisual(selfBtn)
                end)
                button:SetScript("OnMouseDown", function(selfBtn)
                    selfBtn._pressed = true
                    applyVisual(selfBtn)
                end)
                button:SetScript("OnMouseUp", function(selfBtn)
                    selfBtn._pressed = false
                    applyVisual(selfBtn)
                end)

                return button
            end

            local minusButton = createStepperButton("<")
            local plusButton = createStepperButton(">")
            local valueButton = CreateFrame("Button", nil, container)
            valueButton:SetHeight(16)

            local function layoutMicro()
                local gap = 3
                local buttonW = minusButton:GetWidth() or 10
                local containerW = container:GetWidth() or 58
                local valueW = math.max(20, math.min(28, containerW - (buttonW * 2) - (gap * 2)))
                local clusterW = (buttonW * 2) + valueW + (gap * 2)
                local startX = math.floor((containerW - clusterW) / 2)
                if startX < 0 then
                    startX = 0
                end

                minusButton:ClearAllPoints()
                minusButton:SetPoint("LEFT", container, "LEFT", startX, 0)

                valueButton:ClearAllPoints()
                valueButton:SetPoint("LEFT", minusButton, "RIGHT", gap, 0)
                valueButton:SetWidth(valueW)

                plusButton:ClearAllPoints()
                plusButton:SetPoint("LEFT", valueButton, "RIGHT", gap, 0)
            end

            layoutMicro()
            container:HookScript("OnSizeChanged", layoutMicro)

            local valueText = createStyledFontString(valueButton, "ARTWORK", "GameFontHighlightSmall", 11)
            valueText:SetPoint("CENTER", valueButton, "CENTER", 0, 0)
            valueText:SetTextColor(0.86, 0.86, 0.9, 1)

            local valueEdit = CreateFrame("EditBox", nil, valueButton)
            valueEdit:SetAllPoints(valueButton)
            valueEdit:SetAutoFocus(false)
            valueEdit:SetJustifyH("CENTER")
            valueEdit:SetTextInsets(0, 0, 0, 0)
            valueEdit:SetTextColor(1, 1, 1, 1)
            valueEdit:SetHighlightColor(1, 1, 1, 0.25)
            valueEdit:SetNumeric(true)
            applyGlobalFontToObject(valueEdit, 11)
            valueEdit:Hide()

            local currentValue = nil
            local editingValue = false
            local controlEnabled = true
            local stepValue = 1
            local microShiftMultiplier = 5

            local function normalize(v)
                local n = tonumber(v) or tonumber(minValue) or 0
                local minN = tonumber(minValue) or 0
                local maxN = tonumber(maxValue) or minN
                if maxN < minN then
                    minN, maxN = maxN, minN
                end
                if n < minN then n = minN end
                if n > maxN then n = maxN end
                n = minN + (math.floor(((n - minN) / stepValue) + 0.5) * stepValue)
                if n < minN then n = minN end
                if n > maxN then n = maxN end
                return math.floor(n + 0.5)
            end

            local function fmt(v)
                return tostring(math.floor((tonumber(v) or 0) + 0.5))
            end

            local function setValue(newValue, triggerApply)
                local n = normalize(newValue)
                currentValue = n
                if setter then
                    setter(n)
                end
                valueText:SetText(fmt(n))
                if valueEdit:IsShown() then
                    valueEdit:SetText(fmt(n))
                end
                if triggerApply and onApplyCallback then
                    onApplyCallback()
                end
            end

            local function beginEdit()
                editingValue = true
                valueText:Hide()
                valueEdit:SetText(fmt(currentValue or minValue))
                valueEdit:Show()
                valueEdit:SetFocus()
                valueEdit:HighlightText()
            end

            local function endEdit(commit)
                if not editingValue then
                    return
                end
                editingValue = false
                if commit then
                    local parsed = tonumber(valueEdit:GetText())
                    if parsed ~= nil then
                        setValue(parsed, true)
                    end
                end
                valueEdit:Hide()
                valueText:Show()
                valueEdit:ClearFocus()
                valueText:SetText(fmt(currentValue or minValue))
            end

            local function applyEnabledState()
                local alpha = controlEnabled and 1 or 0.5
                container:SetAlpha(alpha)
                label:SetAlpha(alpha)
                minusButton:SetEnabled(controlEnabled)
                plusButton:SetEnabled(controlEnabled)
                valueButton:SetEnabled(controlEnabled)
                if not controlEnabled and editingValue then
                    endEdit(false)
                end
            end

            minusButton:SetScript("OnClick", function()
                if not controlEnabled then
                    return
                end
                local mult = 1
                if IsShiftKeyDown and IsShiftKeyDown() then
                    mult = microShiftMultiplier
                end
                setValue((currentValue or minValue) - (stepValue * mult), true)
            end)
            plusButton:SetScript("OnClick", function()
                if not controlEnabled then
                    return
                end
                local mult = 1
                if IsShiftKeyDown and IsShiftKeyDown() then
                    mult = microShiftMultiplier
                end
                setValue((currentValue or minValue) + (stepValue * mult), true)
            end)
            valueButton:SetScript("OnClick", function()
                if not controlEnabled then
                    return
                end
                beginEdit()
            end)
            valueEdit:SetScript("OnEnterPressed", function(edit)
                endEdit(true)
                edit:ClearFocus()
            end)
            valueEdit:SetScript("OnEscapePressed", function(edit)
                endEdit(false)
                edit:ClearFocus()
            end)
            valueEdit:SetScript("OnEditFocusLost", function()
                endEdit(true)
            end)

            local spec = {
                kind = "stepper",
                label = label,
                control = container,
                valueButton = valueButton,
                valueText = valueText,
                valueEdit = valueEdit,
                minus = minusButton,
                plus = plusButton,
            }
            spec.SetWidth = function(_, newWidth)
                container:SetWidth(math.max(52, math.floor(tonumber(newWidth) or 58)))
            end
            spec.SetEnabled = function(_, enabled)
                controlEnabled = enabled and true or false
                applyEnabledState()
            end
            spec.IsEnabled = function()
                return controlEnabled
            end
            spec.SetVisualValue = function(_, value)
                local n = normalize(value)
                currentValue = n
                valueText:SetText(fmt(n))
                if valueEdit:IsShown() then
                    valueEdit:SetText(fmt(n))
                end
                applyEnabledState()
            end
            spec.Refresh = function()
                local n = normalize(getter and getter() or minValue)
                currentValue = n
                valueText:SetText(fmt(n))
                if valueEdit:IsShown() then
                    valueEdit:SetText(fmt(n))
                end
                applyEnabledState()
            end
            spec.Refresh()
            return spec
        end

        local INTERRUPT_LAYOUT = {
            panel = {
                TOP_PAD = 20,
                CONTENT_LEFT = 20,
                CONTENT_RIGHT = 20,
                HEADER_LEFT = 16,
                HEADER_FLOOR = 16,
                HEADER_MIN_W = 220,
                FALLBACK_CONTENT_W = 620,
                MIN_CONTENT_W = 560,
                BOTTOM_PAD = 60,
            },
            top = {
                HEADER_BOTTOM_GAP = 14,
                LOCK_LABEL_TO_TOGGLE_GAP = 12,
                LOCK_TOGGLE_TO_RESET_GAP = 12,
                LOCK_HELPER_MULTIPLIER = 0.625,
                LOCK_DIVIDER_MULTIPLIER = 1.25,
                LOCK_ROW_FLOOR = 22,
                LOCK_SEGMENT_BUTTON_TEXT_PAD_X = 20,
                RESET_W = 102,
                RESET_H = 22,
                LOCK_BUTTON_TEXT_FALLBACK_W = 36,
                LOCK_TOGGLE_MIN_W = 96,
                HELPER_FLOOR = 10,
                LABEL_FLOOR = 12,
                HELPER_MIN_W = 120,
                DIVIDER_H = 1,
            },
            cards = {
                MIN_W = 320,
                PAD = 12,
                TITLE_H = 16,
                TITLE_TO_CONTENT_GAP = 10,
                SECTION_GAP = 12,
            },
            rows = {
                STRIDE = 34,
                LABEL_X = 12,
                CONTROL_X = 180,
                CONTROL_FLOOR_H = 18,
                DEFAULT_CONTROL_H = 22,
                CONTENT_H = 24,
            },
            appearance = {
                ROW_COUNT = 8,
                ROW_SLOTS = {
                    BACKGROUND_OPACITY = 2,
                    FONT = 3,
                    BAR_TEXTURE = 4,
                    USE_CLASS_COLORS = 5,
                    SHOW_CLASS_ICON = 6,
                    SHOW_SPELL_ICON = 7,
                    RIGHT_DISPLAY = 8,
                },
                PICKER_W = 186,
                SEGMENTED_W = 150,
                RIGHT_DISPLAY_W = 236,
                FIRST_STEPPER_W = 78,
                INLINE_LABEL_TO_CONTROL_GAP = 12,
                FIRST_ROW_GROUP_GAP = 24,
                FONT_AUX_GAP = 10,
                FONT_PICKER_MIN_W = 140,
                FONT_PICKER_RIGHT_RESERVE = 96,
                FONT_SWATCH_FALLBACK_SIZE = 18,
            },
            preview = {
                SAMPLE_GAP = 16,
                SAMPLE_WIDTH_MIN = 160,
                STACKED_SAMPLE_MIN_W = 120,
                ROW_H_MIN = 18,
                ROW_H_MAX = 34,
                ROW_GAP_MAX = 8,
                CARD_MIN_H = 192,
                TICK = 0.05,
                CYCLE = 6.0,
                ACCENT_WIDTH = 6,
                ACCENT_ALPHA = 0.24,
                ICON_SEPARATOR_W = 2,
                ICON_SEPARATOR_GAP = 6,
                ICON_SEPARATOR_VERTICAL_INSET = 1,
                TIMER_VALUE_W = 52,
                COUNT_VALUE_W = 42,
                NAME_LEFT_INSET = 8,
                VALUE_RIGHT_INSET = 8,
                NAME_RIGHT_GAP = 10,
            },
            legend = {
                MIN_W = 140,
                SEED_H = 100,
                SWATCH_SIZE = 10,
                SWATCH_ROW_GAP = 8,
                SWATCH_TEXT_GAP = 8,
                SWATCH_TEXT_Y = 2,
                PRIMARY_TEXT_MIN_W = 96,
                SECONDARY_SECTION_GAP = 12,
                SECONDARY_TEXT_RIGHT_PAD = 20,
                CHIP_W = 12,
                CHIP_H = 2,
                CHIP_TEXT_GAP = 8,
            },
            notes = {
                HELPER_GAP = 10,
                LIMIT_NOTE_GAP = 8,
                BOTTOM_PAD = 4,
                FLOOR = 18,
            },
            alert = {
                ROW_SLOTS = {
                    SOUND = 1,
                },
                PICKER_W = 186,
                PICKER_MIN_W = 136,
                SCOPE_CONTROL_W = 108,
                SCOPE_CLUSTER_GAP = 18,
                SCOPE_LABEL_TO_CONTROL_GAP = 10,
            },
        }

        local function measureInterruptFontStringHeight(fs, floor)
            local measured = 0
            if fs and fs.GetStringHeight then
                measured = math.ceil(fs:GetStringHeight() or 0)
            end
            return math.max(tonumber(floor) or 0, measured)
        end

        local function measureInterruptControlHeight(widget, floor)
            local measured = 0
            if widget and widget.GetHeight then
                measured = math.ceil(widget:GetHeight() or 0)
            end
            return math.max(tonumber(floor) or 0, measured)
        end

        local function setInterruptSingleLineEllipsis(fs, fullText, maxWidth)
            if not fs then
                return
            end
            local source = tostring(fullText or "")
            fs:SetWordWrap(false)
            if fs.SetMaxLines then
                fs:SetMaxLines(1)
            end
            fs:SetWidth(maxWidth or 0)
            fs:SetText(source)
            if (maxWidth or 0) <= 0 then
                return
            end
            if (fs.GetStringWidth and fs:GetStringWidth() or 0) <= maxWidth then
                return
            end
            local cut = string.len(source)
            while cut > 0 do
                local candidate = string.sub(source, 1, cut) .. "..."
                fs:SetText(candidate)
                if (fs.GetStringWidth and fs:GetStringWidth() or 0) <= maxWidth then
                    return
                end
                cut = cut - 1
            end
            fs:SetText("...")
        end

        local function computeInterruptTopBlockLockGeometry(contentW, lockLabel)
            local panelTokens = INTERRUPT_LAYOUT.panel
            local topTokens = INTERRUPT_LAYOUT.top
            local lockLabelW = lockLabel and math.ceil(lockLabel:GetStringWidth() or 0) or 0
            local lockLabelH = lockLabel and math.ceil(lockLabel:GetStringHeight() or 0) or topTokens.LABEL_FLOOR
            local unit = math.max(1, lockLabelH)
            local lockBtnTextW = 0
            if widgets.lockPosition and type(widgets.lockPosition.buttons) == "table" then
                for _, btn in ipairs(widgets.lockPosition.buttons) do
                    if btn and btn.Text then
                        lockBtnTextW = math.max(lockBtnTextW, math.ceil(btn.Text:GetStringWidth() or 0))
                    end
                end
            end
            lockBtnTextW = math.max(lockBtnTextW, topTokens.LOCK_BUTTON_TEXT_FALLBACK_W)
            local lockToggleWFromContent = ((lockBtnTextW + (topTokens.LOCK_SEGMENT_BUTTON_TEXT_PAD_X * 2)) * 2) + 4
            local lockToggleWMax = math.max(
                topTokens.LOCK_TOGGLE_MIN_W,
                (contentW - panelTokens.CONTENT_RIGHT) - (panelTokens.CONTENT_LEFT + lockLabelW + topTokens.LOCK_LABEL_TO_TOGGLE_GAP + topTokens.LOCK_TOGGLE_TO_RESET_GAP + topTokens.RESET_W)
            )
            local lockToggleW = math.max(topTokens.LOCK_TOGGLE_MIN_W, math.min(lockToggleWFromContent, lockToggleWMax))
            local toggleX = (lockLabelW > 0) and (lockLabelW + topTokens.LOCK_LABEL_TO_TOGGLE_GAP) or 0
            local resetX = toggleX + lockToggleW + topTokens.LOCK_TOGGLE_TO_RESET_GAP
            return {
                labelW = lockLabelW,
                labelH = lockLabelH,
                helperGap = unit * topTokens.LOCK_HELPER_MULTIPLIER,
                dividerGap = unit * topTokens.LOCK_DIVIDER_MULTIPLIER,
                toggleW = lockToggleW,
                toggleX = toggleX,
                resetX = resetX,
                rowW = math.max(1, contentW - panelTokens.CONTENT_RIGHT - panelTokens.CONTENT_LEFT),
            }
        end

        local function computeInterruptContentWidth(frameWidth, panelWidth)
            local panelTokens = INTERRUPT_LAYOUT.panel
            local contentW = tonumber(frameWidth)
            if not contentW or contentW <= 1 then
                contentW = tonumber(panelWidth)
            end
            if not contentW or contentW <= 1 then
                contentW = panelTokens.FALLBACK_CONTENT_W
            end
            return math.max(panelTokens.MIN_CONTENT_W, contentW)
        end

        local function computeInterruptCardFrameGeometry(contentW)
            local panelTokens = INTERRUPT_LAYOUT.panel
            local cardTokens = INTERRUPT_LAYOUT.cards
            local cardX = panelTokens.CONTENT_LEFT
            local cardW = math.max(cardTokens.MIN_W, contentW - panelTokens.CONTENT_LEFT - panelTokens.CONTENT_RIGHT)
            return {
                x = cardX,
                width = cardW,
                innerWidth = cardW - (cardTokens.PAD * 2),
            }
        end

        local function computeInterruptHeaderWidth(contentW)
            local panelTokens = INTERRUPT_LAYOUT.panel
            return math.max(panelTokens.HEADER_MIN_W, contentW - panelTokens.HEADER_LEFT - panelTokens.CONTENT_RIGHT)
        end

        local function getInterruptCardRowTop(rowIndex)
            local cardTokens = INTERRUPT_LAYOUT.cards
            local rowTokens = INTERRUPT_LAYOUT.rows
            return -(cardTokens.PAD + cardTokens.TITLE_H + cardTokens.TITLE_TO_CONTENT_GAP + ((rowIndex - 1) * rowTokens.STRIDE))
        end

        local function computeInterruptCardHeight(rowCount, finalRowHeight)
            local cardTokens = INTERRUPT_LAYOUT.cards
            local rowTokens = INTERRUPT_LAYOUT.rows
            local terminalRowH = tonumber(finalRowHeight) or rowTokens.CONTENT_H
            return (cardTokens.PAD * 2) + cardTokens.TITLE_H + cardTokens.TITLE_TO_CONTENT_GAP + (rowCount * rowTokens.STRIDE) - (rowTokens.STRIDE - terminalRowH)
        end

        local function layoutInterruptCardHeader(card, headerWidget)
            if not (card and headerWidget) then
                return
            end
            local cardTokens = INTERRUPT_LAYOUT.cards
            headerWidget:ClearAllPoints()
            headerWidget:SetPoint("TOPLEFT", card, "TOPLEFT", cardTokens.PAD, -cardTokens.PAD)
        end

        local function layoutInterruptCardRow(card, rowIndex, labelWidget, controlWidget, opts)
            opts = type(opts) == "table" and opts or {}
            local rowTokens = INTERRUPT_LAYOUT.rows
            local rowTop = tonumber(opts.rowTop) or getInterruptCardRowTop(rowIndex)
            local labelX = tonumber(opts.labelX) or rowTokens.LABEL_X
            local controlX = tonumber(opts.controlX) or rowTokens.CONTROL_X
            local targetControl = controlWidget and (controlWidget.control or controlWidget) or nil
            if targetControl then
                targetControl:ClearAllPoints()
                targetControl:SetPoint("TOPLEFT", card, "TOPLEFT", controlX, rowTop)
                if opts.layoutWidth and controlWidget and controlWidget.Layout then
                    controlWidget:Layout(opts.layoutWidth)
                elseif opts.width and targetControl.SetWidth then
                    targetControl:SetWidth(opts.width)
                end
            end
            if labelWidget then
                labelWidget:ClearAllPoints()
                if targetControl then
                    local controlH = math.max(rowTokens.CONTROL_FLOOR_H, targetControl:GetHeight() or rowTokens.DEFAULT_CONTROL_H)
                    labelWidget:SetPoint("LEFT", card, "TOPLEFT", labelX, rowTop - math.floor(controlH * 0.5))
                else
                    labelWidget:SetPoint("TOPLEFT", card, "TOPLEFT", labelX, rowTop)
                end
            end
            return rowTop
        end

        local function computeInterruptAppearanceFirstRowGeometry(widthLabelW, rowHeightLabelW)
            local rowTokens = INTERRUPT_LAYOUT.rows
            local appearanceTokens = INTERRUPT_LAYOUT.appearance
            local widthLabelX = rowTokens.LABEL_X
            local widthControlX = widthLabelX + widthLabelW + appearanceTokens.INLINE_LABEL_TO_CONTROL_GAP
            local rowHeightLabelX = widthControlX + appearanceTokens.FIRST_STEPPER_W + appearanceTokens.FIRST_ROW_GROUP_GAP
            local rowHeightControlX = rowHeightLabelX + rowHeightLabelW + appearanceTokens.INLINE_LABEL_TO_CONTROL_GAP
            return {
                widthLabelX = widthLabelX,
                widthControlX = widthControlX,
                rowHeightLabelX = rowHeightLabelX,
                rowHeightControlX = rowHeightControlX,
                stepperW = appearanceTokens.FIRST_STEPPER_W,
            }
        end

        local function computeInterruptAppearanceFontRowGeometry(cardInnerW, fontSizeControlW)
            local rowTokens = INTERRUPT_LAYOUT.rows
            local appearanceTokens = INTERRUPT_LAYOUT.appearance
            local fontPickerW = math.max(appearanceTokens.FONT_PICKER_MIN_W, math.min(appearanceTokens.PICKER_W, cardInnerW - rowTokens.CONTROL_X - appearanceTokens.FONT_PICKER_RIGHT_RESERVE))
            local fontControlX = rowTokens.CONTROL_X
            local fontSizeX = fontControlX + fontPickerW + appearanceTokens.FONT_AUX_GAP
            local swatchX = fontSizeX + (tonumber(fontSizeControlW) or 0) + appearanceTokens.FONT_AUX_GAP
            return {
                pickerW = fontPickerW,
                fontControlX = fontControlX,
                fontSizeX = fontSizeX,
                swatchX = swatchX,
            }
        end

        local function computeInterruptAlertRowGeometry(cardInnerW, scopeLabelWidth)
            local rowTokens = INTERRUPT_LAYOUT.rows
            local alertTokens = INTERRUPT_LAYOUT.alert
            local pickerW = math.max(
                alertTokens.PICKER_MIN_W,
                cardInnerW - rowTokens.CONTROL_X - (scopeLabelWidth + alertTokens.SCOPE_CONTROL_W + alertTokens.SCOPE_CLUSTER_GAP + alertTokens.SCOPE_LABEL_TO_CONTROL_GAP)
            )
            local scopeLabelX = rowTokens.CONTROL_X + pickerW + alertTokens.SCOPE_CLUSTER_GAP
            local scopeControlX = scopeLabelX + scopeLabelWidth + alertTokens.SCOPE_LABEL_TO_CONTROL_GAP
            return {
                pickerW = pickerW,
                scopeLabelX = scopeLabelX,
                scopeControlX = scopeControlX,
            }
        end

        local function createInterruptSlider(parent, labelText, minValue, maxValue, stepValue, getter, setter, onApplyCallback, opts)
            opts = type(opts) == "table" and opts or {}
            local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
            label:SetText(labelText or "")

            local minV = tonumber(minValue) or 0
            local maxV = tonumber(maxValue) or 100
            local stepV = tonumber(stepValue) or 1
            if maxV < minV then
                minV, maxV = maxV, minV
            end

            local container = CreateFrame("Frame", nil, parent)
            container:SetHeight(22)
            container:SetWidth(math.max(140, tonumber(opts.width) or 220))

            local valueText = createStyledFontString(container, "ARTWORK", "GameFontHighlightSmall", 11)
            valueText:SetPoint("RIGHT", container, "RIGHT", 0, 0)
            valueText:SetJustifyH("RIGHT")
            valueText:SetTextColor(0.76, 0.76, 0.78, 1)

            local slider = CreateFrame("Slider", nil, container)
            slider:SetPoint("TOPLEFT", container, "TOPLEFT", 0, 0)
            slider:SetPoint("BOTTOMRIGHT", container, "BOTTOMRIGHT", -52, 0)
            slider:SetMinMaxValues(minV, maxV)
            slider:SetValueStep(stepV)
            local useManualDragTracking = opts.useManualDragTracking ~= false
            if slider.SetObeyStepOnDrag then
                slider:SetObeyStepOnDrag(true)
            end
            slider:SetThumbTexture("Interface\\Buttons\\WHITE8x8")
            local inputThumb = slider:GetThumbTexture()
            if inputThumb then
                inputThumb:SetSize(16, 16)
                inputThumb:SetVertexColor(1, 1, 1, 0.01)
            end
            slider:EnableMouse(not useManualDragTracking)
            slider:SetOrientation("HORIZONTAL")

            local trackBg = slider:CreateTexture(nil, "BACKGROUND")
            trackBg:SetTexture("Interface\\Buttons\\WHITE8x8")
            trackBg:SetPoint("LEFT", slider, "LEFT", 0, 0)
            trackBg:SetPoint("RIGHT", slider, "RIGHT", 0, 0)
            trackBg:SetHeight(2)
            trackBg:SetVertexColor(0.18, 0.18, 0.19, 0.95)

            local trackActive = slider:CreateTexture(nil, "ARTWORK")
            trackActive:SetTexture("Interface\\Buttons\\WHITE8x8")
            trackActive:SetPoint("LEFT", slider, "LEFT", 0, 0)
            trackActive:SetHeight(2)
            trackActive:SetWidth(0)
            trackActive:SetVertexColor(1.0, 0.82, 0.0, 0.75)

            local thumb = slider:CreateTexture(nil, "OVERLAY")
            thumb:SetTexture("Interface\\Buttons\\WHITE8x8")
            thumb:SetSize(8, 8)
            thumb:SetVertexColor(1.0, 0.84, 0.08, 0.98)
            if thumb.SetMask then
                thumb:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask")
            end

            local thumbGlow = slider:CreateTexture(nil, "ARTWORK")
            thumbGlow:SetTexture("Interface\\Buttons\\WHITE8x8")
            thumbGlow:SetSize(14, 14)
            thumbGlow:SetVertexColor(1.0, 0.82, 0.0, 0)
            if thumbGlow.SetMask then
                thumbGlow:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask")
            end
            thumbGlow:SetBlendMode("ADD")

            local inputLayer = nil
            if useManualDragTracking then
                inputLayer = CreateFrame("Button", nil, container)
                inputLayer:SetPoint("TOPLEFT", slider, "TOPLEFT", 0, 0)
                inputLayer:SetPoint("BOTTOMRIGHT", slider, "BOTTOMRIGHT", 0, 0)
                inputLayer:SetFrameStrata(slider:GetFrameStrata())
                inputLayer:SetFrameLevel((slider:GetFrameLevel() or 0) + 5)
                inputLayer:RegisterForClicks("LeftButtonDown", "LeftButtonUp")
                inputLayer:EnableMouse(true)
            end

            local suppress = false
            local currentValue = nil
            local dragging = false
            local hovering = false
            local pendingCommit = false
            local deferApplyUntilMouseUp = opts.deferApplyUntilMouseUp and true or false
            local previewCallback = type(opts.previewCallback) == "function" and opts.previewCallback or nil
            local commitCallback = type(opts.commitCallback) == "function" and opts.commitCallback or onApplyCallback
            local dragLeft = nil
            local dragRight = nil
            local dragScale = nil
            local lastDragCursorX = nil
            local dragCursorDeadzone = math.max(0.5, tonumber(opts.dragCursorDeadzone) or 0.75)

            local function normalize(v)
                local n = tonumber(v) or minV
                if n < minV then n = minV end
                if n > maxV then n = maxV end
                if stepV > 0 then
                    n = minV + (math.floor(((n - minV) / stepV) + 0.5) * stepV)
                end
                return math.floor(n + 0.5)
            end

            local function formatValue(v)
                if type(opts.formatter) == "function" then
                    return tostring(opts.formatter(v))
                end
                return tostring(math.floor((tonumber(v) or 0) + 0.5))
            end

            local function applyVisualState()
                local minSlider, maxSlider = slider:GetMinMaxValues()
                local value = normalize(slider:GetValue())
                local span = math.max(0.0001, (maxSlider - minSlider))
                local pct = math.max(0, math.min(1, (value - minSlider) / span))
                local widthNow = slider:GetWidth() or 0
                local x = pct * widthNow

                thumb:ClearAllPoints()
                thumb:SetPoint("CENTER", slider, "LEFT", x, 0)
                thumbGlow:ClearAllPoints()
                thumbGlow:SetPoint("CENTER", thumb, "CENTER", 0, 0)

                trackActive:ClearAllPoints()
                trackActive:SetPoint("LEFT", slider, "LEFT", 0, 0)
                trackActive:SetPoint("RIGHT", thumb, "CENTER", 0, 0)

                local glowAlpha = 0
                if dragging then
                    glowAlpha = 0.34
                    trackActive:SetVertexColor(1.0, 0.86, 0.16, 0.9)
                    thumb:SetVertexColor(1.0, 0.9, 0.22, 1)
                elseif hovering then
                    glowAlpha = 0.22
                    trackActive:SetVertexColor(1.0, 0.85, 0.12, 0.85)
                    thumb:SetVertexColor(1.0, 0.88, 0.18, 1)
                else
                    trackActive:SetVertexColor(1.0, 0.82, 0.0, 0.75)
                    thumb:SetVertexColor(1.0, 0.84, 0.08, 0.98)
                end
                thumbGlow:SetVertexColor(1.0, 0.82, 0.0, glowAlpha)
            end

            local function resetDragTracking()
                dragLeft = nil
                dragRight = nil
                dragScale = nil
                lastDragCursorX = nil
            end

            local function captureDragBounds()
                dragLeft = slider:GetLeft()
                dragRight = slider:GetRight()
                dragScale = slider:GetEffectiveScale() or 1
                lastDragCursorX = nil
                if not dragLeft or not dragRight or dragRight <= dragLeft or dragScale <= 0 then
                    resetDragTracking()
                end
            end

            local function setValueVisualOnly(v, keepCurrentValue)
                local n = normalize(v)
                if not keepCurrentValue then
                    currentValue = n
                end
                suppress = true
                slider:SetValue(n)
                suppress = false
                valueText:SetText(formatValue(n))
                applyVisualState()
            end

            local function applyValue(v)
                local n = normalize(v)
                if currentValue == n then
                    valueText:SetText(formatValue(n))
                    applyVisualState()
                    return
                end
                currentValue = n
                valueText:SetText(formatValue(n))
                if setter then
                    setter(n)
                end
                if deferApplyUntilMouseUp and dragging then
                    pendingCommit = true
                    if previewCallback then
                        previewCallback(n)
                    end
                    applyVisualState()
                    return
                end
                if commitCallback then
                    pendingCommit = false
                    commitCallback(n)
                elseif onApplyCallback then
                    onApplyCallback()
                end
                applyVisualState()
            end

            local function setValueFromCursor()
                local minSlider, maxSlider = slider:GetMinMaxValues()
                local left = (dragging and dragLeft) or slider:GetLeft()
                local right = (dragging and dragRight) or slider:GetRight()
                if not left or not right or right <= left then
                    return
                end
                local cx = GetCursorPosition()
                local scale = (dragging and dragScale) or (slider:GetEffectiveScale() or 1)
                if not cx or scale <= 0 then
                    return
                end
                cx = cx / scale
                if dragging and lastDragCursorX ~= nil and math.abs(cx - lastDragCursorX) < dragCursorDeadzone then
                    return
                end
                if dragging then
                    lastDragCursorX = cx
                end
                local pct = (cx - left) / (right - left)
                if pct < 0 then pct = 0 end
                if pct > 1 then pct = 1 end
                local raw = minSlider + ((maxSlider - minSlider) * pct)
                local n = normalize(raw)
                if currentValue == n then
                    applyVisualState()
                    return
                end
                setValueVisualOnly(n, true)
                applyValue(n)
            end

            local function commitPendingInteraction()
                if not deferApplyUntilMouseUp or not pendingCommit then
                    return
                end
                pendingCommit = false
                if commitCallback then
                    commitCallback(currentValue)
                end
            end

            local function finishDrag(shouldCommit)
                if not dragging then
                    return
                end
                dragging = false
                resetDragTracking()
                if inputLayer then
                    inputLayer:SetScript("OnUpdate", nil)
                else
                    slider:SetScript("OnUpdate", nil)
                end
                applyVisualState()
                if shouldCommit then
                    commitPendingInteraction()
                end
            end

            slider:SetScript("OnValueChanged", function(selfSlider, value)
                local n = normalize(value)
                if selfSlider:GetValue() ~= n then
                    suppress = true
                    selfSlider:SetValue(n)
                    suppress = false
                end
                valueText:SetText(formatValue(n))
                applyVisualState()
                if suppress or isControlHydrating(selfSlider) or currentValue == n then
                    return
                end
                applyValue(n)
            end)
            local function beginDrag()
                dragging = true
                pendingCommit = false
                if useManualDragTracking then
                    captureDragBounds()
                    setValueFromCursor()
                    inputLayer:SetScript("OnUpdate", function()
                        if dragging then
                            if IsMouseButtonDown and not IsMouseButtonDown("LeftButton") then
                                finishDrag(true)
                                return
                            end
                            setValueFromCursor()
                        end
                    end)
                end
                applyVisualState()
            end

            local function handleEnter()
                hovering = true
                applyVisualState()
            end

            local function handleLeave()
                hovering = false
                applyVisualState()
            end

            if inputLayer then
                inputLayer:SetScript("OnMouseDown", function(_, mouseButton)
                    if mouseButton == "LeftButton" then
                        beginDrag()
                    end
                end)
                inputLayer:SetScript("OnMouseUp", function(_, mouseButton)
                    if mouseButton == "LeftButton" then
                        finishDrag(true)
                    end
                end)
                inputLayer:SetScript("OnEnter", handleEnter)
                inputLayer:SetScript("OnLeave", handleLeave)
                inputLayer:SetScript("OnHide", function()
                    finishDrag(true)
                end)
            else
                slider:SetScript("OnMouseDown", function()
                    beginDrag()
                end)
                slider:SetScript("OnMouseUp", function()
                    finishDrag(true)
                end)
                slider:SetScript("OnEnter", handleEnter)
                slider:SetScript("OnLeave", function()
                    local wasDragging = dragging
                    handleLeave()
                    if wasDragging then
                        finishDrag(true)
                    end
                end)
            end

            container:SetScript("OnHide", function()
                if dragging then
                    finishDrag(true)
                end
            end)

            local spec = {
                label = label,
                control = container,
                slider = slider,
                SetWidth = function(_, width)
                    container:SetWidth(math.max(140, math.floor(tonumber(width) or 220)))
                end,
                Refresh = function()
                    local value = normalize(getter and getter() or minV)
                    currentValue = value
                    pendingCommit = false
                    setValueVisualOnly(value)
                end,
                IsInteracting = function()
                    return dragging
                end,
                CommitPendingInteraction = function()
                    commitPendingInteraction()
                end,
            }
            spec:Refresh()
            return settingsSearchRuntime.registerSpec(spec, "slider")
        end

        local function openInterruptFontColorPicker(onChanged)
            local db = getDB()
            local color = db.fontColor or { r = 1, g = 1, b = 1, a = 1 }
            if ColorPickerFrame and ColorPickerFrame.SetupColorPickerAndShow then
                ColorPickerFrame:SetupColorPickerAndShow({
                    r = color.r,
                    g = color.g,
                    b = color.b,
                    opacity = 1 - color.a,
                    hasOpacity = true,
                    swatchFunc = function()
                        local nr, ng, nb = ColorPickerFrame:GetColorRGB()
                        local alpha = 1 - (OpacitySliderFrame and OpacitySliderFrame:GetValue() or 0)
                        db.fontColor = { r = nr, g = ng, b = nb, a = alpha }
                        if onChanged then onChanged() end
                    end,
                    opacityFunc = function()
                        local nr, ng, nb = ColorPickerFrame:GetColorRGB()
                        local alpha = 1 - (OpacitySliderFrame and OpacitySliderFrame:GetValue() or 0)
                        db.fontColor = { r = nr, g = ng, b = nb, a = alpha }
                        if onChanged then onChanged() end
                    end,
                    cancelFunc = function(previous)
                        db.fontColor = restoreColorPickerPrevious(previous, color)
                        if onChanged then onChanged() end
                    end,
                })
            end
        end

        local function createSubtleCard(parent)
            local card = CreateFrame("Frame", nil, parent, "BackdropTemplate")
            card:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            card:SetBackdropColor(0.06, 0.07, 0.09, 0.42)
            card:SetBackdropBorderColor(0.20, 0.23, 0.29, 0.50)
            return card
        end

        local function createInterruptCardBody(card)
            local body = CreateFrame("Frame", nil, card)
            body:SetAllPoints(card)
            body:SetFrameStrata(card:GetFrameStrata())
            body:SetFrameLevel((card:GetFrameLevel() or 0) + 1)
            return body
        end

        local function syncInterruptCardBody(card, body)
            if not card or not body then
                return
            end
            body:ClearAllPoints()
            body:SetAllPoints(card)
            body:SetFrameStrata(card:GetFrameStrata())
            body:SetFrameLevel((card:GetFrameLevel() or 0) + 1)
        end

        local GUIDED_PREVIEW_ADDON = { 111 / 255, 174 / 255, 107 / 255, 1.0 }
        local GUIDED_PREVIEW_FALLBACK = { 242 / 255, 201 / 255, 76 / 255, 1.0 }
        local GUIDED_PREVIEW_BG_BAR = { 0.09, 0.10, 0.13, 0.88 }
        local GUIDED_PREVIEW_NEUTRAL_BAR = { 0.23, 0.56, 0.88, 0.92 }
        local GUIDED_PREVIEW_ROW_BORDER = { 0.18, 0.21, 0.25, 0.70 }

        local GUIDED_PREVIEW_ROWS = {
            { name = "Yetw", class = "WARRIOR", spellIcon = 132938, accent = "addon", ready = true, count = 9, baseCd = 15, startRemaining = 0, endRemaining = 0 },
            { name = "Artyrka", class = "MAGE", spellIcon = 135856, accent = "addon", ready = false, count = 4, baseCd = 25, startRemaining = 8.4, endRemaining = 3.2 },
            { name = "Deneroc", class = "DEATHKNIGHT", spellIcon = 237527, accent = "fallback", ready = false, count = 2, baseCd = 15, startRemaining = 13.2, endRemaining = 7.6 },
        }

        local clampPreviewNumber = nil

        local function computeInterruptGuidedPreviewGeometry(cardWidth, db)
            local cardTokens = INTERRUPT_LAYOUT.cards
            local previewTokens = INTERRUPT_LAYOUT.preview
            local legendTokens = INTERRUPT_LAYOUT.legend
            local cardInnerW = math.max(0, cardWidth - (cardTokens.PAD * 2))
            local previewTopY = cardTokens.PAD + cardTokens.TITLE_H + cardTokens.TITLE_TO_CONTENT_GAP
            local sampleRowHeight = clampPreviewNumber(db.rowHeight, 30, previewTokens.ROW_H_MIN, previewTokens.ROW_H_MAX)
            local sampleRowGap = clampPreviewNumber(db.rowGap, db.rowGap or 4, 0, previewTokens.ROW_GAP_MAX)
            local sampleDesiredW = clampPreviewNumber(db.width, 198, previewTokens.SAMPLE_WIDTH_MIN, 999)
            local sampleHeight = (sampleRowHeight * #GUIDED_PREVIEW_ROWS) + (sampleRowGap * (#GUIDED_PREVIEW_ROWS - 1))
            local rightDisplay = db.rightDisplay == "timer" and "timer" or "count"
            local valueWidth = rightDisplay == "timer" and previewTokens.TIMER_VALUE_W or previewTokens.COUNT_VALUE_W
            local sideBySideMaxSampleW = math.max(0, cardInnerW - previewTokens.SAMPLE_GAP - legendTokens.MIN_W)
            local legendStacked = sideBySideMaxSampleW < previewTokens.SAMPLE_WIDTH_MIN
            local sampleWidth
            local legendWidth
            if legendStacked then
                sampleWidth = math.max(previewTokens.STACKED_SAMPLE_MIN_W, math.min(sampleDesiredW, cardInnerW))
                legendWidth = cardInnerW
            else
                sampleWidth = math.max(previewTokens.SAMPLE_WIDTH_MIN, math.min(sampleDesiredW, sideBySideMaxSampleW))
                legendWidth = math.max(legendTokens.MIN_W, cardInnerW - sampleWidth - previewTokens.SAMPLE_GAP)
            end
            return {
                cardInnerW = cardInnerW,
                previewTopY = previewTopY,
                sampleRowHeight = sampleRowHeight,
                sampleRowGap = sampleRowGap,
                sampleHeight = sampleHeight,
                sampleWidth = sampleWidth,
                legendWidth = legendWidth,
                legendStacked = legendStacked,
                rightDisplay = rightDisplay,
                valueWidth = valueWidth,
                separatorGap = previewTokens.ICON_SEPARATOR_GAP,
                separatorWidth = previewTokens.ICON_SEPARATOR_W,
            }
        end

        clampPreviewNumber = function(value, defaultValue, minValue, maxValue)
            local numeric = tonumber(value)
            if numeric == nil then
                numeric = tonumber(defaultValue) or 0
            end
            if minValue ~= nil and numeric < minValue then
                numeric = minValue
            end
            if maxValue ~= nil and numeric > maxValue then
                numeric = maxValue
            end
            return numeric
        end

        local function getGuidedPreviewFontPath(db)
            local path = trim(tostring((db and db.fontPath) or ""))
            if path ~= "" then
                return path
            end
            return STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF"
        end

        local function applyGuidedPreviewFont(fontString, db, size, r, g, b, a)
            if not fontString then
                return
            end
            local fontPath = getGuidedPreviewFontPath(db)
            local targetSize = math.max(8, math.floor(tonumber(size) or 12))
            if fontString.SetFont then
                local ok = pcall(fontString.SetFont, fontString, fontPath, targetSize, "")
                if not ok then
                    applyGlobalFontToObject(fontString, targetSize)
                end
            else
                applyGlobalFontToObject(fontString, targetSize)
            end
            fontString:SetTextColor(r or 1, g or 1, b or 1, a or 1)
        end

        local function resolveGuidedPreviewStatusbarPath(value)
            local media = getPortalMedia()
            if media and media.GetChoices then
                for _, option in ipairs(media.GetChoices("statusbar", { currentValue = value }) or {}) do
                    if tostring(option.value or "") == tostring(value or "") then
                        local path = trim(tostring(option.path or ""))
                        if path ~= "" then
                            return path
                        end
                    end
                end
            end
            local raw = trim(tostring(value or ""))
            if raw ~= "" then
                return raw
            end
            return "Interface\\TARGETINGFRAME\\UI-StatusBar"
        end

        local function applyGuidedPreviewClassIcon(texture, classFile)
            if not texture or not classFile or not CLASS_ICON_TCOORDS or not CLASS_ICON_TCOORDS[classFile] then
                return false
            end
            local coords = CLASS_ICON_TCOORDS[classFile]
            texture:SetTexture("Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES")
            texture:SetTexCoord(coords[1] + (4 / 256), coords[2] - (4 / 256), coords[3] + (6 / 256), coords[4] - (4 / 256))
            return true
        end

        local function getGuidedPreviewClassColor(classFile)
            local color = RAID_CLASS_COLORS and RAID_CLASS_COLORS[classFile]
            if color then
                return color.r or 1, color.g or 1, color.b or 1
            end
            return GUIDED_PREVIEW_NEUTRAL_BAR[1], GUIDED_PREVIEW_NEUTRAL_BAR[2], GUIDED_PREVIEW_NEUTRAL_BAR[3]
        end

        local function createGuidedPreviewRow(parent)
            local row = CreateFrame("Frame", nil, parent, "BackdropTemplate")
            row:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            row:SetBackdropColor(GUIDED_PREVIEW_BG_BAR[1], GUIDED_PREVIEW_BG_BAR[2], GUIDED_PREVIEW_BG_BAR[3], GUIDED_PREVIEW_BG_BAR[4])
            row:SetBackdropBorderColor(GUIDED_PREVIEW_ROW_BORDER[1], GUIDED_PREVIEW_ROW_BORDER[2], GUIDED_PREVIEW_ROW_BORDER[3], GUIDED_PREVIEW_ROW_BORDER[4])

            row.barBg = row:CreateTexture(nil, "BACKGROUND")
            row.barBg:SetTexture("Interface\\Buttons\\WHITE8x8")

            row.bar = row:CreateTexture(nil, "ARTWORK")
            row.bar:SetTexture("Interface\\Buttons\\WHITE8x8")

            row.accent = row:CreateTexture(nil, "OVERLAY")
            row.accent:SetColorTexture(1, 1, 1, INTERRUPT_LAYOUT.preview.ACCENT_ALPHA)

            row.classIcon = row:CreateTexture(nil, "ARTWORK")
            row.classIcon:SetTexCoord(0.07, 0.93, 0.07, 0.93)

            row.spellIcon = row:CreateTexture(nil, "ARTWORK")
            row.spellIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)

            row.separator = row:CreateTexture(nil, "OVERLAY")

            row.nameText = createStyledFontString(row, "OVERLAY", "GameFontHighlight", 12)
            row.nameText:SetJustifyH("LEFT")
            row.nameText:SetWordWrap(false)
            if row.nameText.SetMaxLines then
                row.nameText:SetMaxLines(1)
            end

            row.valueText = createStyledFontString(row, "OVERLAY", "GameFontHighlight", 12)
            row.valueText:SetJustifyH("RIGHT")
            row.valueText:SetWordWrap(false)
            if row.valueText.SetMaxLines then
                row.valueText:SetMaxLines(1)
            end

            return row
        end

        local function styleGuidedPreviewHelperText(fontString, size, r, g, b, a)
            if not fontString then
                return
            end
            applyGlobalFontToObject(fontString, size)
            fontString:SetTextColor(r, g, b, a)
            fontString:SetJustifyH("LEFT")
            fontString:SetJustifyV("TOP")
            fontString:SetWordWrap(true)
        end

        local header = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormalLarge", 14)
        header:SetText("|cffffd100Interrupt Tracker|r")
        widgets.sectionDescriptor = createSettingsSectionDescriptor(scrollChild, "Tune interrupt visibility and preview behavior.")

        widgets.lockRowContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.lockRowContainer:SetSize(1, INTERRUPT_LAYOUT.top.LOCK_ROW_FLOOR)
        widgets.masterRowContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.masterRowContainer:SetSize(1, INTERRUPT_LAYOUT.top.LOCK_ROW_FLOOR)
        widgets.lockHelper = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.lockHelper:SetText("")
        widgets.lockHelper:SetTextColor(0.58, 0.58, 0.58, 0.92)
        widgets.lockHelper:SetJustifyH("LEFT")
        widgets.lockHelper:SetWordWrap(false)
        widgets.moduleEnabled = createToggleRow(
            scrollChild,
            "Module",
            function() return getDB().enabled ~= false end,
            function(value) getDB().enabled = value and true or false end,
            "apply_setting"
        )
        self._settingsWindowHeaderToggleSource = widgets.moduleEnabled
        widgets.lockPosition = createLockRow(
            scrollChild,
            function() return getDB().locked end,
            function(value) getDB().locked = value and true or false end,
            "apply_setting"
        )
        widgets.resetAnchor = createActionButton(scrollChild, "Reset Anchor", function()
            local db = getDB()
            db.locked = false
            local module = ensureModule(true)
            if module and module.ResetPositionToCenter then
                pcall(module.ResetPositionToCenter, module)
            end
            applyModuleSettings("apply_setting")
        end, INTERRUPT_LAYOUT.top.RESET_W)
        styleSecondaryActionButtonShared(widgets.resetAnchor, {
            baseBg = { 0.06, 0.07, 0.09, 0.95 },
            hoverBg = { 0.08, 0.09, 0.11, 0.95 },
            pressedBg = { 0.05, 0.06, 0.08, 0.96 },
            baseBorder = { 0.21, 0.24, 0.28, 0.62 },
            hoverBorder = { 0.25, 0.28, 0.33, 0.68 },
            pressedBorder = { 0.23, 0.26, 0.30, 0.66 },
            textColor = { 0.82, 0.83, 0.86, 1 },
        })
        widgets.settingsDivider = scrollChild:CreateTexture(nil, "ARTWORK")
        widgets.settingsDivider:SetColorTexture(0.24, 0.27, 0.32, 0.10)

        widgets.appearanceCard = createSubtleCard(scrollChild)
        widgets.alertCard = createSubtleCard(scrollChild)
        widgets.guidedPreviewCard = createSubtleCard(scrollChild)

        widgets.appearanceHeader = createStyledFontString(widgets.appearanceCard, "ARTWORK", "GameFontHighlight", 12)
        widgets.appearanceHeader:SetText("Appearance")
        widgets.alertHeader = createStyledFontString(widgets.alertCard, "ARTWORK", "GameFontHighlight", 12)
        widgets.alertHeader:SetText("Alerting")
        widgets.guidedPreviewHeader = createStyledFontString(widgets.guidedPreviewCard, "ARTWORK", "GameFontHighlight", 12)
        widgets.guidedPreviewHeader:SetText("Tracker Preview")

        widgets.widthLabel = createStyledFontString(widgets.appearanceCard, "ARTWORK", "GameFontHighlight", 12)
        widgets.widthLabel:SetText("Width")
        widgets.widthStepper = createStepper(
            widgets.appearanceCard,
            160,
            420,
            function() return math.floor(tonumber(getDB().width) or 220) end,
            function(value) getDB().width = math.floor(tonumber(value) or 220) end,
            function() applyModuleSettings("guided_preview_relayout") end
        )

        widgets.rowHeightLabel = createStyledFontString(widgets.appearanceCard, "ARTWORK", "GameFontHighlight", 12)
        widgets.rowHeightLabel:SetText("Row Height")
        widgets.rowHeightStepper = createStepper(
            widgets.appearanceCard,
            18,
            42,
            function() return math.floor(tonumber(getDB().rowHeight) or 22) end,
            function(value) getDB().rowHeight = math.floor(tonumber(value) or 22) end,
            function() applyModuleSettings("guided_preview_relayout") end
        )
        widgets.backgroundOpacity = createInterruptSlider(
            widgets.appearanceCard,
            "Background Opacity",
            0,
            100,
            1,
            function()
                return math.floor(((tonumber(getDB().backgroundOpacity) or 0.88) * 100) + 0.5)
            end,
            function(value)
                getDB().backgroundOpacity = math.max(0, math.min(1, (tonumber(value) or 0) / 100))
            end,
            function() applyModuleSettings("apply_visual_setting") end,
            {
                width = INTERRUPT_LAYOUT.appearance.PICKER_W,
                deferApplyUntilMouseUp = true,
                previewCallback = function()
                    if previewInterruptTrackerBackgroundOpacity then
                        previewInterruptTrackerBackgroundOpacity()
                    end
                end,
                commitCallback = function()
                    applyModuleSettings("apply_visual_setting")
                end,
                formatter = function(value)
                    return string.format("%d%%", math.floor((tonumber(value) or 0) + 0.5))
                end,
            }
        )

        widgets.font = createPickerButton(widgets.appearanceCard, "Font / Size / Color", buildSharedFontPickerChoices, function()
            return tostring(getDB().fontPath or "")
        end, function(value)
            getDB().fontPath = tostring(value or "")
        end, function() applyModuleSettings("apply_visual_setting") end, {
            width = INTERRUPT_LAYOUT.appearance.PICKER_W,
            title = "Select Font Face",
            searchHint = "Search fonts by name",
            pickerWidth = 420,
            pickerHeight = 380,
            useOptionFontPreview = true,
            previewFontSize = 13,
            emptyLabel = "Global UI Font",
        })

        widgets.fontSize = createStepper(
            widgets.appearanceCard,
            8,
            24,
            function() return math.floor(tonumber(getDB().fontSize) or 12) end,
            function(value) getDB().fontSize = math.floor(tonumber(value) or 12) end,
            function() applyModuleSettings("apply_visual_setting") end
        )
        if widgets.fontSize and widgets.fontSize.valueButton and widgets.fontSize.valueEdit then
            widgets.fontSize.valueButton:HookScript("OnClick", function()
                C_Timer.After(0, function()
                    local edit = widgets.fontSize and widgets.fontSize.valueEdit or nil
                    if not edit or not edit.IsShown or not edit:IsShown() then
                        return
                    end
                    if edit.SetFocus then
                        edit:SetFocus()
                    end
                    if edit.HighlightText then
                        edit:HighlightText()
                    end
                end)
            end)
            widgets.fontSize.valueEdit:HookScript("OnShow", function(edit)
                if edit.SetFocus then
                    edit:SetFocus()
                end
                if edit.HighlightText then
                    edit:HighlightText()
                end
            end)
        end
        widgets.fontColorSwatch = CreateFrame("Button", nil, widgets.appearanceCard, "BackdropTemplate")
        widgets.fontColorSwatch:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
            insets = { left = 0, right = 0, top = 0, bottom = 0 },
        })
        widgets.fontColorSwatch:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
        widgets.fontColorSwatch:SetScript("OnClick", function()
            openInterruptFontColorPicker(function()
                applyModuleSettings("apply_visual_setting")
            end)
        end)

        widgets.barTexture = createPickerButton(widgets.appearanceCard, "Bar Texture", function()
            local media = PortalAuthority and PortalAuthority.Media
            return media and media.GetChoices and media.GetChoices("statusbar", { includeCurrent = getDB().barTexture }) or {}
        end, function()
            return tostring(getDB().barTexture or "")
        end, function(value)
            getDB().barTexture = tostring(value or "")
        end, function() applyModuleSettings("apply_visual_setting") end, {
            width = INTERRUPT_LAYOUT.appearance.PICKER_W,
            title = "Select Bar Texture",
            searchHint = "Search textures",
            pickerWidth = 420,
            pickerHeight = 360,
            useOptionTexturePreview = true,
        })

        widgets.useClassColors = createToggleRow(widgets.appearanceCard, "Use Class Colors", function() return getDB().useClassColors end, function(value) getDB().useClassColors = value and true or false end, "apply_visual_setting")
        widgets.showClassIcon = createToggleRow(widgets.appearanceCard, "Show Class Icon", function() return getDB().showClassIcon end, function(value) getDB().showClassIcon = value and true or false end, "guided_preview_relayout")
        widgets.showSpellIcon = createToggleRow(widgets.appearanceCard, "Show Interrupt Icon", function() return getDB().showSpellIcon end, function(value) getDB().showSpellIcon = value and true or false end, "guided_preview_relayout")

        widgets.alertSound = createPickerButton(widgets.alertCard, "Alert Sound", function()
            local media = PortalAuthority and PortalAuthority.Media
            return media and media.GetChoices and media.GetChoices("sound", {
                includeCurrent = getDB().alertSound,
                includeNone = true,
                noneLabel = "None",
            }) or {}
        end, function()
            return getDB().alertSound
        end, function(value)
            getDB().alertSound = value == nil and "" or value
        end, function() applyModuleSettings("apply_setting") end, {
            width = INTERRUPT_LAYOUT.alert.PICKER_W,
            title = "Select Alert Sound",
            searchHint = "Search sounds",
            pickerWidth = 420,
            pickerHeight = 360,
            emptyLabel = "None",
            onRightClick = function(value)
                previewInterruptTrackerAlertSoundValue(value)
            end,
            onOptionRightClick = function(value)
                previewInterruptTrackerAlertSoundValue(value)
            end,
            footerHint = "Right-click previews. Left-click selects.",
        })
        widgets.alertScope = createPremiumSegmentedChoice(widgets.alertCard, "Scope", nil, {
            { label = "All", value = false },
            { label = "Self", value = true },
        }, function(value)
            getDB().selfOnlyAlert = value and true or false
            applyModuleSettings("apply_setting")
        end, {
            semantic = "selection",
            normalizeValue = function(value)
                return value and true or false
            end,
            getValue = function()
                return getDB().selfOnlyAlert
            end,
            setValue = function(value)
                getDB().selfOnlyAlert = value and true or false
            end,
        })

        widgets.rightDisplay = createPremiumSegmentedChoice(widgets.appearanceCard, "Row Value", nil, {
            { label = "Interrupt Count", value = "count" },
            { label = "CD Timer", value = "timer" },
        }, function(value)
            getDB().rightDisplay = value == "timer" and "timer" or "count"
            applyModuleSettings("guided_preview_relayout")
        end, {
            semantic = "selection",
            normalizeValue = function(value)
                return value == "timer" and "timer" or "count"
            end,
            getValue = function()
                return getDB().rightDisplay
            end,
            setValue = function(value)
                getDB().rightDisplay = value == "timer" and "timer" or "count"
            end,
        })

        widgets.guidedPreviewSample = CreateFrame("Frame", nil, widgets.guidedPreviewCard)
        widgets.guidedPreviewRows = {}
        for _ = 1, #GUIDED_PREVIEW_ROWS do
            widgets.guidedPreviewRows[#widgets.guidedPreviewRows + 1] = createGuidedPreviewRow(widgets.guidedPreviewSample)
        end

        widgets.guidedPreviewLegend = CreateFrame("Frame", nil, widgets.guidedPreviewCard)
        widgets.guidedPreviewGreenSwatch = widgets.guidedPreviewLegend:CreateTexture(nil, "ARTWORK")
        widgets.guidedPreviewGoldSwatch = widgets.guidedPreviewLegend:CreateTexture(nil, "ARTWORK")
        widgets.guidedPreviewGreenText = createStyledFontString(widgets.guidedPreviewLegend, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.guidedPreviewGoldText = createStyledFontString(widgets.guidedPreviewLegend, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.guidedPreviewIconChip = widgets.guidedPreviewLegend:CreateTexture(nil, "ARTWORK")
        widgets.guidedPreviewValueChip = widgets.guidedPreviewLegend:CreateTexture(nil, "ARTWORK")
        widgets.guidedPreviewIconNote = createStyledFontString(widgets.guidedPreviewLegend, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.guidedPreviewValueNote = createStyledFontString(widgets.guidedPreviewLegend, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.guidedPreviewSortNote = createStyledFontString(widgets.guidedPreviewCard, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.guidedPreviewLimitNote = createStyledFontString(widgets.guidedPreviewCard, "ARTWORK", "GameFontHighlightSmall", 10)

        styleGuidedPreviewHelperText(widgets.guidedPreviewGreenText, 10, 0.86, 0.88, 0.92, 0.98)
        styleGuidedPreviewHelperText(widgets.guidedPreviewGoldText, 10, 0.86, 0.88, 0.92, 0.98)
        styleGuidedPreviewHelperText(widgets.guidedPreviewIconNote, 9, 0.72, 0.74, 0.78, 0.92)
        styleGuidedPreviewHelperText(widgets.guidedPreviewValueNote, 9, 0.72, 0.74, 0.78, 0.92)
        styleGuidedPreviewHelperText(widgets.guidedPreviewSortNote, 9, 0.56, 0.58, 0.62, 0.88)
        styleGuidedPreviewHelperText(widgets.guidedPreviewLimitNote, 9, 0.56, 0.58, 0.62, 0.88)

        widgets.guidedPreviewGreenSwatch:SetColorTexture(GUIDED_PREVIEW_ADDON[1], GUIDED_PREVIEW_ADDON[2], GUIDED_PREVIEW_ADDON[3], 1)
        widgets.guidedPreviewGoldSwatch:SetColorTexture(GUIDED_PREVIEW_FALLBACK[1], GUIDED_PREVIEW_FALLBACK[2], GUIDED_PREVIEW_FALLBACK[3], 1)
        widgets.guidedPreviewIconChip:SetColorTexture(0.38, 0.42, 0.48, 0.95)
        widgets.guidedPreviewValueChip:SetColorTexture(0.38, 0.42, 0.48, 0.95)

        local GUIDED_PREVIEW_RELAYOUT_SOURCES = {
            hidden_refresh = true,
            on_show = true,
            size_changed = true,
            registered_refresh = true,
            guided_preview_relayout = true,
        }

        local function isGuidedPreviewRelayoutSource(source)
            return GUIDED_PREVIEW_RELAYOUT_SOURCES[tostring(source or "")] and true or false
        end

        local INTERRUPT_PREVIEW_DIRECT_EDIT_SOURCES = {
            apply_setting = true,
            apply_visual_setting = true,
            guided_preview_relayout = true,
            guided_preview_repaint = true,
        }

        local function isInterruptPreviewDirectEditSource(source)
            return INTERRUPT_PREVIEW_DIRECT_EDIT_SOURCES[tostring(source or "")] and true or false
        end

        local function mergeInterruptPreviewRefreshSource(current, incoming)
            local incomingKey = tostring(incoming or "")
            if incomingKey == "" then
                return tostring(current or "")
            end
            if isGuidedPreviewRelayoutSource(incomingKey) then
                return incomingKey
            end
            local currentKey = tostring(current or "")
            if isGuidedPreviewRelayoutSource(currentKey) then
                return currentKey
            end
            return incomingKey
        end

        local function invalidateInterruptPreviewRefresh()
            panelRef._interruptQueuedPreviewReason = nil
            panelRef._interruptPreviewRefreshPending = nil
            panelRef._interruptPreviewRefreshToken = (tonumber(panelRef._interruptPreviewRefreshToken) or 0) + 1
        end

        local function canRunGuidedPreviewTicker()
            if not panelRef or not panelRef._initialized then
                return false
            end
            if panelRef._interruptClosing or panelRef._paSettingsClosing then
                return false
            end
            if not panelRef.IsShown or not panelRef:IsShown() then
                return false
            end
            if settingsFirstOpenHost.selectedPanel ~= panelRef then
                return false
            end
            if settingsFirstOpenHost.selectedKey ~= "interrupt" then
                return false
            end
            if getDB().enabled == false then
                return false
            end
            return interruptTrackerHasFullContent(panelRef)
        end

        local function isGuidedPreviewTickerActive()
            return panelRef and panelRef._guidedPreviewTicker ~= nil
        end

        local function queueInterruptTrackerPreviewRefresh(source)
            local sourceKey = tostring(source or "guided_preview_repaint")
            if panelRef._interruptClosing or not panelRef:IsShown() then
                return
            end
            if isControlHydrating(panelRef) then
                return
            end

            panelRef._interruptQueuedPreviewReason = mergeInterruptPreviewRefreshSource(panelRef._interruptQueuedPreviewReason, sourceKey)
            if panelRef._interruptPreviewRefreshPending then
                return
            end

            panelRef._interruptPreviewRefreshPending = true
            local token = (tonumber(panelRef._interruptPreviewRefreshToken) or 0) + 1
            panelRef._interruptPreviewRefreshToken = token
            C_Timer.After(0, function()
                if not panelRef or panelRef._interruptPreviewRefreshToken ~= token then
                    return
                end
                panelRef._interruptPreviewRefreshPending = nil
                local queuedReason = tostring(panelRef._interruptQueuedPreviewReason or sourceKey)
                panelRef._interruptQueuedPreviewReason = nil
                if panelRef._interruptClosing or not panelRef:IsShown() then
                    return
                end
                if isControlHydrating(panelRef) then
                    return
                end
                if panelRef.RefreshGuidedPreview then
                    panelRef:RefreshGuidedPreview(GetTime(), queuedReason)
                end
            end)
        end

        local function StopGuidedPreviewTicker()
            if panelRef._guidedPreviewTicker then
                panelRef._guidedPreviewTicker:Cancel()
                panelRef._guidedPreviewTicker = nil
            end
            panelRef._guidedPreviewTickerToken = (tonumber(panelRef._guidedPreviewTickerToken) or 0) + 1
            panelRef._guidedPreviewCycleStart = nil
        end

        local function StartGuidedPreviewTicker()
            if isGuidedPreviewTickerActive() then
                return true
            end
            if not canRunGuidedPreviewTicker() then
                StopGuidedPreviewTicker()
                return false
            end
            if not (C_Timer and C_Timer.NewTicker) then
                return false
            end

            panelRef._guidedPreviewCycleStart = GetTime()
            local token = (tonumber(panelRef._guidedPreviewTickerToken) or 0) + 1
            panelRef._guidedPreviewTickerToken = token

            local ticker = nil
            ticker = C_Timer.NewTicker(GUIDED_PREVIEW_TICK_INTERVAL, function()
                if not panelRef or panelRef._guidedPreviewTicker ~= ticker then
                    return
                end
                if (tonumber(panelRef._guidedPreviewTickerToken) or 0) ~= token then
                    return
                end
                if not canRunGuidedPreviewTicker() then
                    StopGuidedPreviewTicker()
                    return
                end
                if panelRef.RefreshGuidedPreview then
                    panelRef:RefreshGuidedPreview(GetTime(), "passive_tick")
                end
            end)
            panelRef._guidedPreviewTicker = ticker
            return ticker ~= nil
        end

        local function syncGuidedPreviewTickerState()
            if canRunGuidedPreviewTicker() then
                StartGuidedPreviewTicker()
            else
                StopGuidedPreviewTicker()
            end
        end

        local function RelayoutGuidedPreviewCard()
            if not widgets.guidedPreviewCard then
                return
            end

            local db = getDB()
            local cardTokens = INTERRUPT_LAYOUT.cards
            local previewTokens = INTERRUPT_LAYOUT.preview
            local legendTokens = INTERRUPT_LAYOUT.legend
            local noteTokens = INTERRUPT_LAYOUT.notes
            widgets.guidedPreviewGreenText:SetText("Portal Authority in use \226\128\148 most accurate tracking.")
            widgets.guidedPreviewGoldText:SetText("Tracked without Portal Authority \226\128\148 still works, less precise.")
            widgets.guidedPreviewIconNote:SetText("Icons show class and tracked interrupt.")
            widgets.guidedPreviewValueNote:SetText("Right side shows timer or count from Row Value.")
            widgets.guidedPreviewSortNote:SetText("Rows sort automatically by availability, then remaining cooldown.")
            widgets.guidedPreviewLimitNote:SetText("Permanent cooldown changes from spec/talents are tracked. Conditional reductions are not currently displayed due to WoW API restrictions. Solar Beam shows 60s. Mind Freeze shows 15s.")
            local cardWidth = math.max(0, widgets.guidedPreviewCard:GetWidth() or 0)
            local previewGeo = computeInterruptGuidedPreviewGeometry(cardWidth, db)
            local cardInnerW = previewGeo.cardInnerW
            local sampleHeight = previewGeo.sampleHeight
            local showClassIcon = db.showClassIcon and true or false
            local showSpellIcon = db.showSpellIcon and true or false
            local rightDisplay = previewGeo.rightDisplay
            local iconSize = previewGeo.sampleRowHeight
            local valueWidth = previewGeo.valueWidth
            local separatorGap = previewGeo.separatorGap
            local separatorWidth = previewGeo.separatorWidth
            local legendStacked = previewGeo.legendStacked
            local legendWidth = previewGeo.legendWidth
            local sampleWidth = previewGeo.sampleWidth

            widgets.guidedPreviewSample:ClearAllPoints()
            widgets.guidedPreviewSample:SetPoint("TOPLEFT", widgets.guidedPreviewCard, "TOPLEFT", cardTokens.PAD, -previewGeo.previewTopY)
            widgets.guidedPreviewSample:SetSize(sampleWidth, sampleHeight)

            widgets.guidedPreviewLegend:ClearAllPoints()
            if legendStacked then
                widgets.guidedPreviewLegend:SetPoint("TOPLEFT", widgets.guidedPreviewSample, "BOTTOMLEFT", 0, -previewTokens.SAMPLE_GAP)
            else
                widgets.guidedPreviewLegend:SetPoint("TOPLEFT", widgets.guidedPreviewSample, "TOPRIGHT", previewTokens.SAMPLE_GAP, 0)
            end
            widgets.guidedPreviewLegend:SetSize(math.max(0, legendWidth), legendTokens.SEED_H)

            widgets.guidedPreviewGreenSwatch:ClearAllPoints()
            widgets.guidedPreviewGreenSwatch:SetPoint("TOPLEFT", widgets.guidedPreviewLegend, "TOPLEFT", 0, 0)
            widgets.guidedPreviewGreenSwatch:SetSize(legendTokens.SWATCH_SIZE, legendTokens.SWATCH_SIZE)
            local primaryTextW = math.max(legendTokens.PRIMARY_TEXT_MIN_W, legendWidth - (legendTokens.SWATCH_SIZE + legendTokens.SWATCH_TEXT_GAP))
            widgets.guidedPreviewGreenText:ClearAllPoints()
            widgets.guidedPreviewGreenText:SetPoint("TOPLEFT", widgets.guidedPreviewGreenSwatch, "TOPRIGHT", legendTokens.SWATCH_TEXT_GAP, legendTokens.SWATCH_TEXT_Y)
            widgets.guidedPreviewGreenText:SetWidth(primaryTextW)
            local greenBlockH = math.max(legendTokens.SWATCH_SIZE, measureInterruptFontStringHeight(widgets.guidedPreviewGreenText, legendTokens.SWATCH_SIZE))

            widgets.guidedPreviewGoldSwatch:ClearAllPoints()
            widgets.guidedPreviewGoldSwatch:SetPoint("TOPLEFT", widgets.guidedPreviewLegend, "TOPLEFT", 0, -(greenBlockH + legendTokens.SWATCH_ROW_GAP))
            widgets.guidedPreviewGoldSwatch:SetSize(legendTokens.SWATCH_SIZE, legendTokens.SWATCH_SIZE)
            widgets.guidedPreviewGoldText:ClearAllPoints()
            widgets.guidedPreviewGoldText:SetPoint("TOPLEFT", widgets.guidedPreviewGoldSwatch, "TOPRIGHT", legendTokens.SWATCH_TEXT_GAP, legendTokens.SWATCH_TEXT_Y)
            widgets.guidedPreviewGoldText:SetWidth(primaryTextW)
            local goldBlockH = math.max(legendTokens.SWATCH_SIZE, measureInterruptFontStringHeight(widgets.guidedPreviewGoldText, legendTokens.SWATCH_SIZE))

            local secondaryTop = greenBlockH + legendTokens.SWATCH_ROW_GAP + goldBlockH + legendTokens.SECONDARY_SECTION_GAP
            local secondaryTextW = math.max(legendTokens.PRIMARY_TEXT_MIN_W, legendWidth - legendTokens.SECONDARY_TEXT_RIGHT_PAD)

            widgets.guidedPreviewIconChip:ClearAllPoints()
            widgets.guidedPreviewIconChip:SetPoint("TOPLEFT", widgets.guidedPreviewLegend, "TOPLEFT", 0, -secondaryTop)
            widgets.guidedPreviewIconChip:SetSize(legendTokens.CHIP_W, legendTokens.CHIP_H)
            widgets.guidedPreviewIconNote:ClearAllPoints()
            widgets.guidedPreviewIconNote:SetPoint("LEFT", widgets.guidedPreviewIconChip, "RIGHT", legendTokens.CHIP_TEXT_GAP, 0)
            widgets.guidedPreviewIconNote:SetWidth(secondaryTextW)
            local iconNoteH = math.max(legendTokens.CHIP_H, measureInterruptFontStringHeight(widgets.guidedPreviewIconNote, legendTokens.CHIP_W))

            widgets.guidedPreviewValueChip:ClearAllPoints()
            widgets.guidedPreviewValueChip:SetPoint("TOPLEFT", widgets.guidedPreviewLegend, "TOPLEFT", 0, -(secondaryTop + iconNoteH + noteTokens.LIMIT_NOTE_GAP))
            widgets.guidedPreviewValueChip:SetSize(legendTokens.CHIP_W, legendTokens.CHIP_H)
            widgets.guidedPreviewValueNote:ClearAllPoints()
            widgets.guidedPreviewValueNote:SetPoint("LEFT", widgets.guidedPreviewValueChip, "RIGHT", legendTokens.CHIP_TEXT_GAP, 0)
            widgets.guidedPreviewValueNote:SetWidth(secondaryTextW)
            local valueNoteH = math.max(legendTokens.CHIP_H, measureInterruptFontStringHeight(widgets.guidedPreviewValueNote, legendTokens.CHIP_W))

            local legendHeight = secondaryTop + iconNoteH + noteTokens.LIMIT_NOTE_GAP + valueNoteH
            widgets.guidedPreviewLegend:SetHeight(legendHeight)
            local bodyHeight = legendStacked and (sampleHeight + previewTokens.SAMPLE_GAP + legendHeight) or math.max(sampleHeight, legendHeight)
            local helperTop = previewGeo.previewTopY + bodyHeight + noteTokens.HELPER_GAP

            widgets.guidedPreviewSortNote:ClearAllPoints()
            widgets.guidedPreviewSortNote:SetPoint("TOPLEFT", widgets.guidedPreviewCard, "TOPLEFT", cardTokens.PAD, -helperTop)
            widgets.guidedPreviewSortNote:SetWidth(cardInnerW)
            local sortNoteH = measureInterruptFontStringHeight(widgets.guidedPreviewSortNote, noteTokens.FLOOR)
            widgets.guidedPreviewLimitNote:ClearAllPoints()
            widgets.guidedPreviewLimitNote:SetPoint("TOPLEFT", widgets.guidedPreviewSortNote, "BOTTOMLEFT", 0, -noteTokens.LIMIT_NOTE_GAP)
            widgets.guidedPreviewLimitNote:SetWidth(cardInnerW)
            local limitNoteH = measureInterruptFontStringHeight(widgets.guidedPreviewLimitNote, noteTokens.FLOOR)

            for index, rowDef in ipairs(GUIDED_PREVIEW_ROWS) do
                local row = widgets.guidedPreviewRows[index]
                local topOffset = -((index - 1) * (previewGeo.sampleRowHeight + previewGeo.sampleRowGap))
                local laneX = 0
                local classIconGap = showSpellIcon and 0 or separatorGap
                local spellIconGap = separatorGap
                local separatorStartX, separatorLaneWidth = nil, 0

                row:ClearAllPoints()
                row:SetPoint("TOPLEFT", widgets.guidedPreviewSample, "TOPLEFT", 0, topOffset)
                row:SetSize(sampleWidth, previewGeo.sampleRowHeight)
                row.accent:Hide()

                if showClassIcon then
                    row.classIcon:Show()
                    row.classIcon:ClearAllPoints()
                    row.classIcon:SetPoint("TOPLEFT", row, "TOPLEFT", 0, 0)
                    row.classIcon:SetSize(iconSize, iconSize)
                    applyGuidedPreviewClassIcon(row.classIcon, rowDef.class)
                    laneX = iconSize + classIconGap
                    if classIconGap > 0 then
                        separatorStartX = laneX - classIconGap
                        separatorLaneWidth = classIconGap
                    end
                else
                    row.classIcon:Hide()
                end

                if showSpellIcon then
                    row.spellIcon:Show()
                    row.spellIcon:ClearAllPoints()
                    row.spellIcon:SetPoint("TOPLEFT", row, "TOPLEFT", laneX, 0)
                    row.spellIcon:SetSize(iconSize, iconSize)
                    row.spellIcon:SetTexture(rowDef.spellIcon)
                    row.spellIcon:SetDesaturated(not rowDef.ready)
                    laneX = laneX + iconSize + spellIconGap
                    if spellIconGap > 0 then
                        separatorStartX = laneX - spellIconGap
                        separatorLaneWidth = spellIconGap
                    end
                else
                    row.spellIcon:Hide()
                end

                if separatorStartX and separatorLaneWidth > 0 then
                    local separatorX = separatorStartX + math.floor(((separatorLaneWidth - separatorWidth) * 0.5) + 0.5)
                    row.separator:Show()
                    row.separator:ClearAllPoints()
                    row.separator:SetPoint("TOPLEFT", row, "TOPLEFT", separatorX, -previewTokens.ICON_SEPARATOR_VERTICAL_INSET)
                    row.separator:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", separatorX, previewTokens.ICON_SEPARATOR_VERTICAL_INSET)
                    row.separator:SetWidth(separatorWidth)
                    if rowDef.accent == "fallback" then
                        row.separator:SetColorTexture(GUIDED_PREVIEW_FALLBACK[1], GUIDED_PREVIEW_FALLBACK[2], GUIDED_PREVIEW_FALLBACK[3], 1)
                    else
                        row.separator:SetColorTexture(GUIDED_PREVIEW_ADDON[1], GUIDED_PREVIEW_ADDON[2], GUIDED_PREVIEW_ADDON[3], 1)
                    end
                else
                    row.separator:Hide()
                end

                row._barLeft = laneX
                row._barAreaWidth = math.max(0, sampleWidth - laneX)
                row._valueWidth = valueWidth

                row.barBg:ClearAllPoints()
                row.barBg:SetPoint("TOPLEFT", row, "TOPLEFT", laneX, 0)
                row.barBg:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", 0, 0)
                row.barBg:SetShown(row._barAreaWidth > 0)

                row.bar:ClearAllPoints()
                row.bar:SetPoint("TOPLEFT", row, "TOPLEFT", laneX, 0)
                row.bar:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", laneX, 0)

                row.nameText:ClearAllPoints()
                row.nameText:SetPoint("LEFT", row, "LEFT", laneX + previewTokens.NAME_LEFT_INSET, 0)
                row.nameText:SetPoint("RIGHT", row, "RIGHT", -(valueWidth + previewTokens.NAME_RIGHT_GAP), 0)

                row.valueText:ClearAllPoints()
                row.valueText:SetPoint("RIGHT", row, "RIGHT", -previewTokens.VALUE_RIGHT_INSET, 0)
                row.valueText:SetWidth(valueWidth)
            end

            panelRef._guidedPreviewMetrics = {
                sampleWidth = sampleWidth,
                rowHeight = previewGeo.sampleRowHeight,
                rowGap = previewGeo.sampleRowGap,
                legendWidth = legendWidth,
                legendStacked = legendStacked,
                rightDisplay = rightDisplay,
                showClassIcon = showClassIcon,
                showSpellIcon = showSpellIcon,
                iconSize = iconSize,
                valueWidth = valueWidth,
                requiredHeight = math.ceil(previewGeo.previewTopY + bodyHeight + noteTokens.HELPER_GAP + sortNoteH + noteTokens.LIMIT_NOTE_GAP + limitNoteH + noteTokens.BOTTOM_PAD),
            }
        end

        local function RefreshGuidedPreview(now, source)
            local refreshSource = tostring(source or "guided_preview_repaint")
            if isGuidedPreviewRelayoutSource(refreshSource) or not panelRef._guidedPreviewMetrics then
                RelayoutGuidedPreviewCard()
            end

            local db = getDB()
            local metrics = panelRef._guidedPreviewMetrics or {}
            local rightDisplay = metrics.rightDisplay or (db.rightDisplay == "timer" and "timer" or "count")
            local fontColor = db.fontColor or { r = 1, g = 1, b = 1, a = 1 }
            local bgAlpha = math.max(0, math.min(1, tonumber(db.backgroundOpacity) or 0.88))
            local useClassColors = db.useClassColors and true or false
            local barTexturePath = resolveGuidedPreviewStatusbarPath(db.barTexture)
            local cycleStart = panelRef._guidedPreviewCycleStart or now or GetTime()
            local progress = (((now or GetTime()) - cycleStart) % INTERRUPT_LAYOUT.preview.CYCLE) / INTERRUPT_LAYOUT.preview.CYCLE
            local tickerOnly = refreshSource == "passive_tick"

            for index, rowDef in ipairs(GUIDED_PREVIEW_ROWS) do
                local row = widgets.guidedPreviewRows[index]
                if not row then
                    break
                end

                local remaining = 0
                if not rowDef.ready then
                    remaining = rowDef.startRemaining + ((rowDef.endRemaining - rowDef.startRemaining) * progress)
                    if remaining < 0 then
                        remaining = 0
                    end
                end

                local ratio = rowDef.ready and 1 or math.max(0, math.min(1, remaining / math.max(1, tonumber(rowDef.baseCd) or 1)))
                local barWidth = math.max(0, math.floor(((row._barAreaWidth or 0) * ratio) + 0.5))

                if not tickerOnly then
                    local barR, barG, barB = GUIDED_PREVIEW_NEUTRAL_BAR[1], GUIDED_PREVIEW_NEUTRAL_BAR[2], GUIDED_PREVIEW_NEUTRAL_BAR[3]
                    if useClassColors then
                        barR, barG, barB = getGuidedPreviewClassColor(rowDef.class)
                    end
                    row:SetBackdropColor(GUIDED_PREVIEW_BG_BAR[1], GUIDED_PREVIEW_BG_BAR[2], GUIDED_PREVIEW_BG_BAR[3], bgAlpha)
                    row:SetBackdropBorderColor(GUIDED_PREVIEW_ROW_BORDER[1], GUIDED_PREVIEW_ROW_BORDER[2], GUIDED_PREVIEW_ROW_BORDER[3], GUIDED_PREVIEW_ROW_BORDER[4])
                    row.barBg:SetColorTexture(0.02, 0.03, 0.05, math.max(0.24, bgAlpha * 0.82))
                    row.barBg:SetShown((row._barAreaWidth or 0) > 0)
                    row.bar:SetTexture(barTexturePath)
                    row.bar:SetVertexColor(barR, barG, barB, 0.92)
                    row.nameText:SetText(rowDef.name)
                    applyGuidedPreviewFont(row.nameText, db, db.fontSize, fontColor.r, fontColor.g, fontColor.b, fontColor.a)
                    applyGuidedPreviewFont(row.valueText, db, db.fontSize, fontColor.r, fontColor.g, fontColor.b, fontColor.a)
                end

                row.bar:SetWidth(barWidth)
                row.bar:SetShown(barWidth > 0)
                row.valueText:SetText(rightDisplay == "timer" and (rowDef.ready and "" or string.format("%.1f", remaining)) or tostring(rowDef.count))
            end
        end

        previewInterruptTrackerBackgroundOpacity = function()
            local bgAlpha = math.max(0, math.min(1, tonumber(getDB().backgroundOpacity) or 0.88))

            local module = getModule()
            if module then
                local function previewRuntimeRow(row)
                    if not row or not row.IsShown or not row:IsShown() or not row._displayMember then
                        return
                    end
                    row:SetBackdropColor(INTERRUPT_RUNTIME_BG_BAR[1], INTERRUPT_RUNTIME_BG_BAR[2], INTERRUPT_RUNTIME_BG_BAR[3], bgAlpha)
                    if row.barBg and row.barBg.GetVertexColor and row.barBg.SetVertexColor then
                        local r, g, b = row.barBg:GetVertexColor()
                        row.barBg:SetVertexColor(r or INTERRUPT_RUNTIME_BG_BAR[1], g or INTERRUPT_RUNTIME_BG_BAR[2], b or INTERRUPT_RUNTIME_BG_BAR[3], bgAlpha)
                    elseif row.barBg and row.barBg.SetVertexColor then
                        row.barBg:SetVertexColor(INTERRUPT_RUNTIME_BG_BAR[1], INTERRUPT_RUNTIME_BG_BAR[2], INTERRUPT_RUNTIME_BG_BAR[3], bgAlpha)
                    end
                end

                previewRuntimeRow(module.selfRow)
                for _, row in ipairs(module.rows or {}) do
                    previewRuntimeRow(row)
                end
            end

            for _, row in ipairs(widgets.guidedPreviewRows or {}) do
                if row then
                    row:SetBackdropColor(GUIDED_PREVIEW_BG_BAR[1], GUIDED_PREVIEW_BG_BAR[2], GUIDED_PREVIEW_BG_BAR[3], bgAlpha)
                    if row.barBg and (tonumber(row._barAreaWidth) or 0) > 0 then
                        row.barBg:SetColorTexture(0.02, 0.03, 0.05, math.max(0.24, bgAlpha * 0.82))
                    end
                end
            end
        end

        -- Guided preview controller
        local guidedPreviewController = {
            IsRelayoutSource = isGuidedPreviewRelayoutSource,
            StartTicker = StartGuidedPreviewTicker,
            StopTicker = StopGuidedPreviewTicker,
            RelayoutCard = RelayoutGuidedPreviewCard,
            Refresh = RefreshGuidedPreview,
        }

        panelRef.RefreshGuidedPreview = function(_, now, source)
            guidedPreviewController.Refresh(now or GetTime(), source or "guided_preview_repaint")
        end
        panelRef.StartGuidedPreviewTicker = function()
            return guidedPreviewController.StartTicker()
        end
        panelRef.StopGuidedPreviewTicker = function()
            guidedPreviewController.StopTicker()
        end

        local function syncInterruptStepperVisual(stepper, value)
            if not stepper then
                return
            end
            if stepper.valueEdit and stepper.valueEdit.IsShown and stepper.valueEdit:IsShown() then
                return
            end
            if stepper.SetVisualValue then
                stepper:SetVisualValue(value)
            elseif stepper.Refresh then
                stepper:Refresh()
            end
        end

        local function refreshInterruptSliderVisual(sliderSpec)
            if not sliderSpec then
                return
            end
            if sliderSpec.IsInteracting and sliderSpec:IsInteracting() then
                return
            end
            if sliderSpec.Refresh then
                sliderSpec:Refresh()
            end
        end

        local function refreshInterruptPickerVisual(spec, value, allowFullRefresh)
            if not spec then
                return
            end
            if allowFullRefresh and spec.Refresh then
                spec.Refresh()
                return
            end
            if spec.SetVisualSelectedValue then
                spec:SetVisualSelectedValue(value)
            end
        end

        local function syncInterruptSelectionControl(spec, value, syncLogicalValue)
            if not spec then
                return
            end
            if spec.SetVisualSelectedValue then
                spec:SetVisualSelectedValue(value)
            end
            if syncLogicalValue and spec.SetSelectedValue then
                spec:SetSelectedValue(value, false)
            end
        end

        local function applyInterruptModuleEnabledState(moduleEnabled, soundScopeEnabled)
            setSettingsControlEnabled(widgets.lockPosition, moduleEnabled)
            setSettingsControlEnabled(widgets.resetAnchor, moduleEnabled)
            setSettingsControlEnabled(widgets.widthStepper, moduleEnabled)
            setSettingsControlEnabled(widgets.rowHeightStepper, moduleEnabled)
            setSettingsControlEnabled(widgets.backgroundOpacity, moduleEnabled)
            setSettingsControlEnabled(widgets.font, moduleEnabled)
            setSettingsControlEnabled(widgets.fontSize, moduleEnabled)
            setSettingsControlEnabled(widgets.fontColorSwatch, moduleEnabled)
            setSettingsControlEnabled(widgets.barTexture, moduleEnabled)
            setSettingsControlEnabled(widgets.useClassColors, moduleEnabled)
            setSettingsControlEnabled(widgets.showClassIcon, moduleEnabled)
            setSettingsControlEnabled(widgets.showSpellIcon, moduleEnabled)
            setSettingsControlEnabled(widgets.rightDisplay, moduleEnabled)
            setSettingsControlEnabled(widgets.alertSound, moduleEnabled)
            setSettingsControlEnabled(widgets.alertScope, moduleEnabled and soundScopeEnabled)

            if widgets.lockRowContainer and widgets.lockRowContainer.SetAlpha then
                widgets.lockRowContainer:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.appearanceCard and widgets.appearanceCard.SetAlpha then
                widgets.appearanceCard:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.guidedPreviewCard and widgets.guidedPreviewCard.SetAlpha then
                widgets.guidedPreviewCard:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.alertCard and widgets.alertCard.SetAlpha then
                widgets.alertCard:SetAlpha(moduleEnabled and 1 or 0.55)
            end

            for _, textWidget in ipairs({
                widgets.lockHelper,
                widgets.appearanceHeader,
                widgets.alertHeader,
                widgets.guidedPreviewHeader,
                widgets.widthLabel,
                widgets.rowHeightLabel,
            }) do
                setSettingsTextEnabled(textWidget, moduleEnabled)
            end
        end

        refreshInterruptTrackerPanel = function(reason, opts)
            opts = type(opts) == "table" and opts or {}
            local db = getDB()
            local isFullRefresh = opts.full and true or false
            local guidedPreviewRefreshSource = tostring(opts.guidedPreviewRefreshSource or reason or "guided_preview_repaint")
            local moduleEnabled = db.enabled ~= false

            syncInterruptSelectionControl(widgets.moduleEnabled, moduleEnabled, true)
            syncInterruptSelectionControl(widgets.lockPosition, db.locked, true)
            if moduleEnabled then
                widgets.lockHelper:SetText(db.locked and "Interrupt Tracker is locked." or "Interrupt Tracker is unlocked - drag to reposition.")
            else
                widgets.lockHelper:SetText("Interrupt Tracker is disabled. Re-enable to edit settings.")
            end

            syncInterruptStepperVisual(widgets.widthStepper, math.floor(tonumber(db.width) or 220))
            syncInterruptStepperVisual(widgets.rowHeightStepper, math.floor(tonumber(db.rowHeight) or 22))
            syncInterruptStepperVisual(widgets.fontSize, math.floor(tonumber(db.fontSize) or 12))
            refreshInterruptSliderVisual(widgets.backgroundOpacity)
            refreshInterruptPickerVisual(widgets.font, tostring(db.fontPath or ""), isFullRefresh)
            refreshInterruptPickerVisual(widgets.barTexture, tostring(db.barTexture or ""), isFullRefresh)
            refreshInterruptPickerVisual(widgets.alertSound, db.alertSound, isFullRefresh)

            syncInterruptSelectionControl(widgets.useClassColors, db.useClassColors)
            syncInterruptSelectionControl(widgets.showClassIcon, db.showClassIcon)
            syncInterruptSelectionControl(widgets.showSpellIcon, db.showSpellIcon)
            syncInterruptSelectionControl(widgets.rightDisplay, db.rightDisplay)
            syncInterruptSelectionControl(widgets.alertScope, db.selfOnlyAlert)

            local soundEnabled = trim(tostring(db.alertSound or "")) ~= ""
            if widgets.alertScope and widgets.alertScope.SetEnabled then
                widgets.alertScope:SetEnabled(moduleEnabled and soundEnabled)
            end
            if widgets.alertScope and widgets.alertScope.label and widgets.alertScope.label.SetAlpha then
                widgets.alertScope.label:SetAlpha((moduleEnabled and soundEnabled) and 1 or 0.55)
            end
            applyInterruptModuleEnabledState(moduleEnabled, soundEnabled)

            local color = db.fontColor or { r = 1, g = 1, b = 1, a = 1 }
            widgets.fontColorSwatch:SetBackdropColor(color.r, color.g, color.b, color.a)

            if panelRef and panelRef.RefreshGuidedPreview then
                if isInterruptPreviewDirectEditSource(guidedPreviewRefreshSource) and not isControlHydrating(panelRef) then
                    if isGuidedPreviewTickerActive() and canRunGuidedPreviewTicker() then
                        invalidateInterruptPreviewRefresh()
                        panelRef:RefreshGuidedPreview(GetTime(), guidedPreviewRefreshSource)
                    else
                        queueInterruptTrackerPreviewRefresh(guidedPreviewRefreshSource)
                    end
                else
                    panelRef:RefreshGuidedPreview(GetTime(), guidedPreviewRefreshSource)
                end
            end

            if not moduleEnabled and panelRef and panelRef.StopGuidedPreviewTicker then
                panelRef:StopGuidedPreviewTicker()
            end
            syncGuidedPreviewTickerState()
            refreshSettingsWindowHeaderAccessoryIfHosted(panelRef)
        end

        passiveSyncInterruptTrackerPanel = function(reason)
            if not panelRef:IsShown() then
                return
            end
            refreshInterruptTrackerPanel(reason or "passive_tick", { full = false })
        end

        local function getInterruptRefreshRoute(source)
            local sourceKey = tostring(source or "")
            local isVisible = panelRef:IsShown()
            if sourceKey == "passive_tick" and not isVisible then
                return nil, sourceKey
            end
            if shouldSuppressSettingsFirstOpenExternalRefresh(panelRef) and (sourceKey == "size_changed" or sourceKey == "registered_refresh") then
                return nil, sourceKey
            end

            local mapping = INTERRUPT_TRIGGER_ROUTE_MAP[sourceKey]
            if not mapping then
                if type(debugSettingsLog) == "function" then
                    debugSettingsLog("interrupt tracker unknown refresh trigger:", sourceKey)
                end
                return isVisible and INTERRUPT_ROUTE_VISIBLE_FULL or INTERRUPT_ROUTE_HIDDEN_FULL, sourceKey
            end

            return isVisible and mapping.visible or mapping.hidden, sourceKey
        end

        local function clampInterruptScrollOffset(offset)
            local maxScroll = math.max(0, (scrollChild:GetHeight() or 0) - (scrollFrame:GetHeight() or 0))
            return math.max(0, math.min(tonumber(offset) or 0, maxScroll))
        end

        layoutInterruptTrackerPanel = function(reason, opts)
            opts = type(opts) == "table" and opts or {}
            local panelTokens = INTERRUPT_LAYOUT.panel
            local topTokens = INTERRUPT_LAYOUT.top
            local cardTokens = INTERRUPT_LAYOUT.cards
            local rowTokens = INTERRUPT_LAYOUT.rows
            local appearanceTokens = INTERRUPT_LAYOUT.appearance
            local previewTokens = INTERRUPT_LAYOUT.preview
            local alertTokens = INTERRUPT_LAYOUT.alert
            local db = getDB()
            local useHostedChrome = isPanelUsingCustomSettingsWindowHost(panelRef)
            local contentW = computeInterruptContentWidth(scrollFrame:GetWidth(), self:GetWidth())
            local surfaceGeo = computeInterruptCardFrameGeometry(contentW)
            scrollChild:SetWidth(contentW)

            local headerWidth = computeInterruptHeaderWidth(contentW)
            local y = -panelTokens.TOP_PAD
            if useHostedChrome then
                y = y - SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE
            end

            if useHostedChrome then
                setSettingsWindowChromeVisible(header, false, scrollChild)
                setSettingsWindowChromeVisible(widgets.sectionDescriptor, false, scrollChild)
            else
                setSettingsWindowChromeVisible(header, true)
                setSettingsWindowChromeVisible(widgets.sectionDescriptor, true, scrollChild)
                header:ClearAllPoints()
                header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", panelTokens.HEADER_LEFT, y)
                header:SetWidth(headerWidth)
                if header.SetJustifyH then
                    header:SetJustifyH("LEFT")
                end
                y = y - measureInterruptFontStringHeight(header, panelTokens.HEADER_FLOOR) - topTokens.HEADER_BOTTOM_GAP
                y = layoutSettingsSectionDescriptor(
                    widgets.sectionDescriptor,
                    scrollChild,
                    panelTokens.HEADER_LEFT,
                    y,
                    headerWidth
                )
            end

            widgets.lockHelper:SetText(db.locked and "Interrupt Tracker is locked." or "Interrupt Tracker is unlocked - drag to reposition.")
            local lockLabel = widgets.lockPosition and widgets.lockPosition.label or nil
            local lockGeom = computeInterruptTopBlockLockGeometry(contentW, lockLabel)
            if useHostedChrome then
                setSettingsWindowChromeVisible(widgets.masterRowContainer, false, scrollChild)
                setSettingsWindowChromeVisible(widgets.moduleEnabled and widgets.moduleEnabled.label or nil, false, scrollChild)
                setSettingsWindowChromeVisible(widgets.moduleEnabled and widgets.moduleEnabled.control or nil, false, scrollChild)
            else
                setSettingsWindowChromeVisible(widgets.masterRowContainer, true)
                setSettingsWindowChromeVisible(widgets.moduleEnabled and widgets.moduleEnabled.label or nil, true)
                setSettingsWindowChromeVisible(widgets.moduleEnabled and widgets.moduleEnabled.control or nil, true)
                if widgets.moduleEnabled and widgets.moduleEnabled.Layout then
                    widgets.moduleEnabled:Layout(math.max(lockGeom.toggleW, 150))
                end
                local masterLabel = widgets.moduleEnabled and widgets.moduleEnabled.label or nil
                local masterLabelH = measureInterruptFontStringHeight(masterLabel, topTokens.LABEL_FLOOR)
                local masterToggleH = measureInterruptControlHeight(widgets.moduleEnabled and widgets.moduleEnabled.control, topTokens.LOCK_ROW_FLOOR)
                local masterRowH = math.max(topTokens.LOCK_ROW_FLOOR, masterLabelH, masterToggleH)
                widgets.masterRowContainer:ClearAllPoints()
                widgets.masterRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", panelTokens.CONTENT_LEFT, y)
                widgets.masterRowContainer:SetSize(lockGeom.rowW, masterRowH)
                if masterLabel then
                    masterLabel:ClearAllPoints()
                    masterLabel:SetPoint("LEFT", widgets.masterRowContainer, "LEFT", 0, 0)
                end
                if widgets.moduleEnabled and widgets.moduleEnabled.control then
                    widgets.moduleEnabled.control:ClearAllPoints()
                    widgets.moduleEnabled.control:SetPoint("LEFT", widgets.masterRowContainer, "LEFT", lockGeom.toggleX, 0)
                end
                y = y - masterRowH - 4
            end

            if widgets.lockPosition and widgets.lockPosition.Layout then
                widgets.lockPosition:Layout(lockGeom.toggleW)
            end
            local lockToggleH = measureInterruptControlHeight(widgets.lockPosition and widgets.lockPosition.control, topTokens.LOCK_ROW_FLOOR)
            local lockRowH = math.max(topTokens.LOCK_ROW_FLOOR, lockGeom.labelH, lockToggleH, topTokens.RESET_H)

            widgets.lockRowContainer:ClearAllPoints()
            widgets.lockRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", panelTokens.CONTENT_LEFT, y)
            widgets.lockRowContainer:SetSize(lockGeom.rowW, lockRowH)
            if lockLabel then
                lockLabel:ClearAllPoints()
                lockLabel:SetPoint("LEFT", widgets.lockRowContainer, "LEFT", 0, 0)
            end
            if widgets.lockPosition and widgets.lockPosition.control then
                widgets.lockPosition.control:ClearAllPoints()
                widgets.lockPosition.control:SetPoint("LEFT", widgets.lockRowContainer, "LEFT", lockGeom.toggleX, 0)
            end
            widgets.resetAnchor:ClearAllPoints()
            widgets.resetAnchor:SetSize(topTokens.RESET_W, topTokens.RESET_H)
            widgets.resetAnchor:SetPoint("LEFT", widgets.lockRowContainer, "LEFT", lockGeom.resetX, 0)
            y = y - lockRowH

            widgets.lockHelper:ClearAllPoints()
            widgets.lockHelper:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", panelTokens.CONTENT_LEFT, y - lockGeom.helperGap)
            widgets.lockHelper:SetWidth(math.max(topTokens.HELPER_MIN_W, contentW - panelTokens.CONTENT_LEFT - panelTokens.CONTENT_RIGHT))
            if widgets.lockHelper.SetJustifyH then widgets.lockHelper:SetJustifyH("LEFT") end
            setInterruptSingleLineEllipsis(widgets.lockHelper, widgets.lockHelper:GetText() or "", math.max(topTokens.HELPER_MIN_W, contentW - panelTokens.CONTENT_LEFT - panelTokens.CONTENT_RIGHT))
            local lockHelperH = measureInterruptFontStringHeight(widgets.lockHelper, topTokens.HELPER_FLOOR)
            y = y - lockGeom.helperGap - lockHelperH

            widgets.settingsDivider:ClearAllPoints()
            local dividerY = y - (lockGeom.dividerGap * 0.5)
            widgets.settingsDivider:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", panelTokens.CONTENT_LEFT, dividerY)
            widgets.settingsDivider:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", -panelTokens.CONTENT_RIGHT, dividerY)
            widgets.settingsDivider:SetHeight(topTokens.DIVIDER_H)
            y = y - lockGeom.dividerGap

            local cardX = surfaceGeo.x
            local cardW = surfaceGeo.width
            local cardInnerW = surfaceGeo.innerWidth

            local appearanceH = computeInterruptCardHeight(appearanceTokens.ROW_COUNT, rowTokens.CONTENT_H)
            widgets.appearanceCard:ClearAllPoints()
            widgets.appearanceCard:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", cardX, y)
            widgets.appearanceCard:SetSize(cardW, appearanceH)
            layoutInterruptCardHeader(widgets.appearanceCard, widgets.appearanceHeader)

            local widthRowTop = getInterruptCardRowTop(1)
            local widthControlH = math.max(rowTokens.CONTROL_FLOOR_H, (widgets.widthStepper and widgets.widthStepper.control and widgets.widthStepper.control:GetHeight()) or rowTokens.DEFAULT_CONTROL_H)
            local widthLabelW = math.ceil(widgets.widthLabel:GetStringWidth() or 0)
            local rowHeightLabelW = math.ceil(widgets.rowHeightLabel:GetStringWidth() or 0)
            local appearanceFirstRowGeo = computeInterruptAppearanceFirstRowGeometry(widthLabelW, rowHeightLabelW)
            widgets.widthStepper.control:ClearAllPoints()
            widgets.widthStepper.control:SetPoint("TOPLEFT", widgets.appearanceCard, "TOPLEFT", appearanceFirstRowGeo.widthControlX, widthRowTop)
            widgets.widthStepper.control:SetWidth(appearanceFirstRowGeo.stepperW)
            widgets.widthLabel:ClearAllPoints()
            widgets.widthLabel:SetPoint("LEFT", widgets.appearanceCard, "TOPLEFT", appearanceFirstRowGeo.widthLabelX, widthRowTop - math.floor(widthControlH * 0.5))

            widgets.rowHeightLabel:ClearAllPoints()
            widgets.rowHeightLabel:SetPoint("LEFT", widgets.appearanceCard, "TOPLEFT", appearanceFirstRowGeo.rowHeightLabelX, widthRowTop - math.floor(widthControlH * 0.5))
            widgets.rowHeightStepper.control:ClearAllPoints()
            widgets.rowHeightStepper.control:SetPoint("TOPLEFT", widgets.appearanceCard, "TOPLEFT", appearanceFirstRowGeo.rowHeightControlX, widthRowTop)
            widgets.rowHeightStepper.control:SetWidth(appearanceFirstRowGeo.stepperW)

            layoutInterruptCardRow(widgets.appearanceCard, appearanceTokens.ROW_SLOTS.BACKGROUND_OPACITY, widgets.backgroundOpacity.label, widgets.backgroundOpacity.control, {
                width = appearanceTokens.PICKER_W,
            })
            if widgets.backgroundOpacity.SetWidth then
                widgets.backgroundOpacity:SetWidth(appearanceTokens.PICKER_W)
            end

            local fontSizeControlW = math.max(0, (widgets.fontSize and widgets.fontSize.control and widgets.fontSize.control:GetWidth()) or 0)
            local fontSizeControlH = math.max(rowTokens.CONTROL_FLOOR_H, (widgets.fontSize and widgets.fontSize.control and widgets.fontSize.control:GetHeight()) or rowTokens.DEFAULT_CONTROL_H)
            local fontRowTop = getInterruptCardRowTop(appearanceTokens.ROW_SLOTS.FONT)
            local fontRowGeo = computeInterruptAppearanceFontRowGeometry(cardInnerW, fontSizeControlW)
            layoutInterruptCardRow(widgets.appearanceCard, appearanceTokens.ROW_SLOTS.FONT, widgets.font.label, widgets.font, {
                width = fontRowGeo.pickerW,
                controlX = fontRowGeo.fontControlX,
            })
            if widgets.fontSize and widgets.fontSize.control then
                widgets.fontSize.control:ClearAllPoints()
                widgets.fontSize.control:SetPoint("TOPLEFT", widgets.appearanceCard, "TOPLEFT", fontRowGeo.fontSizeX, fontRowTop)
            end
            widgets.fontColorSwatch:ClearAllPoints()
            widgets.fontColorSwatch:SetPoint("LEFT", widgets.appearanceCard, "TOPLEFT", fontRowGeo.swatchX, fontRowTop - math.floor(fontSizeControlH * 0.5))
            widgets.fontColorSwatch:SetSize(
                (FIXED_FOOTPRINTS and FIXED_FOOTPRINTS.FONT_COLOR_SWATCH_SIZE) or appearanceTokens.FONT_SWATCH_FALLBACK_SIZE,
                (FIXED_FOOTPRINTS and FIXED_FOOTPRINTS.FONT_COLOR_SWATCH_SIZE) or appearanceTokens.FONT_SWATCH_FALLBACK_SIZE
            )

            layoutInterruptCardRow(widgets.appearanceCard, appearanceTokens.ROW_SLOTS.BAR_TEXTURE, widgets.barTexture.label, widgets.barTexture, {
                width = appearanceTokens.PICKER_W,
            })
            layoutInterruptCardRow(widgets.appearanceCard, appearanceTokens.ROW_SLOTS.USE_CLASS_COLORS, widgets.useClassColors.label, widgets.useClassColors, {
                layoutWidth = appearanceTokens.SEGMENTED_W,
            })
            layoutInterruptCardRow(widgets.appearanceCard, appearanceTokens.ROW_SLOTS.SHOW_CLASS_ICON, widgets.showClassIcon.label, widgets.showClassIcon, {
                layoutWidth = appearanceTokens.SEGMENTED_W,
            })
            layoutInterruptCardRow(widgets.appearanceCard, appearanceTokens.ROW_SLOTS.SHOW_SPELL_ICON, widgets.showSpellIcon.label, widgets.showSpellIcon, {
                layoutWidth = appearanceTokens.SEGMENTED_W,
            })
            layoutInterruptCardRow(widgets.appearanceCard, appearanceTokens.ROW_SLOTS.RIGHT_DISPLAY, widgets.rightDisplay.label, widgets.rightDisplay, {
                layoutWidth = appearanceTokens.RIGHT_DISPLAY_W,
            })
            y = y - appearanceH - cardTokens.SECTION_GAP

            widgets.guidedPreviewCard:ClearAllPoints()
            widgets.guidedPreviewCard:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", cardX, y)
            widgets.guidedPreviewCard:SetSize(cardW, previewTokens.CARD_MIN_H)
            layoutInterruptCardHeader(widgets.guidedPreviewCard, widgets.guidedPreviewHeader)
            if isGuidedPreviewRelayoutSource(reason) or not panelRef._guidedPreviewMetrics or math.abs((tonumber(panelRef._guidedPreviewCardWidth) or 0) - cardW) > 0.5 then
                guidedPreviewController.RelayoutCard()
            end
            panelRef._guidedPreviewCardWidth = cardW
            local guidedCardH = math.max((panelRef._guidedPreviewMetrics and panelRef._guidedPreviewMetrics.requiredHeight) or previewTokens.CARD_MIN_H, previewTokens.CARD_MIN_H)
            widgets.guidedPreviewCard:SetHeight(guidedCardH)
            y = y - guidedCardH - cardTokens.SECTION_GAP

            local alertH = computeInterruptCardHeight(1, rowTokens.CONTENT_H)
            widgets.alertCard:ClearAllPoints()
            widgets.alertCard:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", cardX, y)
            widgets.alertCard:SetSize(cardW, alertH)
            layoutInterruptCardHeader(widgets.alertCard, widgets.alertHeader)

            local alertRowTop = getInterruptCardRowTop(alertTokens.ROW_SLOTS.SOUND)
            if widgets.alertScope and widgets.alertScope.Layout then
                widgets.alertScope:Layout(alertTokens.SCOPE_CONTROL_W)
            end
            local scopeLabelWidth = math.ceil((widgets.alertScope and widgets.alertScope.label and widgets.alertScope.label:GetStringWidth()) or 0)
            local alertRowGeo = computeInterruptAlertRowGeometry(cardInnerW, scopeLabelWidth)
            layoutInterruptCardRow(widgets.alertCard, alertTokens.ROW_SLOTS.SOUND, widgets.alertSound.label, widgets.alertSound, {
                width = alertRowGeo.pickerW,
            })
            local alertControlH = math.max(rowTokens.CONTROL_FLOOR_H, widgets.alertSound.control:GetHeight() or rowTokens.DEFAULT_CONTROL_H)
            if widgets.alertScope then
                widgets.alertScope.label:ClearAllPoints()
                widgets.alertScope.label:SetPoint("LEFT", widgets.alertCard, "TOPLEFT", alertRowGeo.scopeLabelX, alertRowTop - math.floor(alertControlH * 0.5))
                widgets.alertScope.control:ClearAllPoints()
                widgets.alertScope.control:SetPoint("TOPLEFT", widgets.alertCard, "TOPLEFT", alertRowGeo.scopeControlX, alertRowTop)
            end
            y = y - alertH - cardTokens.SECTION_GAP

            local used = math.abs(y) + panelTokens.BOTTOM_PAD
            scrollChild:SetHeight(math.max(scrollFrame:GetHeight(), used))
            updateScrollBehavior(scrollFrame, scrollChild)

            if opts.preserveScroll then
                scrollFrame:SetVerticalScroll(clampInterruptScrollOffset(opts.previousScroll))
            elseif tostring(reason or "") == "on_show" then
                scrollFrame:SetVerticalScroll(0)
            end
        end

        local function runInterruptTrackerHiddenFullRefresh(source)
            layoutInterruptTrackerPanel(source or "hidden_refresh")
            refreshInterruptTrackerPanel(source or "hidden_refresh", {
                full = true,
                afterLayout = true,
            })
        end

        local function runInterruptTrackerVisibleFullLayout(source)
            local sourceKey = tostring(source or "on_show")
            local preserveScroll = sourceKey ~= "on_show"
            local previousScroll = preserveScroll and (tonumber(scrollFrame:GetVerticalScroll()) or 0) or 0
            layoutInterruptTrackerPanel(sourceKey, {
                preserveScroll = preserveScroll,
                previousScroll = previousScroll,
            })
            refreshInterruptTrackerPanel(sourceKey, {
                full = true,
                afterLayout = true,
            })
        end

        routeInterruptTrackerRefresh = function(source)
            local route, sourceKey = getInterruptRefreshRoute(source)
            if not route then
                return
            end
            if route == INTERRUPT_ROUTE_PASSIVE then
                passiveSyncInterruptTrackerPanel(sourceKey)
            elseif route == INTERRUPT_ROUTE_VISIBLE_FULL then
                if panelRef:IsShown() then
                    runInterruptTrackerVisibleFullLayout(sourceKey)
                else
                    runInterruptTrackerHiddenFullRefresh(sourceKey)
                end
            else
                runInterruptTrackerHiddenFullRefresh(sourceKey)
            end
        end

        -- Layout / refresh controllers
        local layoutController = {
            ClampScrollOffset = clampInterruptScrollOffset,
            Layout = layoutInterruptTrackerPanel,
        }
        local refreshController = {
            SyncStepperVisual = syncInterruptStepperVisual,
            RefreshSliderVisual = refreshInterruptSliderVisual,
            RefreshPickerVisual = refreshInterruptPickerVisual,
            SyncSelectionControl = syncInterruptSelectionControl,
            Refresh = refreshInterruptTrackerPanel,
            PassiveSync = passiveSyncInterruptTrackerPanel,
            GetRoute = getInterruptRefreshRoute,
            RunHiddenFullRefresh = runInterruptTrackerHiddenFullRefresh,
            RunVisibleFullLayout = runInterruptTrackerVisibleFullLayout,
            Route = routeInterruptTrackerRefresh,
        }

        self._layout = layoutController.Layout
        self._refresh = refreshController.Refresh
        self._routeInterruptTrackerRefresh = refreshController.Route
        self._runInterruptTrackerVisibleFullLayout = refreshController.RunVisibleFullLayout
        self._invalidateInterruptPreviewRefresh = invalidateInterruptPreviewRefresh
        self._settingsFirstOpenKey = "interrupt"
        self._settingsFirstOpenSizeTarget = scrollFrame
        self._settingsFirstOpenRender = function(panel, source)
            if panel and panel._runInterruptTrackerVisibleFullLayout then
                panel._runInterruptTrackerVisibleFullLayout(source or "on_show")
            elseif panel and panel._routeInterruptTrackerRefresh then
                panel._routeInterruptTrackerRefresh(source or "on_show")
            end
        end
        self._settingsFirstOpenIsReady = interruptTrackerHasFullContent
        registerRefreshCallback(function()
            if shouldSuppressSettingsFirstOpenExternalRefresh(panelRef) then
                return
            end
            if refreshController.Route then
                refreshController.Route("registered_refresh")
            end
        end, panelRef)
        scrollFrame:SetScript("OnSizeChanged", function()
            if handleSettingsFirstOpenSizeReady(panelRef, "size_changed") then
                return
            end
            if shouldSuppressSettingsFirstOpenExternalRefresh(panelRef) then
                return
            end
            if refreshController.Route then
                refreshController.Route("size_changed")
            end
        end)
        self._initialized = true
        settingsSearchRuntime.endDescriptorCapture(self)
        if refreshController.Route and not (self.IsShown and self:IsShown()) then
            refreshController.Route("hidden_refresh")
        end
    end

    panel:SetScript("OnShow", function(self)
        if not self._paAnchored then
            local parent = self:GetParent()
            if parent then
                self:ClearAllPoints()
                self:SetAllPoints(parent)
                self._paAnchored = true
            end
        end
        self._interruptClosing = false
        self:EnsureBuilt()
        if not handleSettingsFirstOpenPanelShow(self) then
            if self._runInterruptTrackerVisibleFullLayout then
                withPanelHydration(self, function()
                    self._runInterruptTrackerVisibleFullLayout("on_show")
                end)
            elseif self._routeInterruptTrackerRefresh then
                withPanelHydration(self, function()
                    self._routeInterruptTrackerRefresh("on_show")
                end)
            end
        end
    end)

    panel:HookScript("OnHide", function(self)
        self._interruptClosing = true
        handleSettingsFirstOpenPanelHide(self)
        if self._invalidateInterruptPreviewRefresh then
            self._invalidateInterruptPreviewRefresh()
        end
        if self.StopGuidedPreviewTicker then
            self:StopGuidedPreviewTicker()
        end
    end)

    return panel
end

local function createKeystoneUtilityPanel()
    local panel = CreateFrame("Frame")
    panel.name = "Keystone Utility"
    panel._paSearchSectionKey = "keystone"
    panel._paSearchSectionName = panel.name
    local ensureKeystonePanelAnchored
    local renderKeystoneWhenReady
    local keystoneHasSizedViewport
    local startKeystoneRenderBootstrap

    panel.EnsureBuilt = function(self)
        if self._initialized and self._layout and self._refresh then return end
        ensureDatabase()
        if not PortalAuthorityDB then
            return
        end
        settingsSearchRuntime.beginDescriptorCapture(self)

        local scrollFrame, scrollChild = createScrollableChild(self)
        if not scrollFrame or not scrollChild then
            settingsSearchRuntime.endDescriptorCapture(self)
            return
        end
        self._sizingFrame = scrollFrame
        self._kuScrollChild = scrollChild
        local widgets = {}
        local panelRef = self

        local function onApply()
            if PortalAuthority and PortalAuthority.ApplyKeystoneUtilitySettings then
                PortalAuthority:ApplyKeystoneUtilitySettings()
            end
            if panelRef and panelRef._refresh then
                panelRef._refresh()
            end
        end

        local header = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormalLarge", 14)
        header:SetText("|cffffd100Keystone Utility|r")
        widgets.sectionDescriptor = createSettingsSectionDescriptor(scrollChild, "Configure keystone assistant behavior and automation.")

        local helperHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        helperHeader:SetText("Keystone Assistant")

        local function createSubtleCard(parent)
            local card = CreateFrame("Frame", nil, parent, "BackdropTemplate")
            card:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            card:SetBackdropColor(0.06, 0.07, 0.09, 0.42)
            card:SetBackdropBorderColor(0.20, 0.23, 0.29, 0.82)
            return card
        end

        local function createStatusChip(parent, titleText)
            local chip = CreateFrame("Frame", nil, parent, "BackdropTemplate")
            chip:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            chip:SetBackdropColor(0.09, 0.10, 0.13, 0.86)
            chip:SetBackdropBorderColor(0.23, 0.26, 0.31, 0.90)
            chip:SetSize(108, 34)

            chip.title = createStyledFontString(chip, "ARTWORK", "GameFontHighlightSmall", 10)
            chip.title:SetPoint("TOPLEFT", chip, "TOPLEFT", 8, -5)
            chip.title:SetPoint("TOPRIGHT", chip, "TOPRIGHT", -8, -5)
            chip.title:SetJustifyH("LEFT")
            chip.title:SetTextColor(0.72, 0.74, 0.78, 0.94)
            chip.title:SetText(titleText or "")

            chip.value = createStyledFontString(chip, "ARTWORK", "GameFontHighlightSmall", 11)
            chip.value:SetPoint("BOTTOMLEFT", chip, "BOTTOMLEFT", 8, 5)
            chip.value:SetPoint("BOTTOMRIGHT", chip, "BOTTOMRIGHT", -8, 5)
            chip.value:SetJustifyH("LEFT")
            chip.value:SetTextColor(0.86, 0.88, 0.92, 1)
            chip.value:SetText("")

            function chip:SetState(text, tone)
                self.value:SetText(tostring(text or ""))
                if tone == "good" then
                    self.value:SetTextColor(0.74, 0.94, 0.76, 1)
                    self:SetBackdropBorderColor(0.20, 0.39, 0.23, 0.90)
                elseif tone == "warn" then
                    self.value:SetTextColor(0.94, 0.84, 0.58, 1)
                    self:SetBackdropBorderColor(0.44, 0.34, 0.18, 0.90)
                else
                    self.value:SetTextColor(0.86, 0.88, 0.92, 1)
                    self:SetBackdropBorderColor(0.23, 0.26, 0.31, 0.90)
                end
            end

            return chip
        end

        local disabledEnabledChoices = {
            { label = "Disabled", value = false, toggleState = "off" },
            { label = "Enabled", value = true, toggleState = "on" },
        }
        local modifierChoices = {
            { label = "Shift", value = "SHIFT" },
            { label = "Ctrl", value = "CTRL" },
        }

        local function createKUSettingSegment(labelText, choices, getter, setter, opts)
            opts = type(opts) == "table" and opts or {}
            local internalValue = getter and getter() or nil
            local segmented = createPremiumSegmentedChoice(
                scrollChild,
                labelText or "",
                nil,
                choices or {},
                function(value)
                    internalValue = value
                    if setter then
                        setter(value)
                    end
                    onApply()
                end,
                {
                    semantic = opts.semantic or "toggle",
                    normalizeValue = opts.normalizeValue,
                    getValue = function()
                        return internalValue
                    end,
                    setValue = function(value)
                        internalValue = value
                    end,
                    controlHeight = 22,
                    textSize = 11,
                    minWidth = opts.minWidth or 170,
                    segmentGap = opts.segmentGap or 4,
                    segmentMinWidth = opts.segmentMinWidth or 48,
                }
            )
            local spec = {}
            spec.label = segmented.label
            spec.control = segmented.control
            spec.buttons = segmented.buttons
            spec.Layout = function(_, width)
                segmented:Layout(width)
            end
            spec.SetEnabled = function(_, enabled)
                segmented:SetEnabled(enabled and true or false)
            end
            spec.SetVisualSelectedValue = function(_, value)
                internalValue = value
                segmented:SetVisualSelectedValue(value)
            end
            spec.Refresh = function()
                if getter then
                    local v = getter()
                    internalValue = v
                    segmented:SetVisualSelectedValue(v)
                end
            end
            return spec
        end

        widgets.assistantCard = createSubtleCard(scrollChild)
        widgets.releaseCard = createSubtleCard(scrollChild)
        widgets.topSectionDivider = scrollChild:CreateTexture(nil, "ARTWORK")
        widgets.topSectionDivider:SetColorTexture(0.24, 0.27, 0.32, 0.10)

        widgets.statusStrip = CreateFrame("Frame", nil, widgets.assistantCard)
        widgets.statusKeystone = createStatusChip(widgets.statusStrip, "Keystone")
        widgets.statusLeader = createStatusChip(widgets.statusStrip, "Leader/Assist")
        widgets.statusAutomation = createStatusChip(widgets.statusStrip, "Automation")

        widgets.keystoneHelperEnabled = createKUSettingSegment(
            "Enable Keystone Assistant",
            disabledEnabledChoices,
            function() return PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.keystoneHelperEnabled) end,
            function(value)
                if PortalAuthorityDB then
                    PortalAuthorityDB.keystoneHelperEnabled = PA_SafeBool(value)
                end
            end,
            { semantic = "toggle" }
        )
        local helperDesc = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        helperDesc:SetText("Adds Readycheck and Pull buttons to the Keystone window.")
        helperDesc:SetTextColor(0.72, 0.72, 0.72, 1)
        helperDesc:SetJustifyH("LEFT")

        widgets.keystoneAutoSlotEnabled = createKUSettingSegment(
            "Auto Slot Keystone",
            disabledEnabledChoices,
            function() return PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.keystoneAutoSlotEnabled) end,
            function(value)
                if PortalAuthorityDB then
                    PortalAuthorityDB.keystoneAutoSlotEnabled = PA_SafeBool(value)
                end
            end,
            { semantic = "toggle" }
        )
        local autoSlotDesc = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        autoSlotDesc:SetText("When the keystone receptacle opens, attempts to slot your keystone automatically.")
        autoSlotDesc:SetTextColor(0.72, 0.72, 0.72, 1)
        autoSlotDesc:SetJustifyH("LEFT")

        widgets.keystoneAutoStartEnabled = createKUSettingSegment(
            "Auto Start Key after Pull",
            disabledEnabledChoices,
            function() return PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.keystoneAutoStartEnabled) end,
            function(value)
                if PortalAuthorityDB then
                    PortalAuthorityDB.keystoneAutoStartEnabled = PA_SafeBool(value)
                end
            end,
            { semantic = "toggle" }
        )
        local autoStartDesc = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        autoStartDesc:SetText("When a pull countdown ends, attempts to start the key (out of combat).")
        autoStartDesc:SetTextColor(0.72, 0.72, 0.72, 1)
        autoStartDesc:SetJustifyH("LEFT")

        local releaseHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        releaseHeader:SetText("Release Spirit Rules")

        widgets.releaseGateEnabled = createKUSettingSegment(
            "Hide Release Spirit (Hold-to-Release)",
            disabledEnabledChoices,
            function() return PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.releaseGateEnabled) end,
            function(value)
                if PortalAuthorityDB then
                    PortalAuthorityDB.releaseGateEnabled = PA_SafeBool(value)
                end
            end,
            { semantic = "toggle" }
        )
        local releaseEnabledDesc = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        releaseEnabledDesc:SetText("Hides Release Spirit until you hold a modifier. Does not affect resurrection prompts.")
        releaseEnabledDesc:SetTextColor(0.72, 0.72, 0.72, 1)
        releaseEnabledDesc:SetJustifyH("LEFT")

        local function normalizeModifier(value)
            local raw = string.upper(trim(tostring(value or "")))
            if raw == "CTRL" then
                return "CTRL"
            end
            return "SHIFT"
        end

        widgets.releaseGateModifier = createKUSettingSegment(
            "Reveal Modifier",
            modifierChoices,
            function() return normalizeModifier(PortalAuthorityDB and PortalAuthorityDB.releaseGateModifier) end,
            function(value)
                if PortalAuthorityDB then
                    PortalAuthorityDB.releaseGateModifier = normalizeModifier(value)
                end
            end,
            {
                semantic = "selection",
                normalizeValue = normalizeModifier,
                minWidth = 120,
                segmentMinWidth = 54,
            }
        )

        local holdLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        holdLabel:SetText("Hold (sec)")
        local HOLD_STEP = 0.05
        local HOLD_SHIFT_MULTIPLIER = 5
        local HOLD_MIN = 0.00
        local HOLD_MAX = 5.00
        local holdCurrentValue = nil
        local holdEditing = false
        local holdControlEnabled = true
        widgets.releaseHoldStepper = CreateFrame("Frame", nil, scrollChild)
        widgets.releaseHoldStepper:SetSize(84, 22)

        local holdStepperBg = CreateFrame("Frame", nil, widgets.releaseHoldStepper, "BackdropTemplate")
        holdStepperBg:SetPoint("TOPLEFT", widgets.releaseHoldStepper, "TOPLEFT", 0, 0)
        holdStepperBg:SetPoint("BOTTOMRIGHT", widgets.releaseHoldStepper, "BOTTOMRIGHT", 0, 0)
        holdStepperBg:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
            insets = { left = 0, right = 0, top = 0, bottom = 0 },
        })
        holdStepperBg:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
        holdStepperBg:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)

        local function createHoldArrow(symbol)
            local btn = CreateFrame("Button", nil, widgets.releaseHoldStepper)
            btn:SetSize(12, 16)
            btn._text = createStyledFontString(btn, "ARTWORK", "GameFontHighlight", 11)
            btn._text:SetPoint("CENTER", btn, "CENTER", 0, 0)
            btn._text:SetText(symbol)
            btn._text:SetTextColor(0.74, 0.74, 0.76, 1)
            btn:SetScript("OnEnter", function(selfBtn)
                selfBtn._text:SetTextColor(0.95, 0.95, 0.98, 1)
            end)
            btn:SetScript("OnLeave", function(selfBtn)
                selfBtn._text:SetTextColor(0.74, 0.74, 0.76, 1)
            end)
            return btn
        end

        local holdMinus = createHoldArrow("<")
        local holdPlus = createHoldArrow(">")
        local holdValueButton = CreateFrame("Button", nil, widgets.releaseHoldStepper)
        holdValueButton:SetSize(40, 16)
        local holdValueText = createStyledFontString(holdValueButton, "ARTWORK", "GameFontHighlightSmall", 11)
        holdValueText:SetPoint("CENTER", holdValueButton, "CENTER", 0, 0)
        holdValueText:SetTextColor(0.86, 0.86, 0.90, 1)
        local holdValueEdit = CreateFrame("EditBox", nil, holdValueButton)
        holdValueEdit:SetAllPoints(holdValueButton)
        holdValueEdit:SetAutoFocus(false)
        holdValueEdit:SetJustifyH("CENTER")
        holdValueEdit:SetTextInsets(0, 0, 0, 0)
        holdValueEdit:SetTextColor(1, 1, 1, 1)
        holdValueEdit:SetHighlightColor(1, 1, 1, 0.25)
        applyGlobalFontToObject(holdValueEdit, 11)
        holdValueEdit:Hide()

        holdMinus:SetPoint("LEFT", widgets.releaseHoldStepper, "LEFT", 6, 0)
        holdValueButton:SetPoint("LEFT", holdMinus, "RIGHT", 4, 0)
        holdPlus:SetPoint("LEFT", holdValueButton, "RIGHT", 4, 0)

        local function normalizeHoldSeconds(value)
            local n = tonumber(value)
            if n == nil then
                local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
                n = tonumber(defaults.releaseGateHoldSeconds) or 1.0
            end
            if n < HOLD_MIN then n = HOLD_MIN end
            if n > HOLD_MAX then n = HOLD_MAX end
            n = math.floor((n / HOLD_STEP) + 0.5) * HOLD_STEP
            n = math.floor((n * 100) + 0.5) / 100
            if n < HOLD_MIN then n = HOLD_MIN end
            if n > HOLD_MAX then n = HOLD_MAX end
            return n
        end

        local function formatHoldSeconds(value)
            return string.format("%.2f", normalizeHoldSeconds(value))
        end

        local function setHoldVisual(value)
            holdCurrentValue = normalizeHoldSeconds(value)
            holdValueText:SetText(formatHoldSeconds(holdCurrentValue))
            if holdEditing then
                holdValueEdit:SetText(formatHoldSeconds(holdCurrentValue))
            end
        end

        local function commitHoldValue(value)
            local clean = normalizeHoldSeconds(value)
            local old = normalizeHoldSeconds(PortalAuthorityDB and PortalAuthorityDB.releaseGateHoldSeconds)
            setHoldVisual(clean)
            if math.abs(clean - old) < 0.0001 then
                return false
            end
            if PortalAuthorityDB then
                PortalAuthorityDB.releaseGateHoldSeconds = clean
            end
            onApply()
            return true
        end

        local function endHoldEdit(commit)
            if not holdEditing then
                return
            end
            holdEditing = false
            if commit then
                local parsed = tonumber(trim(holdValueEdit:GetText() or ""))
                if parsed ~= nil then
                    commitHoldValue(parsed)
                end
            end
            holdValueEdit:Hide()
            holdValueText:Show()
            holdValueEdit:ClearFocus()
            setHoldVisual(holdCurrentValue)
        end

        local function beginHoldEdit()
            if not holdControlEnabled then
                return
            end
            holdEditing = true
            holdValueText:Hide()
            holdValueEdit:SetText(formatHoldSeconds(holdCurrentValue))
            holdValueEdit:Show()
            holdValueEdit:SetFocus()
            holdValueEdit:HighlightText()
        end

        local function setHoldEnabled(enabled)
            holdControlEnabled = enabled and true or false
            widgets.releaseHoldStepper:SetAlpha(holdControlEnabled and 1 or 0.55)
            holdMinus:SetEnabled(holdControlEnabled)
            holdPlus:SetEnabled(holdControlEnabled)
            holdValueButton:SetEnabled(holdControlEnabled)
            if not holdControlEnabled and holdEditing then
                endHoldEdit(false)
            end
        end

        holdMinus:SetScript("OnClick", function()
            if not holdControlEnabled then
                return
            end
            local mult = (IsShiftKeyDown and IsShiftKeyDown()) and HOLD_SHIFT_MULTIPLIER or 1
            commitHoldValue((holdCurrentValue or normalizeHoldSeconds(nil)) - (HOLD_STEP * mult))
        end)
        holdPlus:SetScript("OnClick", function()
            if not holdControlEnabled then
                return
            end
            local mult = (IsShiftKeyDown and IsShiftKeyDown()) and HOLD_SHIFT_MULTIPLIER or 1
            commitHoldValue((holdCurrentValue or normalizeHoldSeconds(nil)) + (HOLD_STEP * mult))
        end)
        holdValueButton:SetScript("OnClick", beginHoldEdit)
        holdValueEdit:SetScript("OnEnterPressed", function(edit)
            endHoldEdit(true)
            edit:ClearFocus()
        end)
        holdValueEdit:SetScript("OnEscapePressed", function(edit)
            endHoldEdit(false)
            edit:ClearFocus()
        end)
        holdValueEdit:SetScript("OnEditFocusLost", function()
            -- Explicit-action only: no commit on focus loss.
            endHoldEdit(false)
        end)

        widgets.releaseHoldStepper.SetEnabled = setHoldEnabled
        widgets.releaseHoldStepper.Refresh = function()
            setHoldVisual(normalizeHoldSeconds(PortalAuthorityDB and PortalAuthorityDB.releaseGateHoldSeconds))
        end
        widgets.releaseHoldStepper.SetVisualValue = setHoldVisual
        setHoldVisual(normalizeHoldSeconds(PortalAuthorityDB and PortalAuthorityDB.releaseGateHoldSeconds))

        local KU_UpdateKeystoneTooltipPreview
        local KU_PositionPreviewTooltip
        local KU_ReadPreviewBodyLeftLines
        local releaseHoldDesc = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        releaseHoldDesc:SetText("Hold the reveal modifier; after holding for this delay, Release Spirit will auto-trigger. Range: 0.00-5.00s (decimals allowed).")
        releaseHoldDesc:SetTextColor(0.72, 0.72, 0.72, 1)
        releaseHoldDesc:SetJustifyH("LEFT")
        local tooltipHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormalLarge", 14)
        tooltipHeader:SetText("|cffffd100Keystone Tooltip|r")
        local tooltipSubheader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        tooltipSubheader:SetText("Tooltip Customization")
        local KEYSTONE_UTILITY_LAYOUT = {
            SCROLL_WIDTH_FUDGE = 8,
            MIN_CONTENT_W = 560,
            HEADER_MIN_W = 220,
            LABEL_MIN_W = 150,
            LABEL_TEXT_PAD = 8,
            LABEL_TO_CONTROL_GAP = 12,
            CONTROL_MIN_W = 170,
            CONTROL_MAX_W = 220,
            CONTROL_WIDTH_RATIO = 0.34,
            DESC_MIN_W = 120,
            DESC_RIGHT_PAD = 10,
            STATUS_CHIP_MIN_W = 92,
            STATUS_CHIP_TEXT_PAD = 20,
            TOOLTIP_LABEL_MIN_W = 64,
            TOOLTIP_LABEL_MAX_W = 140,
            TOOLTIP_LABEL_TEXT_PAD = 8,
            TOOLTIP_LABEL_TO_CONTROL_GAP = 8,
            PAGE = {
                TOP_PAD = 20,
                HEADER_LEFT = 16,
                CONTENT_LEFT = 20,
                CONTENT_RIGHT = 20,
                TITLE_FLOOR = 16,
                TITLE_TO_SECTION_GAP = 8,
                BOTTOM_PAD = 40,
            },
            SECTION = {
                TITLE_FLOOR = 16,
                SUBHEADER_FLOOR = 12,
                SUBHEADER_GAP = 8,
                STACK_GAP = 16,
                DIVIDER_H = 1,
                DIVIDER_Y_OFFSET = 8,
                RELEASE_TO_TOOLTIP_GAP = 20,
                TOOLTIP_TITLE_TO_SUBHEADER_GAP = 6,
                TOOLTIP_SUBHEADER_TO_CONTENT_GAP = 8,
                TOOLTIP_BOTTOM_GAP = 14,
            },
            CARD = {
                PAD_X = 14,
                PAD_TOP = 12,
                PAD_BOTTOM = 12,
                ROW_FLOOR = 22,
                ROW_GAP = 10,
                DESC_GAP = 2,
                LABEL_FLOOR = 12,
                HELPER_FLOOR = 11,
                CONTROL_FLOOR = 22,
                CONTROL_TOP_NUDGE = 1,
            },
            STATUS = {
                STRIP_Y_NUDGE = 2,
                CHIP_H = 34,
                CHIP_GAP = 8,
            },
            TOOLTIP = {
                PANE_GAP = 16,
                STATUS_H = 16,
                ROW_GAP = 8,
                BASE_ROW_H = 30,
                ROW_H_COMPOUND_DROPPED = 68,
                ROW_H_SWATCH_DROPPED = 56,
                INLINE_BLOCK_GAP = 6,
                INLINE_REGION_GAP = 8,
                SUBLINE_MAIN_TO_LABEL_GAP = 2,
                SUBLINE_LABEL_TO_CONTROL_GAP = 2,
                INSPECTOR_PAD_X = 10,
                INSPECTOR_PAD_Y = 2,
                STATUS_TO_CONTENT_GAP = 2,
                MAIN_TOP_PAD = 2,
                SWATCH_GAP = 8,
                TOP_LABEL_Y_INSET = 4,
                SUBLINE_LABEL_X_INSET = 7,
                SUBLINE_LABEL_MIN_W = 72,
                SUBLINE_LABEL_RIGHT_PAD = 14,
                SUBLINE_ACCENT_X_INSET = 2,
                SUBLINE_ACCENT_Y_NUDGE = 1,
                SUBLINE_ACCENT_MIN_H = 12,
                SUBLINE_ACCENT_HEIGHT_PAD = 1,
                DROPPED_ROW_TOP_PAD = 2,
                DROPPED_ROW_BOTTOM_PAD = 4,
                CONTROL_FLOOR = 19,
                INLINE_LABEL_FLOOR = 10,
                TITLE_TOP_PAD = 8,
                PREVIEW_TITLE_FLOOR = 11,
                PREVIEW_TITLE_PAD_X = 10,
                PREVIEW_TITLE_CLEARANCE = 3,
                PREVIEW_FRAME_OFFSET_Y = 8,
                PREVIEW_BODY_TOP_GAP = 7,
                PREVIEW_BODY_PAD_X = 10,
                PREVIEW_BODY_BOTTOM_PAD = 10,
                STICKY_TOP_PAD = 0,
            },
            METRIC_WATCH_INTERVAL = 0.20,
        }
        local TOOLTIP_BUILDER_PREVIEW_MIN_W = 250
        local TOOLTIP_BUILDER_INSPECTOR_MIN_W = 250
        local TOOLTIP_BUILDER_PREVIEW_READABLE_MIN_W = 130
        local TOOLTIP_BUILDER_INSPECTOR_PICKER_W = 190
        local TOOLTIP_BUILDER_INLINE_TOGGLE_W = 88
        local TOOLTIP_BUILDER_INLINE_LABEL_W = 102
        local TOOLTIP_BUILDER_INSPECTOR_RIGHT_INSET = 30
        local TOOLTIP_BUILDER_MAIN_MIN_W = 240
        local TOOLTIP_BUILDER_MAIN_MAX_W = 360
        local TOOLTIP_BUILDER_PREVIEW_H = 260
        local TOOLTIP_BUILDER_CARD_BG_R, TOOLTIP_BUILDER_CARD_BG_G, TOOLTIP_BUILDER_CARD_BG_B, TOOLTIP_BUILDER_CARD_BG_A = 0.06, 0.07, 0.09, 0.90
        local TOOLTIP_BUILDER_CARD_BORDER_R, TOOLTIP_BUILDER_CARD_BORDER_G, TOOLTIP_BUILDER_CARD_BORDER_B, TOOLTIP_BUILDER_CARD_BORDER_A = 0.20, 0.23, 0.29, 0.90
        local TOOLTIP_BUILDER_MUTED_TEXT_R, TOOLTIP_BUILDER_MUTED_TEXT_G, TOOLTIP_BUILDER_MUTED_TEXT_B, TOOLTIP_BUILDER_MUTED_TEXT_A = 0.72, 0.74, 0.78, 0.94
        local TOOLTIP_BUILDER_HIGHLIGHT_BG_R, TOOLTIP_BUILDER_HIGHLIGHT_BG_G, TOOLTIP_BUILDER_HIGHLIGHT_BG_B = 0.24, 0.30, 0.38
        local TOOLTIP_BUILDER_HIGHLIGHT_ACCENT_R, TOOLTIP_BUILDER_HIGHLIGHT_ACCENT_G, TOOLTIP_BUILDER_HIGHLIGHT_ACCENT_B = 0.72, 0.79, 0.92

        local tooltipDungeonNameChoices = {
            { label = "Short Name", value = "SHORT" },
            { label = "Full Name", value = "FULL" },
            { label = "Nickname", value = "NICKNAME" },
            { label = "Nickname - Full Name", value = "NICKNAME_FULL" },
            { label = "Default", value = "NO_CHANGES" },
        }
        local tooltipLevelChoices = {
            { label = "n", value = "N" },
            { label = "+n", value = "PLUS_N" },
            { label = "mn+", value = "M_N_PLUS" },
            { label = "Hide", value = "HIDE" },
            { label = "Default", value = "NO_CHANGES" },
        }
        local tooltipAffixesChoices = {
            { label = "No Changes", value = "NO_CHANGES" },
            { label = "Rename to \"Affixes\"", value = "RENAME_AFFIXES" },
            { label = "Hide", value = "HIDE" },
        }
        local tooltipModifiersSegmentChoices = {
            { label = "Hide", value = "HIDE", toggleState = "off" },
            { label = "Default", value = "NO_CHANGES", toggleState = "on" },
            { label = "Affixes", value = "RENAME_AFFIXES", toggleState = "on" },
        }
        local tooltipHideShowChoices = {
            { label = "Hide", value = "HIDE", toggleState = "off" },
            { label = "Show", value = "NO_CHANGES", toggleState = "on" },
        }
        local tooltipOffOnChoices = {
            { label = "Off", value = false, toggleState = "off" },
            { label = "On", value = true, toggleState = "on" },
        }
        local tooltipPrefixOffOnChoices = {
            -- Inverted mapping (UI intent):
            -- Off => remove "Keystone:" prefix
            -- On  => keep "Keystone:" prefix
            { label = "Off", value = true, toggleState = "off" },
            { label = "On", value = false, toggleState = "on" },
        }
        local tooltipLineConfigs = {
            {
                lineId = "DungeonName",
                label = "Dungeon Name",
                type = "picker",
                dbKey = "keystoneTooltipDungeonNameMode",
                options = tooltipDungeonNameChoices,
                inline = {
                    label = "'Keystone' Prefix",
                    dbKey = "keystoneTooltipRemoveKeystonePrefix",
                    choices = tooltipPrefixOffOnChoices,
                    layout = "subline",
                },
                affectsLayout = true,
            },
            {
                lineId = "Level",
                label = "M+ Level",
                type = "picker",
                dbKey = "keystoneTooltipLevelMode",
                options = tooltipLevelChoices,
                inline = {
                    label = "Append to Name",
                    dbKey = "keystoneTooltipLevelAddToName",
                    choices = tooltipOffOnChoices,
                    layout = "subline",
                },
                affectsLayout = true,
            },
            {
                lineId = "Resilient",
                label = "Resilient Level",
                type = "segmented",
                dbKey = "keystoneTooltipResilientMode",
                choices = tooltipHideShowChoices,
                affectsLayout = true,
            },
            {
                lineId = "Soulbound",
                label = "Soulbound / BOP",
                type = "segmented",
                dbKey = "keystoneTooltipSoulboundMode",
                choices = tooltipHideShowChoices,
                affectsLayout = true,
            },
            {
                lineId = "Unique",
                label = "Unique",
                type = "segmented",
                dbKey = "keystoneTooltipUniqueMode",
                choices = tooltipHideShowChoices,
                affectsLayout = true,
            },
            {
                lineId = "Modifiers",
                label = "Dungeon Modifiers",
                type = "segmented",
                dbKey = "keystoneTooltipAffixesMode",
                choices = tooltipModifiersSegmentChoices,
                affectsLayout = true,
            },
            {
                lineId = "Duration",
                label = "Duration",
                type = "segmented",
                dbKey = "keystoneTooltipDurationMode",
                choices = tooltipHideShowChoices,
                affectsLayout = true,
            },
            {
                lineId = "RPQuote",
                label = "Yellow RP Quote",
                type = "segmented",
                dbKey = "keystoneTooltipRPQuoteMode",
                choices = tooltipHideShowChoices,
                affectsLayout = true,
            },
        }

        local tooltipBuilder = {}
        widgets.tooltipBuilder = tooltipBuilder
        tooltipBuilder.rows = {}
        tooltipBuilder.rowsById = {}
        tooltipBuilder.previewOverlays = {}
        tooltipBuilder.previewOverlaysByLineId = {}
        tooltipBuilder.mappingByLineId = {}
        tooltipBuilder.visibleInspectorLineIds = {}
        tooltipBuilder.visiblePreviewLineIds = {}
        tooltipBuilder.hoveredLineId = nil
        tooltipBuilder.selectedLineId = nil
        tooltipBuilder._lastCommit = nil

        local tooltipBuilderRoot = CreateFrame("Frame", nil, scrollChild)
        tooltipBuilder.root = tooltipBuilderRoot

        tooltipBuilder.inspectorPane = CreateFrame("Frame", nil, tooltipBuilderRoot, "BackdropTemplate")
        tooltipBuilder.inspectorPane:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
            insets = { left = 0, right = 0, top = 0, bottom = 0 },
        })
        tooltipBuilder.inspectorPane:SetBackdropColor(TOOLTIP_BUILDER_CARD_BG_R, TOOLTIP_BUILDER_CARD_BG_G, TOOLTIP_BUILDER_CARD_BG_B, TOOLTIP_BUILDER_CARD_BG_A)
        tooltipBuilder.inspectorPane:SetBackdropBorderColor(TOOLTIP_BUILDER_CARD_BORDER_R, TOOLTIP_BUILDER_CARD_BORDER_G, TOOLTIP_BUILDER_CARD_BORDER_B, TOOLTIP_BUILDER_CARD_BORDER_A)
        if tooltipBuilder.inspectorPane.SetBackdrop then
            tooltipBuilder.inspectorPane:SetBackdrop(nil)
        end

        tooltipBuilder.statusSlot = CreateFrame("Frame", nil, tooltipBuilder.inspectorPane)
        tooltipBuilder.statusSlot:SetHeight(KEYSTONE_UTILITY_LAYOUT.TOOLTIP.STATUS_H)
        tooltipBuilder.statusText = createStyledFontString(tooltipBuilder.statusSlot, "ARTWORK", "GameFontHighlightSmall", 11)
        tooltipBuilder.statusText:SetPoint("TOPLEFT", tooltipBuilder.statusSlot, "TOPLEFT", 0, 0)
        tooltipBuilder.statusText:SetPoint("BOTTOMLEFT", tooltipBuilder.statusSlot, "BOTTOMLEFT", 0, 0)
        tooltipBuilder.statusText:SetJustifyH("LEFT")
        tooltipBuilder.statusText:SetTextColor(TOOLTIP_BUILDER_MUTED_TEXT_R, TOOLTIP_BUILDER_MUTED_TEXT_G, TOOLTIP_BUILDER_MUTED_TEXT_B, 0.88)
        tooltipBuilder.statusText:SetText("")

        tooltipBuilder.inspectorContent = CreateFrame("Frame", nil, tooltipBuilder.inspectorPane)
        tooltipBuilder.inspectorContent:SetSize(1, 1)
        tooltipBuilder.inspectorHeader = createStyledFontString(tooltipBuilder.inspectorContent, "ARTWORK", "GameFontHighlightSmall", 11)
        tooltipBuilder.inspectorHeader:SetText("")
        tooltipBuilder.inspectorHeader:SetTextColor(TOOLTIP_BUILDER_MUTED_TEXT_R, TOOLTIP_BUILDER_MUTED_TEXT_G, TOOLTIP_BUILDER_MUTED_TEXT_B, 0.95)
        tooltipBuilder.inspectorHeader:SetJustifyH("LEFT")
        tooltipBuilder.inspectorHeader:Hide()

        tooltipBuilder.previewPane = CreateFrame("Frame", nil, tooltipBuilderRoot, "BackdropTemplate")
        tooltipBuilder.previewPane:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
            insets = { left = 0, right = 0, top = 0, bottom = 0 },
        })
        tooltipBuilder.previewPane:SetBackdropColor(TOOLTIP_BUILDER_CARD_BG_R, TOOLTIP_BUILDER_CARD_BG_G, TOOLTIP_BUILDER_CARD_BG_B, 0.92)
        tooltipBuilder.previewPane:SetBackdropBorderColor(TOOLTIP_BUILDER_CARD_BORDER_R, TOOLTIP_BUILDER_CARD_BORDER_G, TOOLTIP_BUILDER_CARD_BORDER_B, TOOLTIP_BUILDER_CARD_BORDER_A)
        if tooltipBuilder.previewPane.SetBackdrop then
            tooltipBuilder.previewPane:SetBackdrop(nil)
        end

        tooltipBuilder.previewTitle = createStyledFontString(tooltipBuilder.previewPane, "ARTWORK", "GameFontHighlightSmall", 11)
        tooltipBuilder.previewTitle:SetText("")
        tooltipBuilder.previewTitle:SetTextColor(TOOLTIP_BUILDER_MUTED_TEXT_R, TOOLTIP_BUILDER_MUTED_TEXT_G, TOOLTIP_BUILDER_MUTED_TEXT_B, 0.90)
        tooltipBuilder.previewTitle:Hide()

        widgets.keystoneTooltipPreviewAnchor = CreateFrame("Frame", nil, tooltipBuilder.previewPane, "BackdropTemplate")
        widgets.keystoneTooltipPreviewAnchor:EnableMouse(false)
        widgets.keystoneTooltipPreviewAnchor:SetSize(164, 220)

        widgets.keystoneTooltipPreviewTooltip = CreateFrame("GameTooltip", "PortalAuthority_KeystoneTooltipPreview", widgets.keystoneTooltipPreviewAnchor, "GameTooltipTemplate")
        widgets.keystoneTooltipPreviewTooltip:EnableMouse(false)
        widgets.keystoneTooltipPreviewTooltip:SetClampedToScreen(true)
        widgets.keystoneTooltipPreviewTooltip:SetOwner(widgets.keystoneTooltipPreviewAnchor, "ANCHOR_NONE")
        widgets.keystoneTooltipPreviewTooltip:ClearAllPoints()
        widgets.keystoneTooltipPreviewTooltip:SetPoint("TOPLEFT", widgets.keystoneTooltipPreviewAnchor, "TOPLEFT", 6, -6)

        tooltipBuilder.previewHitLayer = CreateFrame("Frame", nil, tooltipBuilder.previewPane)
        tooltipBuilder.previewHitLayer:SetFrameStrata("TOOLTIP")
        tooltipBuilder.previewHitLayer:SetFrameLevel((widgets.keystoneTooltipPreviewTooltip:GetFrameLevel() or 0) + 50)
        tooltipBuilder.previewHitLayer:EnableMouse(true)

        local function KU_ApplyExternalTooltipSkin(tt)
            if not tt then
                return
            end
            local elv = _G.ElvUI
            local E = nil
            if type(elv) == "table" then
                E = elv[1] or elv
            end
            if E and E.GetModule then
                local okTT, TT = pcall(E.GetModule, E, "Tooltip")
                if okTT and TT and TT.SetStyle then
                    pcall(TT.SetStyle, TT, tt)
                end
            end
        end

        local function refreshTooltipAffixesSwatch()
            local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
            local fallback = defaults.keystoneTooltipAffixesColor or { r = 1, g = 0.82, b = 0, a = 1 }
            local c = PortalAuthorityDB and PortalAuthorityDB.keystoneTooltipAffixesColor or fallback
            local r = tonumber(c and c.r) or fallback.r
            local g = tonumber(c and c.g) or fallback.g
            local b = tonumber(c and c.b) or fallback.b
            local a = tonumber(c and c.a) or fallback.a
            for _, row in ipairs(tooltipBuilder.rows) do
                if row.colorSwatch and row.colorSwatch.SetBackdropColor then
                    row.colorSwatch:SetBackdropColor(r, g, b, a)
                end
            end
        end

        local function openKeystoneTooltipAffixesColorPicker(onChangedFn)
            if not (ColorPickerFrame and ColorPickerFrame.SetupColorPickerAndShow) then
                return
            end
            local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
            local fallback = defaults.keystoneTooltipAffixesColor or { r = 1, g = 0.82, b = 0, a = 1 }
            local cur = PortalAuthorityDB and PortalAuthorityDB.keystoneTooltipAffixesColor or fallback
            local r = tonumber(cur and cur.r) or fallback.r
            local g = tonumber(cur and cur.g) or fallback.g
            local b = tonumber(cur and cur.b) or fallback.b
            local a = tonumber(cur and cur.a) or fallback.a
            ColorPickerFrame:SetupColorPickerAndShow({
                r = r,
                g = g,
                b = b,
                opacity = 1 - a,
                hasOpacity = true,
                swatchFunc = function()
                    local nr, ng, nb = ColorPickerFrame:GetColorRGB()
                    local na = 1 - (OpacitySliderFrame and OpacitySliderFrame:GetValue() or 0)
                    PortalAuthorityDB.keystoneTooltipAffixesColor = { r = nr, g = ng, b = nb, a = na }
                    if onChangedFn then onChangedFn() end
                end,
                opacityFunc = function()
                    local nr, ng, nb = ColorPickerFrame:GetColorRGB()
                    local na = 1 - (OpacitySliderFrame and OpacitySliderFrame:GetValue() or 0)
                    PortalAuthorityDB.keystoneTooltipAffixesColor = { r = nr, g = ng, b = nb, a = na }
                    if onChangedFn then onChangedFn() end
                end,
                cancelFunc = function(prev)
                    PortalAuthorityDB.keystoneTooltipAffixesColor = restoreColorPickerPrevious(prev, fallback)
                    if onChangedFn then onChangedFn() end
                end,
            })
        end

        local function KU_FindFirstKeystoneLinkInBags()
            local firstBag = BACKPACK_CONTAINER or 0
            local lastBag = NUM_TOTAL_EQUIPPED_BAG_SLOTS or 4
            for bag = firstBag, lastBag do
                local slots = 0
                if C_Container and C_Container.GetContainerNumSlots then
                    local okSlots, bagSlots = pcall(C_Container.GetContainerNumSlots, bag)
                    if okSlots then
                        slots = tonumber(bagSlots) or 0
                    end
                end
                for slot = 1, slots do
                    if C_Container and C_Container.GetContainerItemLink then
                        local okLink, link = pcall(C_Container.GetContainerItemLink, bag, slot)
                        if okLink and type(link) == "string" and string.find(link, "|Hkeystone:", 1, true) then
                            return link
                        end
                    end
                end
            end
            return nil
        end

        local function KU_BuildFallbackKeystoneContext()
            local mapID = 0
            local level = 10
            local affixIDs = {}
            local displayName = "Sample Keystone"

            if C_MythicPlus and C_MythicPlus.GetOwnedKeystoneMapID then
                local ok, ownedMapID = pcall(C_MythicPlus.GetOwnedKeystoneMapID)
                if ok then
                    mapID = tonumber(ownedMapID) or mapID
                end
            end
            if mapID <= 0 and C_MythicPlus and C_MythicPlus.GetOwnedKeystoneChallengeMapID then
                local ok, ownedChallengeMapID = pcall(C_MythicPlus.GetOwnedKeystoneChallengeMapID)
                if ok then
                    mapID = tonumber(ownedChallengeMapID) or mapID
                end
            end
            if mapID <= 0 and C_ChallengeMode and C_ChallengeMode.GetActiveChallengeMapID then
                local ok, activeMapID = pcall(C_ChallengeMode.GetActiveChallengeMapID)
                if ok then
                    mapID = tonumber(activeMapID) or mapID
                end
            end
            if mapID <= 0 and C_ChallengeMode and C_ChallengeMode.GetMapTable then
                local ok, mapTable = pcall(C_ChallengeMode.GetMapTable)
                if ok and type(mapTable) == "table" then
                    for _, v in ipairs(mapTable) do
                        local n = tonumber(v) or 0
                        if n > 0 then
                            mapID = n
                            break
                        end
                    end
                end
            end

            if C_MythicPlus and C_MythicPlus.GetOwnedKeystoneLevel then
                local ok, ownedLevel = pcall(C_MythicPlus.GetOwnedKeystoneLevel)
                if ok then
                    local n = tonumber(ownedLevel) or 0
                    if n > 0 then
                        level = n
                    end
                end
            end

            if C_MythicPlus and C_MythicPlus.GetCurrentAffixes then
                local ok, currentAffixes = pcall(C_MythicPlus.GetCurrentAffixes)
                if ok and type(currentAffixes) == "table" then
                    for _, a in ipairs(currentAffixes) do
                        local id = 0
                        if type(a) == "table" then
                            id = tonumber(a.id) or tonumber(a.affixID) or tonumber(a[1]) or 0
                        else
                            id = tonumber(a) or 0
                        end
                        if id > 0 then
                            affixIDs[#affixIDs + 1] = id
                            if #affixIDs >= 3 then
                                break
                            end
                        end
                    end
                end
            end
            if #affixIDs == 0 and C_ChallengeMode and C_ChallengeMode.GetAffixInfo then
                for id = 1, 200 do
                    local ok, name = pcall(C_ChallengeMode.GetAffixInfo, id)
                    if ok and type(name) == "string" and trim(name) ~= "" then
                        affixIDs[#affixIDs + 1] = id
                        if #affixIDs >= 3 then
                            break
                        end
                    end
                end
            end

            if mapID > 0 and C_ChallengeMode and C_ChallengeMode.GetMapUIInfo then
                local ok, name = pcall(C_ChallengeMode.GetMapUIInfo, mapID)
                if ok and type(name) == "string" and trim(name) ~= "" then
                    displayName = trim(name)
                end
            end

            return mapID, level, affixIDs, displayName
        end

        local function KU_BuildFallbackKeystoneHyperlink(mapID, level, affixIDs)
            local safeMapID = tonumber(mapID) or 0
            local safeLevel = tonumber(level) or 10
            if safeLevel <= 0 then
                safeLevel = 10
            end

            local affixParts = {}
            if type(affixIDs) == "table" then
                for i = 1, math.min(#affixIDs, 3) do
                    local n = tonumber(affixIDs[i]) or 0
                    if n > 0 then
                        affixParts[#affixParts + 1] = tostring(n)
                    end
                end
            end
            local affixSuffix = (#affixParts > 0) and (":" .. table.concat(affixParts, ":")) or ""
            return string.format("|cffa335ee|Hkeystone:180653:%d:%d%s|h[Keystone]|h|r", safeMapID, safeLevel, affixSuffix)
        end

        local function KU_SeedFallbackPreviewLines(previewTooltip, displayName, level, affixIDs)
            if not previewTooltip then
                return
            end
            previewTooltip:ClearLines()
            previewTooltip:AddLine("Mythic Keystone", 0.64, 0.21, 0.93)
            previewTooltip:AddLine("Keystone: " .. (displayName or "Sample Keystone"), 1, 1, 1)
            previewTooltip:AddLine("Mythic Level: " .. tostring(math.floor(tonumber(level) or 10)), 1, 1, 1)
            previewTooltip:AddLine("Resilient Level: 2", 1, 1, 1)
            previewTooltip:AddLine("Soulbound", 1, 1, 1)
            previewTooltip:AddLine("Unique", 1, 1, 1)
            previewTooltip:AddLine("Dungeon Modifiers", 1, 1, 1)

            if type(affixIDs) == "table" then
                for i = 1, math.min(#affixIDs, 3) do
                    local affixID = tonumber(affixIDs[i]) or 0
                    if affixID > 0 then
                        local affixName = nil
                        if C_ChallengeMode and C_ChallengeMode.GetAffixInfo then
                            local ok, name = pcall(C_ChallengeMode.GetAffixInfo, affixID)
                            if ok and type(name) == "string" and trim(name) ~= "" then
                                affixName = trim(name)
                            end
                        end
                        previewTooltip:AddLine("- " .. (affixName or ("Affix " .. tostring(affixID))), 1, 1, 1)
                    end
                end
            end

            previewTooltip:AddLine("Duration: 33:00", 1, 1, 1)
            previewTooltip:AddLine("Your fate awaits.", 1, 0.82, 0)
        end

        local function KU_ApplyPreviewWordWrap(tooltip, previewAnchor)
            if not tooltip or not tooltip.GetName then
                return
            end
            local baseName = tooltip:GetName()
            if type(baseName) ~= "string" or baseName == "" then
                return
            end
            local anchorW = 0
            if previewAnchor and previewAnchor.GetWidth then
                anchorW = tonumber(previewAnchor:GetWidth()) or 0
            end
            if tooltipBuilder and tooltipBuilder.previewPane and tooltipBuilder.previewPane.GetWidth then
                local paneW = tonumber(tooltipBuilder.previewPane:GetWidth()) or 0
                if paneW > 0 then
                    anchorW = math.max(anchorW, paneW - 20)
                end
            end
            if anchorW <= 0 then
                anchorW = 280
            end
            local maxW = anchorW - 20
            if maxW < 240 then maxW = 240 end
            if maxW > 280 then maxW = 280 end

            if tooltip.SetWidth then
                pcall(tooltip.SetWidth, tooltip, maxW)
            end
            local textW = maxW - 20
            for i = 1, (tooltip.NumLines and tooltip:NumLines() or 0) do
                local left = _G[baseName .. "TextLeft" .. i]
                local right = _G[baseName .. "TextRight" .. i]
                if left then
                    if left.SetWidth then pcall(left.SetWidth, left, textW) end
                    if left.SetWordWrap then pcall(left.SetWordWrap, left, true) end
                    if left.SetNonSpaceWrap then pcall(left.SetNonSpaceWrap, left, true) end
                end
                if right then
                    if right.SetWidth then pcall(right.SetWidth, right, textW) end
                    if right.SetWordWrap then pcall(right.SetWordWrap, right, true) end
                    if right.SetNonSpaceWrap then pcall(right.SetNonSpaceWrap, right, true) end
                end
            end
        end

        local function KU_FitPreviewTooltipFrameToContent(tooltip)
            if not tooltip or not tooltip.GetName then
                return
            end
            local baseName = tooltip:GetName()
            if type(baseName) ~= "string" or baseName == "" then
                return
            end

            local minLeft, maxRight, minBottom, maxTop
            local sumLineH = 0
            for i = 1, (tooltip.NumLines and tooltip:NumLines() or 0) do
                local left = _G[baseName .. "TextLeft" .. i]
                local right = _G[baseName .. "TextRight" .. i]
                local leftShown = left and left.IsShown and left:IsShown() and trim(left:GetText() or "") ~= ""
                local rightShown = right and right.IsShown and right:IsShown() and trim(right:GetText() or "") ~= ""
                if leftShown then
                    local l, r, t, b = left:GetLeft(), left:GetRight(), left:GetTop(), left:GetBottom()
                    if l and r and t and b then
                        minLeft = minLeft and math.min(minLeft, l) or l
                        maxRight = maxRight and math.max(maxRight, r) or r
                        maxTop = maxTop and math.max(maxTop, t) or t
                        minBottom = minBottom and math.min(minBottom, b) or b
                    end
                end
                if rightShown then
                    local l, r, t, b = right:GetLeft(), right:GetRight(), right:GetTop(), right:GetBottom()
                    if l and r and t and b then
                        minLeft = minLeft and math.min(minLeft, l) or l
                        maxRight = maxRight and math.max(maxRight, r) or r
                        maxTop = maxTop and math.max(maxTop, t) or t
                        minBottom = minBottom and math.min(minBottom, b) or b
                    end
                end
                if leftShown or rightShown then
                    local leftH = (left and left.GetStringHeight and tonumber(left:GetStringHeight())) or 0
                    local rightH = (right and right.GetStringHeight and tonumber(right:GetStringHeight())) or 0
                    local lineH = math.max(leftH, rightH, 12)
                    sumLineH = sumLineH + lineH + 2
                end
            end

            local targetW, targetH
            if minLeft and maxRight and maxTop and minBottom then
                targetW = math.max(1, math.ceil((maxRight - minLeft) + 20))
                targetH = math.max(1, math.ceil((maxTop - minBottom) + 14))
            end
            if sumLineH > 0 then
                local byStringH = math.max(1, math.ceil(sumLineH + 14))
                if targetH then
                    targetH = math.max(targetH, byStringH)
                else
                    targetH = byStringH
                end
            end
            if targetW and tooltip.SetWidth then
                pcall(tooltip.SetWidth, tooltip, targetW)
            end
            if targetH and tooltip.SetHeight then
                pcall(tooltip.SetHeight, tooltip, targetH)
            end
        end

        local function KU_RequestPreviewSettle(tooltip, previewAnchor)
            if not tooltip then
                return
            end
            tooltip._paPreviewSettleAnchor = previewAnchor
            tooltip._paPreviewSettlePasses = 90
            local settleDriver = tooltipBuilder and tooltipBuilder.previewSettleDriver or nil
            if settleDriver then
                settleDriver._elapsed = 0
                settleDriver:Show()
            end
        end

        local function KU_RunPreviewSettleStep(tooltip)
            if not tooltip then
                return
            end
            local anchor = tooltip._paPreviewSettleAnchor or widgets.keystoneTooltipPreviewAnchor
            if not anchor then
                tooltip._paPreviewSettlePasses = 0
                return
            end
            KU_ApplyPreviewWordWrap(tooltip, anchor)
            tooltip:Show()
            KU_FitPreviewTooltipFrameToContent(tooltip)
            KU_PositionPreviewTooltip(tooltip, anchor)
            tooltip._paPreviewSettlePasses = (tonumber(tooltip._paPreviewSettlePasses) or 1) - 1
            if (tooltip._paPreviewSettlePasses or 0) < 0 then
                tooltip._paPreviewSettlePasses = 0
            end
        end

        if not tooltipBuilder.previewSettleDriver then
            local settleDriver = CreateFrame("Frame", nil, tooltipBuilder.previewPane)
            settleDriver:Hide()
            settleDriver:SetScript("OnUpdate", function(selfDriver, elapsed)
                selfDriver._elapsed = (tonumber(selfDriver._elapsed) or 0) + (tonumber(elapsed) or 0)
                if selfDriver._elapsed < 0.08 then
                    return
                end
                selfDriver._elapsed = 0
                if not panelRef or not panelRef.IsShown or not panelRef:IsShown() then
                    selfDriver:Hide()
                    return
                end
                local tt = widgets and widgets.keystoneTooltipPreviewTooltip or nil
                local anchor = widgets and widgets.keystoneTooltipPreviewAnchor or nil
                if tt and tt.IsShown and tt:IsShown() and anchor then
                    if (tonumber(tt._paPreviewSettlePasses) or 0) > 0 then
                        KU_RunPreviewSettleStep(tt)
                    else
                        KU_ApplyPreviewWordWrap(tt, anchor)
                        KU_FitPreviewTooltipFrameToContent(tt)
                        KU_PositionPreviewTooltip(tt, anchor)
                    end
                end
            end)
            tooltipBuilder.previewSettleDriver = settleDriver
            panelRef._kuTooltipPreviewSettleDriver = settleDriver
        end

        KU_UpdateKeystoneTooltipPreview = function()
            local previewAnchor = widgets.keystoneTooltipPreviewAnchor
            local previewTooltip = widgets.keystoneTooltipPreviewTooltip
            if not previewAnchor or not previewTooltip then
                return
            end
            KU_ApplyExternalTooltipSkin(previewTooltip)

            local link = KU_FindFirstKeystoneLinkInBags()
            previewTooltip:SetOwner(previewAnchor, "ANCHOR_NONE")
            previewTooltip:ClearAllPoints()
            previewTooltip:SetPoint("TOPLEFT", previewAnchor, "TOPLEFT", 6, -6)
            previewTooltip:ClearLines()

            if type(link) ~= "string" then
                local mapID, level, affixIDs, displayName = KU_BuildFallbackKeystoneContext()
                local fallbackLink = KU_BuildFallbackKeystoneHyperlink(mapID, level, affixIDs)
                local okSet = false
                if previewTooltip.SetHyperlink and type(fallbackLink) == "string" then
                    okSet = pcall(previewTooltip.SetHyperlink, previewTooltip, fallbackLink)
                end
                if not okSet then
                    KU_SeedFallbackPreviewLines(previewTooltip, displayName, level, affixIDs)
                end
                if PortalAuthority and PortalAuthority.KeystoneTooltip_OnItemTooltip then
                    PortalAuthority:KeystoneTooltip_OnItemTooltip(previewTooltip, { hyperlink = fallbackLink })
                end
                KU_ApplyPreviewWordWrap(previewTooltip, previewAnchor)
                previewTooltip:Show()
                KU_RequestPreviewSettle(previewTooltip, previewAnchor)
                KU_RunPreviewSettleStep(previewTooltip)
                return
            end

            previewTooltip:SetHyperlink(link)
            if PortalAuthority and PortalAuthority.KeystoneTooltip_OnItemTooltip then
                PortalAuthority:KeystoneTooltip_OnItemTooltip(previewTooltip, { hyperlink = link })
            end
            KU_ApplyPreviewWordWrap(previewTooltip, previewAnchor)
            previewTooltip:Show()
            KU_RequestPreviewSettle(previewTooltip, previewAnchor)
            KU_RunPreviewSettleStep(previewTooltip)
        end

        local function KU_Normalize(v)
            local ok, s = pcall(tostring, v)
            if not ok or s == nil then
                return ""
            end
            s = trim(tostring(s))
            if s == "" then
                return ""
            end
            return string.upper(s)
        end

        local KU_RefreshTooltipBuilderVisual = nil
        panelRef._kuHydrateKeystoneTooltipControls = function()
            if KU_RefreshTooltipBuilderVisual then
                KU_RefreshTooltipBuilderVisual()
            end
        end
        panelRef._kuHydrateKeystoneTooltipVisualOnly = panelRef._kuHydrateKeystoneTooltipControls
        panelRef._kuRefreshHoldForce = function()
            if widgets.releaseHoldStepper and widgets.releaseHoldStepper.Refresh then
                widgets.releaseHoldStepper:Refresh()
            end
        end
        panelRef._commitHoldIfDirty = nil

        KU_PositionPreviewTooltip = function(previewTooltip, previewAnchor)
            if not previewTooltip or not previewAnchor then
                return
            end
            local x = 6
            local y = -8
            previewTooltip:ClearAllPoints()
            previewTooltip:SetPoint("TOPLEFT", previewAnchor, "TOPLEFT", x, y)
        end

        if widgets.keystoneTooltipPreviewTooltip
            and widgets.keystoneTooltipPreviewTooltip.HasScript
            and widgets.keystoneTooltipPreviewTooltip:HasScript("OnTooltipSetItem")
        then
            widgets.keystoneTooltipPreviewTooltip:HookScript("OnTooltipSetItem", function(tt)
                local anchor = widgets.keystoneTooltipPreviewAnchor
                if not anchor then return end
                KU_RequestPreviewSettle(tt, anchor)
                KU_RunPreviewSettleStep(tt)
            end)
        end
        if widgets.keystoneTooltipPreviewTooltip
            and widgets.keystoneTooltipPreviewTooltip.HasScript
            and widgets.keystoneTooltipPreviewTooltip:HasScript("OnShow")
        then
            widgets.keystoneTooltipPreviewTooltip:HookScript("OnShow", function(tt)
                local anchor = widgets.keystoneTooltipPreviewAnchor
                if not anchor then return end
                if (tonumber(tt._paPreviewSettlePasses) or 0) <= 0 then
                    KU_RequestPreviewSettle(tt, anchor)
                end
            end)
        end
        if widgets.keystoneTooltipPreviewTooltip
            and widgets.keystoneTooltipPreviewTooltip.HasScript
            and widgets.keystoneTooltipPreviewTooltip:HasScript("OnUpdate")
        then
            widgets.keystoneTooltipPreviewTooltip:HookScript("OnUpdate", function(tt)
                if (tonumber(tt._paPreviewSettlePasses) or 0) > 0 then
                    KU_RunPreviewSettleStep(tt)
                end
            end)
        end
        if widgets.keystoneTooltipPreviewTooltip
            and widgets.keystoneTooltipPreviewTooltip.HasScript
            and widgets.keystoneTooltipPreviewTooltip:HasScript("OnHide")
        then
            widgets.keystoneTooltipPreviewTooltip:HookScript("OnHide", function(tt)
                tt._paPreviewSettlePasses = 0
            end)
        end

        local function KU_SetBuilderStatus(text)
            local value = trim(tostring(text or ""))
            tooltipBuilder.statusText:SetText(value)
        end

        local function KU_ClearBuilderStatus()
            KU_SetBuilderStatus("")
        end

        local function KU_ValuesEqual(a, b)
            if type(a) == "boolean" or type(b) == "boolean" then
                return PA_SafeBool(a) == PA_SafeBool(b)
            end
            return KU_Normalize(a) == KU_Normalize(b)
        end

        local function KU_ResolveVisualChoice(rawValue, choices)
            for _, choice in ipairs(choices or {}) do
                if KU_ValuesEqual(choice.value, rawValue) then
                    return choice.value, choice.label
                end
            end
            for _, choice in ipairs(choices or {}) do
                if KU_Normalize(choice.value) == "NO_CHANGES" then
                    return choice.value, choice.label
                end
            end
            local first = choices and choices[1]
            if first then
                return first.value, first.label
            end
            return nil, ""
        end

        local function KU_SetRowHighlight(row, hovered, selected)
            if not row then
                return
            end
            if selected then
                row.highlightBg:SetAlpha(0.12)
                row.highlightAccent:SetAlpha(0.34)
            elseif hovered then
                row.highlightBg:SetAlpha(0.07)
                row.highlightAccent:SetAlpha(0)
            else
                row.highlightBg:SetAlpha(0)
                row.highlightAccent:SetAlpha(0)
            end
        end

        local function KU_SetOverlayHighlight(overlay, hovered, selected)
            if not overlay then
                return
            end
            if selected then
                overlay._bg:SetAlpha(0.12)
                overlay._accent:SetAlpha(0.34)
            elseif hovered then
                overlay._bg:SetAlpha(0.07)
                overlay._accent:SetAlpha(0)
            else
                overlay._bg:SetAlpha(0)
                overlay._accent:SetAlpha(0)
            end
        end

        local function KU_RefreshLinkedVisuals()
            for _, row in ipairs(tooltipBuilder.rows) do
                KU_SetRowHighlight(row, tooltipBuilder.hoveredLineId == row.lineId, tooltipBuilder.selectedLineId == row.lineId)
            end
            for _, overlay in ipairs(tooltipBuilder.previewOverlays) do
                KU_SetOverlayHighlight(overlay, tooltipBuilder.hoveredLineId == overlay.lineId, tooltipBuilder.selectedLineId == overlay.lineId)
            end
        end

        local function KU_SetHoveredLine(lineId)
            local normalized = lineId
            if normalized and not tooltipBuilder.rowsById[normalized] then
                normalized = nil
            end
            if tooltipBuilder.hoveredLineId ~= normalized then
                tooltipBuilder.hoveredLineId = normalized
                KU_RefreshLinkedVisuals()
            end
        end

        local function KU_ClearHover()
            if tooltipBuilder.hoveredLineId ~= nil then
                tooltipBuilder.hoveredLineId = nil
                KU_RefreshLinkedVisuals()
            end
        end

        local function KU_SelectLine(lineId, fromPreviewClick)
            if lineId and tooltipBuilder.rowsById[lineId] then
                if tooltipBuilder.selectedLineId == lineId then
                    tooltipBuilder.selectedLineId = nil
                else
                    tooltipBuilder.selectedLineId = lineId
                end
                KU_ClearBuilderStatus()
            else
                tooltipBuilder.selectedLineId = nil
            end
            KU_RefreshLinkedVisuals()

            if fromPreviewClick and lineId and tooltipBuilder.rowsById[lineId] then
                -- Non-scrollable layout: no per-row viewport to adjust.
            end
        end

        tooltipBuilder.inspectorPane:EnableMouse(true)
        tooltipBuilder.inspectorPane:SetScript("OnMouseDown", function(_, mouseButton)
            if mouseButton == "LeftButton" then
                KU_SelectLine(nil, false)
            end
        end)
        tooltipBuilder.previewHitLayer:SetScript("OnMouseDown", function(_, mouseButton)
            if mouseButton == "LeftButton" then
                KU_SelectLine(nil, false)
            end
        end)

        local function KU_OnTooltipCommit(lineId, affectsLayout)
            tooltipBuilder._lastCommit = {
                lineId = lineId,
                affectsLayout = affectsLayout and true or false,
            }
            onApply()
        end

        local function KU_ForwardPanelMouseWheel(delta)
            if not scrollFrame then
                return
            end
            local onWheel = scrollFrame.GetScript and scrollFrame:GetScript("OnMouseWheel") or nil
            if type(onWheel) == "function" then
                onWheel(scrollFrame, delta)
            end
        end

        local function KU_CreatePremiumPickerButton(parent, getter, setter, optionsProvider, onCommit, controlOpts)
            controlOpts = type(controlOpts) == "table" and controlOpts or {}
            local cycleEnabled = controlOpts.enableCycle and true or false
            local wheelCycleEnabled = cycleEnabled and not (controlOpts.disableWheelCycle and true or false)
            local noSearch = controlOpts.noSearch and true or false
            local hideTitle = controlOpts.hideTitle and true or false
            local autoHeightToOptions = controlOpts.autoHeightToOptions and true or false
            local cycleGutterW = 18
            local button = CreateFrame("Button", nil, parent, "BackdropTemplate")
            button:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
            button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
            button:SetHeight(22)
            button:SetWidth(TOOLTIP_BUILDER_INSPECTOR_PICKER_W)

            local text = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 11)
            local leftTextInset = cycleEnabled and (8 + cycleGutterW) or 8
            local rightTextInset = cycleEnabled and (8 + cycleGutterW) or 18
            text:SetPoint("LEFT", button, "LEFT", leftTextInset, 0)
            text:SetPoint("RIGHT", button, "RIGHT", -rightTextInset, 0)
            text:SetJustifyH(cycleEnabled and "CENTER" or "LEFT")
            text:SetTextColor(0.92, 0.92, 0.92, 1)

            local caret = nil
            local leftChevron = nil
            local rightChevron = nil
            if not cycleEnabled then
                caret = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 10)
                caret:SetPoint("RIGHT", button, "RIGHT", -7, 0)
                caret:SetText("v")
                caret:SetTextColor(0.76, 0.76, 0.78, 1)
            else
                leftChevron = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 10)
                leftChevron:SetPoint("LEFT", button, "LEFT", 8, 0)
                leftChevron:SetText("<")
                leftChevron:SetTextColor(0.62, 0.64, 0.69, 0.95)

                rightChevron = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 10)
                rightChevron:SetPoint("RIGHT", button, "RIGHT", -8, 0)
                rightChevron:SetText(">")
                rightChevron:SetTextColor(0.62, 0.64, 0.69, 0.95)
            end

            local picker = CreatePicker(UIParent, {}, function(value)
                setter(tostring(value or ""))
                if onCommit then
                    onCommit()
                end
            end, {
                title = "Select Tooltip Option",
                searchHint = "Search options",
                width = 380,
                height = 330,
                showSecondary = false,
                showClearButton = false,
                preserveOrder = true,
                noSearch = noSearch,
                hideTitle = hideTitle,
                hideScrollBar = (noSearch and hideTitle),
                minHeight = autoHeightToOptions and 120 or 220,
            })

            local currentButtonLabel = ""
            local function getTextMaxWidth()
                local base = (button:GetWidth() or 0) - (leftTextInset + rightTextInset)
                return math.max(4, base)
            end
            local function setButtonLabel(labelText)
                currentButtonLabel = tostring(labelText or "")
                text:SetWordWrap(false)
                if text.SetMaxLines then
                    text:SetMaxLines(1)
                end
                local maxWidth = getTextMaxWidth()
                text:SetWidth(maxWidth)
                text:SetText(currentButtonLabel)
                if text:GetStringWidth() <= maxWidth then
                    return
                end
                local source = currentButtonLabel
                local cut = string.len(source)
                while cut > 0 do
                    local candidate = string.sub(source, 1, cut) .. "..."
                    text:SetText(candidate)
                    if text:GetStringWidth() <= maxWidth then
                        return
                    end
                    cut = cut - 1
                end
                text:SetText("...")
            end

            local function applyVisual(hovered)
                if hovered then
                    button:SetBackdropColor(0.16, 0.17, 0.20, 0.95)
                    button:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                    if caret then
                        caret:SetTextColor(0.88, 0.88, 0.90, 1)
                    end
                    if leftChevron then
                        leftChevron:SetTextColor(0.84, 0.85, 0.89, 1.0)
                    end
                    if rightChevron then
                        rightChevron:SetTextColor(0.84, 0.85, 0.89, 1.0)
                    end
                else
                    button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
                    button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                    if caret then
                        caret:SetTextColor(0.76, 0.76, 0.78, 1)
                    end
                    if leftChevron then
                        leftChevron:SetTextColor(0.62, 0.64, 0.69, 0.95)
                    end
                    if rightChevron then
                        rightChevron:SetTextColor(0.62, 0.64, 0.69, 0.95)
                    end
                end
            end

            local function buildPickerOptions()
                local built = {}
                for _, option in ipairs(optionsProvider and optionsProvider() or {}) do
                    built[#built + 1] = {
                        value = tostring(option.value or ""),
                        label = tostring(option.label or option.value or ""),
                        buttonLabel = tostring(option.label or option.value or ""),
                        secondary = "",
                    }
                end
                return built
            end

            local function resolveSelectedValue(options)
                local selectedRaw = getter and getter() or nil
                local selectedValue = tostring(selectedRaw or "")
                local visualValue, visualLabel = KU_ResolveVisualChoice(selectedRaw, options)
                if visualValue ~= nil then
                    selectedValue = tostring(visualValue)
                end
                local selectedIndex = 1
                for i, option in ipairs(options or {}) do
                    if tostring(option.value or "") == selectedValue then
                        selectedIndex = i
                        break
                    end
                end
                return selectedValue, selectedIndex, visualLabel
            end

            local spec = {}
            spec.control = button
            local function applyAutoHeight(options)
                if not autoHeightToOptions or not picker then
                    return
                end
                local optionCount = math.max(1, #(options or {}))
                local rowH = math.max(20, tonumber(picker._rowHeight) or 26)
                local topInset
                if noSearch and hideTitle then
                    topInset = 14
                elseif noSearch then
                    topInset = 34
                else
                    topInset = 72
                end
                local bottomInset = 48
                local targetH = topInset + bottomInset + (optionCount * rowH)
                targetH = math.max(tonumber(picker._minHeight) or 120, targetH)
                picker:SetHeight(math.floor(targetH))
            end
            spec.SetWidth = function(_, width)
                button:SetWidth(math.max(0, math.floor(tonumber(width) or TOOLTIP_BUILDER_INSPECTOR_PICKER_W)))
                setButtonLabel(currentButtonLabel)
            end
            spec.ClosePicker = function()
                if picker and picker.Close and picker.IsShown and picker:IsShown() then
                    picker:Close()
                end
            end
            spec.Refresh = function()
                local options = buildPickerOptions()
                picker:SetOptions(options)
                applyAutoHeight(options)
                local selectedValue, _, selectedLabel = resolveSelectedValue(options)
                if selectedValue ~= nil then
                    picker:SetSelectedValue(tostring(selectedValue))
                end
                setButtonLabel(selectedLabel ~= "" and selectedLabel or "Default")
            end

            local function cycleBy(delta)
                local options = buildPickerOptions()
                if #options <= 0 then
                    return
                end
                local _, selectedIndex = resolveSelectedValue(options)
                local newIndex = ((selectedIndex - 1 + delta) % #options) + 1
                local newValue = tostring(options[newIndex] and options[newIndex].value or "")
                setter(newValue)
                if onCommit then
                    onCommit()
                end
                spec.Refresh()
            end

            button:SetScript("OnEnter", function()
                applyVisual(true)
            end)
            button:SetScript("OnLeave", function()
                applyVisual(false)
            end)
            button:SetScript("OnClick", function(selfButton)
                if cycleEnabled then
                    local cursorX = GetCursorPosition()
                    local scale = selfButton:GetEffectiveScale() or (UIParent and UIParent:GetEffectiveScale()) or 1
                    if scale and scale > 0 then
                        cursorX = cursorX / scale
                    end
                    local left = selfButton:GetLeft() or 0
                    local width = selfButton:GetWidth() or 0
                    local localX = cursorX - left
                    if localX <= cycleGutterW then
                        cycleBy(-1)
                        return
                    elseif localX >= (width - cycleGutterW) then
                        cycleBy(1)
                        return
                    end
                end
                if cycleEnabled and picker and picker.IsShown and picker:IsShown() then
                    picker:Close()
                    return
                end
                spec.Refresh()
                picker:Open(selfButton)
            end)
            button:EnableMouseWheel(true)
            button:SetScript("OnMouseWheel", function(_, delta)
                if not wheelCycleEnabled then
                    KU_ForwardPanelMouseWheel(delta)
                    return
                end
                if delta > 0 then
                    cycleBy(-1)
                elseif delta < 0 then
                    cycleBy(1)
                end
            end)
            button:HookScript("OnSizeChanged", function()
                setButtonLabel(currentButtonLabel)
            end)

            spec.Refresh()
            return spec
        end

        local function KU_CreateSegmentedControl(parent, choices, getter, setter, onCommit, controlOpts)
            local internalValue = getter and getter() or nil
            local segmented = createPremiumSegmentedChoice(parent, "", nil, choices, function(value)
                internalValue = value
                setter(value)
                if onCommit then
                    onCommit()
                end
            end, {
                semantic = "toggle",
                controlHeight = controlOpts and controlOpts.controlHeight or nil,
                textSize = controlOpts and controlOpts.textSize or nil,
                textEllipsis = controlOpts and controlOpts.textEllipsis or nil,
                minWidth = controlOpts and controlOpts.minWidth or 0,
                segmentGap = controlOpts and controlOpts.segmentGap or nil,
                segmentMinWidth = controlOpts and controlOpts.segmentMinWidth or nil,
                getValue = function()
                    return internalValue
                end,
                setValue = function(value)
                    internalValue = value
                end,
            })
            if segmented.label then
                segmented.label:Hide()
            end
            local spec = {}
            spec.control = segmented.control
            spec.Layout = function(_, width)
                segmented:Layout(width)
            end
            spec.SetEnabled = function(_, enabled)
                segmented:SetEnabled(enabled)
            end
            spec.SetChoiceEnabled = function(_, value, enabled)
                segmented:SetChoiceEnabled(value, enabled)
            end
            spec.SetVisualSelectedValue = function(_, value)
                segmented:SetVisualSelectedValue(value)
            end
            spec.Refresh = function()
                local selectedValue = getter and getter() or nil
                local visualValue = KU_ResolveVisualChoice(selectedValue, choices)
                if visualValue ~= nil then
                    internalValue = visualValue
                    segmented:SetVisualSelectedValue(visualValue)
                end
            end
            spec.Refresh()
            return spec
        end

        local function KU_CreateInspectorRow(cfg)
            local row = {}
            row.lineId = cfg.lineId
            row.cfg = cfg
            row.container = CreateFrame("Button", nil, tooltipBuilder.inspectorContent)
            row.container:EnableMouse(true)
            row.container:SetHeight(KEYSTONE_UTILITY_LAYOUT.TOOLTIP.BASE_ROW_H)
            row.container:SetScript("OnEnter", function()
                KU_SetHoveredLine(row.lineId)
            end)
            row.container:SetScript("OnLeave", function()
                KU_SetHoveredLine(nil)
            end)
            row.container:SetScript("OnClick", function()
                KU_SelectLine(row.lineId, false)
            end)

            row.highlightBg = row.container:CreateTexture(nil, "BACKGROUND")
            row.highlightBg:SetAllPoints(row.container)
            row.highlightBg:SetTexture("Interface\\Buttons\\WHITE8x8")
            row.highlightBg:SetVertexColor(TOOLTIP_BUILDER_HIGHLIGHT_BG_R, TOOLTIP_BUILDER_HIGHLIGHT_BG_G, TOOLTIP_BUILDER_HIGHLIGHT_BG_B, 0.16)
            row.highlightBg:SetAlpha(0)
            row.highlightAccent = row.container:CreateTexture(nil, "BORDER")
            row.highlightAccent:SetPoint("TOPLEFT", row.container, "TOPLEFT", 0, 0)
            row.highlightAccent:SetPoint("BOTTOMLEFT", row.container, "BOTTOMLEFT", 0, 0)
            row.highlightAccent:SetWidth(1)
            row.highlightAccent:SetTexture("Interface\\Buttons\\WHITE8x8")
            row.highlightAccent:SetVertexColor(TOOLTIP_BUILDER_HIGHLIGHT_ACCENT_R, TOOLTIP_BUILDER_HIGHLIGHT_ACCENT_G, TOOLTIP_BUILDER_HIGHLIGHT_ACCENT_B, 0.62)
            row.highlightAccent:SetAlpha(0)

            row.label = createStyledFontString(row.container, "ARTWORK", "GameFontHighlight", 12)
            row.label:SetText(cfg.label)
            row.label:SetJustifyH("LEFT")
            row.label:SetWordWrap(false)
            if row.label.SetMaxLines then
                row.label:SetMaxLines(1)
            end

            if cfg.type == "picker" then
                row.main = KU_CreatePremiumPickerButton(
                    row.container,
                    function()
                        return KU_Normalize(PortalAuthorityDB and PortalAuthorityDB[cfg.dbKey])
                    end,
                    function(value)
                        if PortalAuthorityDB then
                            PortalAuthorityDB[cfg.dbKey] = tostring(value or "")
                        end
                    end,
                    function()
                        return cfg.options or {}
                    end,
                    function()
                        KU_OnTooltipCommit(cfg.lineId, cfg.affectsLayout)
                    end,
                    {
                        enableCycle = (cfg.lineId == "DungeonName" or cfg.lineId == "Level"),
                        disableWheelCycle = (cfg.lineId == "DungeonName" or cfg.lineId == "Level"),
                        noSearch = (cfg.lineId == "DungeonName" or cfg.lineId == "Level"),
                        hideTitle = (cfg.lineId == "DungeonName" or cfg.lineId == "Level"),
                        autoHeightToOptions = (cfg.lineId == "DungeonName" or cfg.lineId == "Level"),
                    }
                )
            else
                row.main = KU_CreateSegmentedControl(
                    row.container,
                    cfg.choices or tooltipHideShowChoices,
                    function()
                        return KU_Normalize(PortalAuthorityDB and PortalAuthorityDB[cfg.dbKey])
                    end,
                    function(value)
                        if PortalAuthorityDB then
                            PortalAuthorityDB[cfg.dbKey] = value
                        end
                    end,
                    function()
                        KU_OnTooltipCommit(cfg.lineId, cfg.affectsLayout)
                    end,
                    {
                        textSize = (cfg.lineId == "Modifiers") and 10 or nil,
                        textEllipsis = (cfg.lineId == "Modifiers"),
                        segmentGap = (cfg.lineId == "Modifiers") and 2 or nil,
                        segmentMinWidth = (cfg.lineId == "Modifiers") and 34 or nil,
                        minWidth = 0,
                    }
                )
            end

            if cfg.inline then
                row.inlineAccent = row.container:CreateTexture(nil, "ARTWORK")
                row.inlineAccent:SetTexture("Interface\\Buttons\\WHITE8x8")
                row.inlineAccent:SetVertexColor(0.82, 0.84, 0.88, 0.58)
                row.inlineAccent:SetSize(2, 12)
                row.inlineLabel = createStyledFontString(row.container, "ARTWORK", "GameFontHighlightSmall", 10)
                row.inlineLabel:SetText(cfg.inline.label)
                row.inlineLabel:SetJustifyH("LEFT")
                row.inlineLabel:SetWordWrap(false)
                row.inlineLabel:SetTextColor(TOOLTIP_BUILDER_MUTED_TEXT_R, TOOLTIP_BUILDER_MUTED_TEXT_G, TOOLTIP_BUILDER_MUTED_TEXT_B, 0.92)
                if row.inlineLabel.SetMaxLines then
                    row.inlineLabel:SetMaxLines(1)
                end
                row.inline = KU_CreateSegmentedControl(
                    row.container,
                    cfg.inline.choices,
                    function()
                        return PortalAuthorityDB and PortalAuthorityDB[cfg.inline.dbKey]
                    end,
                    function(value)
                        if PortalAuthorityDB then
                            PortalAuthorityDB[cfg.inline.dbKey] = PA_SafeBool(value)
                        end
                    end,
                    function()
                        KU_OnTooltipCommit(cfg.lineId, cfg.affectsLayout)
                    end,
                    {
                        controlHeight = 19,
                        textSize = 10,
                    }
                )
            end

            if cfg.hasColorSwatch then
                row.colorSwatch = CreateFrame("Button", nil, row.container, "BackdropTemplate")
                row.colorSwatch:SetBackdrop({
                    bgFile = "Interface\\Buttons\\WHITE8x8",
                    edgeFile = "Interface\\Buttons\\WHITE8x8",
                    edgeSize = 1,
                    insets = { left = 0, right = 0, top = 0, bottom = 0 },
                })
                row.colorSwatch:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                row.colorSwatch:SetSize(22, 18)
                row.colorSwatch:SetScript("OnClick", function()
                    openKeystoneTooltipAffixesColorPicker(function()
                        refreshTooltipAffixesSwatch()
                        KU_OnTooltipCommit(cfg.lineId, cfg.affectsLayout)
                    end)
                end)
            end

            tooltipBuilder.rows[#tooltipBuilder.rows + 1] = row
            tooltipBuilder.rowsById[cfg.lineId] = row
            return row
        end

        for _, cfg in ipairs(tooltipLineConfigs) do
            KU_CreateInspectorRow(cfg)
        end

        panelRef._kuCloseTooltipBuilderPickers = function()
            if not tooltipBuilder or not tooltipBuilder.rows then
                return
            end
            for _, row in ipairs(tooltipBuilder.rows) do
                if row and row.main and row.main.ClosePicker then
                    row.main:ClosePicker()
                end
            end
        end

        local function KU_GetTooltipBuilderInspectorVisibilityState()
            local db = PortalAuthorityDB or {}
            local levelMode = KU_Normalize(db.keystoneTooltipLevelMode)
            local addToName = PA_SafeBool(db.keystoneTooltipLevelAddToName)
            local levelVisible = true
            if levelMode == "HIDE" then
                levelVisible = false
            elseif addToName and levelMode ~= "" and levelMode ~= "NO_CHANGES" then
                levelVisible = false
            end
            return {
                DungeonName = true,
                Level = levelVisible,
                Resilient = KU_Normalize(db.keystoneTooltipResilientMode) ~= "HIDE",
                Soulbound = KU_Normalize(db.keystoneTooltipSoulboundMode) ~= "HIDE",
                Unique = KU_Normalize(db.keystoneTooltipUniqueMode) ~= "HIDE",
                Modifiers = KU_Normalize(db.keystoneTooltipAffixesMode) ~= "HIDE",
                Duration = KU_Normalize(db.keystoneTooltipDurationMode) ~= "HIDE",
                RPQuote = KU_Normalize(db.keystoneTooltipRPQuoteMode) ~= "HIDE",
            }
        end

        local function KU_GetVisibleInspectorLineIds()
            local visible = KU_GetTooltipBuilderInspectorVisibilityState()
            local ids = {}
            for _, cfg in ipairs(tooltipLineConfigs) do
                if visible[cfg.lineId] then
                    ids[#ids + 1] = cfg.lineId
                end
            end
            return ids
        end

        local function KU_EnsurePreviewOverlay(index)
            if tooltipBuilder.previewOverlays[index] then
                return tooltipBuilder.previewOverlays[index]
            end
            local overlay = CreateFrame("Button", nil, tooltipBuilder.previewHitLayer)
            overlay:SetFrameStrata(tooltipBuilder.previewHitLayer:GetFrameStrata())
            overlay:SetFrameLevel((tooltipBuilder.previewHitLayer:GetFrameLevel() or 0) + 2)
            overlay:RegisterForClicks("LeftButtonUp")
            overlay:EnableMouse(true)
            overlay._bg = overlay:CreateTexture(nil, "BACKGROUND")
            overlay._bg:SetAllPoints(overlay)
            overlay._bg:SetTexture("Interface\\Buttons\\WHITE8x8")
            overlay._bg:SetVertexColor(TOOLTIP_BUILDER_HIGHLIGHT_BG_R, TOOLTIP_BUILDER_HIGHLIGHT_BG_G, TOOLTIP_BUILDER_HIGHLIGHT_BG_B, 0.16)
            overlay._bg:SetAlpha(0)
            overlay._accent = overlay:CreateTexture(nil, "BORDER")
            overlay._accent:SetPoint("TOPLEFT", overlay, "TOPLEFT", 0, 0)
            overlay._accent:SetPoint("BOTTOMLEFT", overlay, "BOTTOMLEFT", 0, 0)
            overlay._accent:SetWidth(1)
            overlay._accent:SetTexture("Interface\\Buttons\\WHITE8x8")
            overlay._accent:SetVertexColor(TOOLTIP_BUILDER_HIGHLIGHT_ACCENT_R, TOOLTIP_BUILDER_HIGHLIGHT_ACCENT_G, TOOLTIP_BUILDER_HIGHLIGHT_ACCENT_B, 0.62)
            overlay._accent:SetAlpha(0)
            overlay:SetScript("OnEnter", function(selfOverlay)
                KU_SetHoveredLine(selfOverlay.lineId)
            end)
            overlay:SetScript("OnLeave", function()
                KU_SetHoveredLine(nil)
            end)
            overlay:SetScript("OnClick", function(selfOverlay)
                if selfOverlay.lineId then
                    KU_SelectLine(selfOverlay.lineId, true)
                end
            end)
            tooltipBuilder.previewOverlays[index] = overlay
            return overlay
        end

        local function KU_HideUnusedPreviewOverlays(fromIndex)
            for i = fromIndex, #tooltipBuilder.previewOverlays do
                local overlay = tooltipBuilder.previewOverlays[i]
                if overlay then
                    overlay:Hide()
                    overlay.lineId = nil
                end
            end
        end

        KU_ReadPreviewBodyLeftLines = function(previewTooltip)
            local lines = {}
            if not previewTooltip or not previewTooltip.GetName then
                return lines
            end
            local baseName = previewTooltip:GetName()
            if type(baseName) ~= "string" or baseName == "" then
                return lines
            end
            local count = previewTooltip:NumLines() or 0
            for i = 1, count do
                local left = _G[baseName .. "TextLeft" .. i]
                if left and left.GetText and left.IsShown and left:IsShown() then
                    local text = trim(left:GetText() or "")
                    if text ~= "" then
                        lines[#lines + 1] = { fs = left, text = text }
                    end
                end
            end
            -- Keep real first lines (e.g. "Keystone: ..."). Only drop the synthetic
            -- fallback header line when the hyperlink path wasn't available.
            if #lines > 0 then
                local firstLower = string.lower(trim(tostring(lines[1].text or "")))
                if string.find(firstLower, "mythic keystone", 1, true) then
                    table.remove(lines, 1)
                end
            end
            return lines
        end

        local function KU_BuildPreviewRegions()
            tooltipBuilder.mappingByLineId = {}
            tooltipBuilder.previewOverlaysByLineId = {}
            tooltipBuilder.visibleInspectorLineIds = KU_GetVisibleInspectorLineIds()
            tooltipBuilder.visiblePreviewLineIds = {}

            local previewTooltip = widgets.keystoneTooltipPreviewTooltip
            local bodyLines = KU_ReadPreviewBodyLeftLines(previewTooltip)
            local total = #bodyLines
            local cursor = 1
            local regions = {}
            local visibility = KU_GetTooltipBuilderInspectorVisibilityState()

            local function addSingle(lineId, matcher)
                if not visibility[lineId] then
                    return
                end
                if cursor <= total then
                    if matcher then
                        local lineText = (bodyLines[cursor] and bodyLines[cursor].text) or ""
                        if not matcher(string.lower(trim(tostring(lineText or "")))) then
                            return
                        end
                    end
                    regions[#regions + 1] = { lineId = lineId, startIndex = cursor, endIndex = cursor }
                    cursor = cursor + 1
                end
            end

            addSingle("DungeonName")
            addSingle("Level")
            addSingle("Resilient", function(lowerText)
                return string.find(lowerText, "resilient", 1, true) ~= nil
            end)
            addSingle("Soulbound", function(lowerText)
                return string.find(lowerText, "soulbound", 1, true) ~= nil
                    or string.find(lowerText, "binds when picked up", 1, true) ~= nil
                    or string.find(lowerText, "binds when equipped", 1, true) ~= nil
            end)
            addSingle("Unique", function(lowerText)
                return string.find(lowerText, "unique", 1, true) == 1
            end)

            if visibility.Modifiers and cursor <= total then
                local trailing = 0
                if visibility.Duration then trailing = trailing + 1 end
                if visibility.RPQuote then trailing = trailing + 1 end
                local modifiersEnd = total - trailing
                if modifiersEnd < cursor then
                    modifiersEnd = cursor
                end
                if modifiersEnd > total then
                    modifiersEnd = total
                end
                regions[#regions + 1] = { lineId = "Modifiers", startIndex = cursor, endIndex = modifiersEnd }
                cursor = modifiersEnd + 1
            end

            addSingle("Duration", function(lowerText)
                return string.find(lowerText, "duration", 1, true) ~= nil
            end)
            addSingle("RPQuote")

            -- Keep inspector<->preview linking based on actual rendered regions so
            -- missing optional lines (e.g. fallback without Resilient) do not shift
            -- subsequent mappings.
            do
                local actualInspectorLineIds = {}
                for _, region in ipairs(regions) do
                    actualInspectorLineIds[#actualInspectorLineIds + 1] = region.lineId
                end
                tooltipBuilder.visibleInspectorLineIds = actualInspectorLineIds
            end

            local overlayIndex = 1
            local visiblePreviewRegions = {}
            for _, region in ipairs(regions) do
                local startLine = bodyLines[region.startIndex]
                local endLine = bodyLines[region.endIndex]
                if startLine and endLine and startLine.fs and endLine.fs then
                    local overlay = KU_EnsurePreviewOverlay(overlayIndex)
                    overlay:ClearAllPoints()
                    overlay:SetPoint("TOPLEFT", startLine.fs, "TOPLEFT", -4, 2)
                    overlay:SetPoint("BOTTOMRIGHT", endLine.fs, "BOTTOMRIGHT", 4, -2)
                    overlay.lineId = region.lineId
                    overlay:Show()
                    tooltipBuilder.previewOverlaysByLineId[region.lineId] = overlay
                    tooltipBuilder.visiblePreviewLineIds[#tooltipBuilder.visiblePreviewLineIds + 1] = region.lineId
                    visiblePreviewRegions[#visiblePreviewRegions + 1] = { lineId = region.lineId, overlay = overlay }
                    overlayIndex = overlayIndex + 1
                end
            end
            KU_HideUnusedPreviewOverlays(overlayIndex)

            local ambiguous = false
            if #tooltipBuilder.visibleInspectorLineIds ~= #tooltipBuilder.visiblePreviewLineIds then
                ambiguous = true
            else
                for _, lineId in ipairs(tooltipBuilder.visibleInspectorLineIds) do
                    if not tooltipBuilder.previewOverlaysByLineId[lineId] then
                        ambiguous = true
                        break
                    end
                end
            end

            if not ambiguous then
                for _, lineId in ipairs(tooltipBuilder.visibleInspectorLineIds) do
                    tooltipBuilder.mappingByLineId[lineId] = tooltipBuilder.previewOverlaysByLineId[lineId]
                end
            else
                tooltipBuilder.mappingByLineId = {}
                local maxZip = math.min(#tooltipBuilder.visibleInspectorLineIds, #visiblePreviewRegions)
                for i = 1, maxZip do
                    local lineId = tooltipBuilder.visibleInspectorLineIds[i]
                    local overlay = visiblePreviewRegions[i] and visiblePreviewRegions[i].overlay or nil
                    if lineId and overlay and overlay:IsShown() then
                        overlay.lineId = lineId
                        tooltipBuilder.mappingByLineId[lineId] = overlay
                    end
                end
            end
        end

        local function KU_RebuildTooltipPreviewLinks(commitInfo)
            local oldHovered = tooltipBuilder.hoveredLineId
            local oldSelected = tooltipBuilder.selectedLineId
            if KU_UpdateKeystoneTooltipPreview then
                KU_UpdateKeystoneTooltipPreview()
            end
            KU_BuildPreviewRegions()

            if oldSelected and not tooltipBuilder.mappingByLineId[oldSelected] then
                tooltipBuilder.selectedLineId = nil
                if commitInfo and commitInfo.affectsLayout then
                    KU_SetBuilderStatus("Line hidden.")
                end
            elseif commitInfo then
                KU_ClearBuilderStatus()
            else
                tooltipBuilder.selectedLineId = oldSelected
            end

            if oldHovered and tooltipBuilder.rowsById[oldHovered] then
                tooltipBuilder.hoveredLineId = oldHovered
            else
                tooltipBuilder.hoveredLineId = nil
            end

            KU_RefreshLinkedVisuals()
        end

        KU_RefreshTooltipBuilderVisual = function()
            if not PortalAuthorityDB then
                ensureDatabase()
                if not PortalAuthorityDB then
                    return
                end
            end
            for _, row in ipairs(tooltipBuilder.rows) do
                if row.main and row.main.Refresh then
                    row.main:Refresh()
                end
                if row.inline and row.inline.Refresh then
                    row.inline:Refresh()
                end
            end
            do
                local levelRow = tooltipBuilder.rowsById and tooltipBuilder.rowsById.Level or nil
                if levelRow and levelRow.inline then
                    local levelMode = KU_Normalize(PortalAuthorityDB and PortalAuthorityDB.keystoneTooltipLevelMode)
                    local forceInlineOff = (levelMode == "HIDE" or levelMode == "NO_CHANGES")
                    local allowInline = not forceInlineOff
                    if levelRow.inline.SetEnabled then
                        levelRow.inline:SetEnabled(allowInline)
                    end
                    if levelRow.inlineLabel then
                        levelRow.inlineLabel:SetAlpha(allowInline and 0.95 or 0.52)
                    end
                    if levelRow.inlineAccent then
                        levelRow.inlineAccent:SetAlpha(allowInline and 0.55 or 0.30)
                    end
                end
            end
            do
                local modifiersRow = tooltipBuilder.rowsById and tooltipBuilder.rowsById.Modifiers or nil
                local mode = KU_Normalize(PortalAuthorityDB and PortalAuthorityDB.keystoneTooltipAffixesMode)
                if modifiersRow and modifiersRow.colorSwatch then
                    modifiersRow.colorSwatch:SetAlpha((mode == "HIDE") and 0.50 or 1.00)
                end
            end
            refreshTooltipAffixesSwatch()
            local commitInfo = tooltipBuilder._lastCommit
            tooltipBuilder._lastCommit = nil
            KU_RebuildTooltipPreviewLinks(commitInfo)
        end

        panelRef._kuHydrateKeystoneTooltipControls = KU_RefreshTooltipBuilderVisual
        panelRef._kuHydrateKeystoneTooltipVisualOnly = KU_RefreshTooltipBuilderVisual

        local assistantRows = {
            {
                id = "keystoneHelperEnabled",
                spec = widgets.keystoneHelperEnabled,
                label = widgets.keystoneHelperEnabled and widgets.keystoneHelperEnabled.label or nil,
                control = widgets.keystoneHelperEnabled and widgets.keystoneHelperEnabled.control or nil,
                desc = helperDesc,
            },
            {
                id = "keystoneAutoSlotEnabled",
                spec = widgets.keystoneAutoSlotEnabled,
                label = widgets.keystoneAutoSlotEnabled and widgets.keystoneAutoSlotEnabled.label or nil,
                control = widgets.keystoneAutoSlotEnabled and widgets.keystoneAutoSlotEnabled.control or nil,
                desc = autoSlotDesc,
            },
            {
                id = "keystoneAutoStartEnabled",
                spec = widgets.keystoneAutoStartEnabled,
                label = widgets.keystoneAutoStartEnabled and widgets.keystoneAutoStartEnabled.label or nil,
                control = widgets.keystoneAutoStartEnabled and widgets.keystoneAutoStartEnabled.control or nil,
                desc = autoStartDesc,
            },
        }
        local releaseRows = {
            {
                id = "releaseGateEnabled",
                spec = widgets.releaseGateEnabled,
                label = widgets.releaseGateEnabled and widgets.releaseGateEnabled.label or nil,
                control = widgets.releaseGateEnabled and widgets.releaseGateEnabled.control or nil,
                desc = releaseEnabledDesc,
            },
            {
                id = "releaseGateModifier",
                spec = widgets.releaseGateModifier,
                label = widgets.releaseGateModifier and widgets.releaseGateModifier.label or nil,
                control = widgets.releaseGateModifier and widgets.releaseGateModifier.control or nil,
                desc = nil,
            },
            {
                id = "releaseHold",
                label = holdLabel,
                control = widgets.releaseHoldStepper,
                desc = releaseHoldDesc,
                controlWidth = 84,
                noLayout = true,
            },
        }
        for _, row in ipairs(assistantRows) do
            local searchTarget = row and (row.spec or row) or nil
            if searchTarget and frameIsAlive(row.desc) then
                settingsSearchRuntime.attachExtraSearchRefs(searchTarget, { row.desc })
            end
        end
        for _, row in ipairs(releaseRows) do
            local searchTarget = row and (row.spec or row) or nil
            if searchTarget and frameIsAlive(row.desc) then
                settingsSearchRuntime.attachExtraSearchRefs(searchTarget, { row.desc })
            end
        end
        local statusChips = {
            widgets.statusKeystone,
            widgets.statusLeader,
            widgets.statusAutomation,
        }
        local function KU_RoundMetric(value)
            local n = tonumber(value) or 0
            return math.floor(n + 0.5)
        end

        local function KU_GetRowLabel(row)
            if not row then
                return nil
            end
            return row.label or (row.spec and row.spec.label) or nil
        end

        local function KU_GetRowControl(row)
            if not row then
                return nil
            end
            return row.control or (row.spec and row.spec.control) or nil
        end

        local function KU_MeasureFontStringWidth(fs)
            if not (fs and fs.GetStringWidth) then
                return 0
            end
            return math.ceil(tonumber(fs:GetStringWidth()) or 0)
        end

        local function KU_MeasureFontStringHeight(fs, floor)
            local measured = 0
            if fs and fs.GetStringHeight then
                measured = math.ceil(tonumber(fs:GetStringHeight()) or 0)
            end
            return math.max(tonumber(floor) or 0, measured)
        end

        local function KU_MeasureControlHeight(widget, floor)
            local measured = 0
            if widget and widget.GetHeight then
                measured = math.ceil(tonumber(widget:GetHeight()) or 0)
            end
            return math.max(tonumber(floor) or 0, measured)
        end

        local function KU_AppendMetric(parts, key, value)
            parts[#parts + 1] = tostring(key or "") .. "=" .. tostring(KU_RoundMetric(value))
        end

        local function KU_AppendFontMetrics(parts, prefix, fs)
            KU_AppendMetric(parts, tostring(prefix or "") .. "W", KU_MeasureFontStringWidth(fs))
            KU_AppendMetric(parts, tostring(prefix or "") .. "H", KU_MeasureFontStringHeight(fs, 0))
        end

        local function KU_ComputeContentWidth()
            return math.max((scrollFrame:GetWidth() or 0) - KEYSTONE_UTILITY_LAYOUT.SCROLL_WIDTH_FUDGE, KEYSTONE_UTILITY_LAYOUT.MIN_CONTENT_W)
        end

        local function KU_ComputeSectionColumns(cardW, rows)
            local T = KEYSTONE_UTILITY_LAYOUT
            local C = T.CARD
            local innerW = math.max(1, cardW - (C.PAD_X * 2))
            local labelMetricW = T.LABEL_MIN_W
            for _, row in ipairs(rows or {}) do
                labelMetricW = math.max(labelMetricW, KU_MeasureFontStringWidth(KU_GetRowLabel(row)))
            end
            local preferredControlW = math.max(T.CONTROL_MIN_W, math.min(T.CONTROL_MAX_W, math.floor(innerW * T.CONTROL_WIDTH_RATIO)))
            local controlW = math.max(T.CONTROL_MIN_W, math.min(preferredControlW, innerW - T.LABEL_MIN_W - T.LABEL_TO_CONTROL_GAP))
            local controlX = C.PAD_X + innerW - controlW
            local maxLabelAvailW = math.max(T.LABEL_MIN_W, controlX - C.PAD_X - T.LABEL_TO_CONTROL_GAP)
            local labelW = math.max(T.LABEL_MIN_W, math.min(labelMetricW + T.LABEL_TEXT_PAD, maxLabelAvailW))
            local descW = math.max(T.DESC_MIN_W, controlX - C.PAD_X - T.DESC_RIGHT_PAD)
            return {
                labelX = C.PAD_X,
                labelW = labelW,
                controlX = controlX,
                controlW = controlW,
                descX = C.PAD_X,
                descW = descW,
                rowTopY = -C.PAD_TOP,
                rowGap = C.ROW_GAP,
                descGap = C.DESC_GAP,
            }
        end

        local function KU_LayoutRows(parent, rows, columns)
            local T = KEYSTONE_UTILITY_LAYOUT
            local C = T.CARD
            local rowTopY = columns and columns.rowTopY or 0
            for _, row in ipairs(rows or {}) do
                local label = KU_GetRowLabel(row)
                local control = KU_GetRowControl(row)
                local desc = row and row.desc or nil
                local controlW = row and row.controlWidth or columns.controlW
                local controlYOffset = row and row.controlYOffset or C.CONTROL_TOP_NUDGE
                if label then
                    label:ClearAllPoints()
                    label:SetPoint("TOPLEFT", parent, "TOPLEFT", columns.labelX, rowTopY)
                    label:SetWidth(columns.labelW)
                    if label.SetJustifyH then
                        label:SetJustifyH("LEFT")
                    end
                end
                if control then
                    if row and row.spec and row.spec.Layout and not row.noLayout then
                        row.spec:Layout(controlW)
                    elseif control.SetWidth and controlW then
                        control:SetWidth(controlW)
                    end
                    control:ClearAllPoints()
                    control:SetPoint("TOPLEFT", parent, "TOPLEFT", columns.controlX, rowTopY + controlYOffset)
                end
                local labelH = KU_MeasureFontStringHeight(label, C.LABEL_FLOOR)
                local controlH = KU_MeasureControlHeight(control, C.CONTROL_FLOOR)
                local rowBaseH = math.max(C.ROW_FLOOR, labelH, controlH)
                local rowBottomY = rowTopY - rowBaseH
                if desc then
                    desc:ClearAllPoints()
                    desc:SetPoint("TOPLEFT", parent, "TOPLEFT", columns.descX, rowBottomY - columns.descGap)
                    desc:SetWidth(columns.descW)
                    if desc.SetJustifyH then
                        desc:SetJustifyH("LEFT")
                    end
                    local descH = KU_MeasureFontStringHeight(desc, C.HELPER_FLOOR)
                    rowBottomY = rowBottomY - columns.descGap - descH
                end
                rowTopY = rowBottomY - columns.rowGap
            end
            return rowTopY
        end

        local function KU_ComputeTooltipGeometry(contentSpan)
            local T = KEYSTONE_UTILITY_LAYOUT
            local TT = T.TOOLTIP
            local geometry = {
                sideBySide = true,
                rootLeft = 0,
                rootW = math.max(0, contentSpan),
            }
            local thresholdW = TOOLTIP_BUILDER_PREVIEW_MIN_W + TOOLTIP_BUILDER_INSPECTOR_MIN_W + TT.PANE_GAP
            if contentSpan >= thresholdW then
                geometry.inspectorW = math.max(TOOLTIP_BUILDER_INSPECTOR_MIN_W, math.floor(contentSpan * 0.60))
                geometry.previewW = contentSpan - geometry.inspectorW - TT.PANE_GAP
                if geometry.previewW < TOOLTIP_BUILDER_PREVIEW_MIN_W then
                    geometry.inspectorW = contentSpan - TOOLTIP_BUILDER_PREVIEW_MIN_W - TT.PANE_GAP
                    geometry.previewW = TOOLTIP_BUILDER_PREVIEW_MIN_W
                end
            else
                local splitSpan = math.max(0, contentSpan - TT.PANE_GAP)
                geometry.inspectorW = math.floor(splitSpan * 0.60)
                geometry.previewW = splitSpan - geometry.inspectorW
                if geometry.previewW < TOOLTIP_BUILDER_PREVIEW_READABLE_MIN_W then
                    geometry.previewW = math.min(splitSpan, TOOLTIP_BUILDER_PREVIEW_READABLE_MIN_W)
                    geometry.inspectorW = math.max(0, splitSpan - geometry.previewW)
                end
            end
            geometry.previewW = math.max(0, geometry.previewW or 0)
            geometry.inspectorW = math.max(0, geometry.inspectorW or 0)
            geometry.inspectorContentW = math.max(1, geometry.inspectorW - (TT.INSPECTOR_PAD_X * 2))
            local labelMetricW = 0
            for _, row in ipairs(tooltipBuilder.rows or {}) do
                labelMetricW = math.max(labelMetricW, KU_MeasureFontStringWidth(row and row.label or nil))
            end
            geometry.labelColX = 0
            geometry.labelW = math.max(T.TOOLTIP_LABEL_MIN_W, math.min(T.TOOLTIP_LABEL_MAX_W, labelMetricW + T.TOOLTIP_LABEL_TEXT_PAD))
            geometry.controlColX = geometry.labelW + T.TOOLTIP_LABEL_TO_CONTROL_GAP
            geometry.rightInset = TOOLTIP_BUILDER_INSPECTOR_RIGHT_INSET
            local availW = geometry.inspectorContentW - (geometry.controlColX + geometry.rightInset)
            availW = math.max(0, availW)
            if availW >= TOOLTIP_BUILDER_MAIN_MIN_W then
                geometry.mainControlW = math.max(TOOLTIP_BUILDER_MAIN_MIN_W, math.min(availW, TOOLTIP_BUILDER_MAIN_MAX_W))
            else
                geometry.mainControlW = availW
            end
            geometry.mainControlW = math.max(0, math.min(geometry.mainControlW, availW))
            geometry.inlineRegionX = geometry.controlColX + geometry.mainControlW + TT.INLINE_REGION_GAP
            geometry.availableInlineW = geometry.inspectorContentW - geometry.rightInset - geometry.inlineRegionX
            geometry.inlineBlockW = TOOLTIP_BUILDER_INLINE_LABEL_W + TT.INLINE_BLOCK_GAP + TOOLTIP_BUILDER_INLINE_TOGGLE_W
            geometry.previewTitleH = KU_MeasureFontStringHeight(tooltipBuilder.previewTitle, TT.PREVIEW_TITLE_FLOOR)
            if geometry.sideBySide then
                local alignedBorderTopOffset = TT.INSPECTOR_PAD_Y
                    + TT.STATUS_H
                    + TT.STATUS_TO_CONTENT_GAP
                    + TT.MAIN_TOP_PAD
                    - TT.STICKY_TOP_PAD
                local minimumTitleClearance = geometry.previewTitleH + TT.PREVIEW_TITLE_CLEARANCE
                local borderTopOffset = math.max(alignedBorderTopOffset, minimumTitleClearance)
                geometry.previewAnchorTopInset = math.max(0, borderTopOffset - TT.PREVIEW_FRAME_OFFSET_Y)
            else
                geometry.previewAnchorTopInset = TT.TITLE_TOP_PAD + geometry.previewTitleH + TT.PREVIEW_BODY_TOP_GAP
            end
            return geometry
        end

        local function KU_HasSizedLayoutSurface()
            local readyFrame = self._sizingFrame or self
            if not readyFrame then
                return false
            end
            local width = tonumber(readyFrame:GetWidth()) or 0
            local height = tonumber(readyFrame:GetHeight()) or 0
            return width > 1 and height > 1
        end

        local function KU_BuildMetricSignature()
            local parts = {}
            KU_AppendMetric(parts, "viewportW", scrollFrame and scrollFrame:GetWidth() or 0)
            KU_AppendFontMetrics(parts, "Header", header)
            KU_AppendFontMetrics(parts, "AssistantHeader", helperHeader)
            KU_AppendFontMetrics(parts, "ReleaseHeader", releaseHeader)
            KU_AppendFontMetrics(parts, "TooltipSectionHeader", tooltipHeader)
            KU_AppendFontMetrics(parts, "TooltipSubheader", tooltipSubheader)
            for _, row in ipairs(assistantRows) do
                KU_AppendFontMetrics(parts, "Assistant" .. tostring(row.id or ""), KU_GetRowLabel(row))
                if row.desc then
                    KU_AppendFontMetrics(parts, "AssistantDesc" .. tostring(row.id or ""), row.desc)
                end
            end
            for _, row in ipairs(releaseRows) do
                KU_AppendFontMetrics(parts, "Release" .. tostring(row.id or ""), KU_GetRowLabel(row))
                if row.desc then
                    KU_AppendFontMetrics(parts, "ReleaseDesc" .. tostring(row.id or ""), row.desc)
                end
            end
            for index, chip in ipairs(statusChips) do
                KU_AppendFontMetrics(parts, "StatusTitle" .. tostring(index), chip and chip.title or nil)
                KU_AppendFontMetrics(parts, "StatusValue" .. tostring(index), chip and chip.value or nil)
            end
            KU_AppendFontMetrics(parts, "TooltipBuilderHeader", tooltipBuilder.inspectorHeader)
            KU_AppendFontMetrics(parts, "TooltipPreviewTitle", tooltipBuilder.previewTitle)
            for _, row in ipairs(tooltipBuilder.rows or {}) do
                KU_AppendFontMetrics(parts, "TooltipRow" .. tostring(row.lineId or ""), row and row.label or nil)
                if row and row.inlineLabel then
                    KU_AppendFontMetrics(parts, "TooltipInline" .. tostring(row.lineId or ""), row.inlineLabel)
                end
            end
            return table.concat(parts, "|")
        end

        local function invalidateLayout(reason)
            self._kuLayoutDirty = true
            self._kuLayoutDirtyReason = tostring(reason or self._kuLayoutDirtyReason or "layout-dirty")
        end

        local function ensureLayoutCurrent(reason)
            if not self._layout then
                return false
            end
            if not KU_HasSizedLayoutSurface() then
                invalidateLayout(reason or "unsized")
                return false
            end
            local currentSignature = KU_BuildMetricSignature()
            local needsLayout = self._kuLayoutDirty or (self._kuMetricSignatureCache ~= currentSignature)
            if not needsLayout then
                return true
            end
            self._layout(reason or "layout")
            if not KU_HasSizedLayoutSurface() then
                invalidateLayout(reason or "unsized")
                return false
            end
            self._kuMetricSignatureCache = KU_BuildMetricSignature()
            self._kuLayoutDirty = false
            self._kuLayoutDirtyReason = nil
            return true
        end

        local function KU_ReadLeaderOrAssistState()
            local isLeader = (UnitIsGroupLeader and UnitIsGroupLeader("player")) and true or false
            local isAssist = (UnitIsGroupAssistant and UnitIsGroupAssistant("player")) and true or false
            return isLeader or isAssist
        end

        local function KU_ReadKeystoneLevelFromLink(link)
            if type(link) ~= "string" then
                return 0
            end
            local itemString = link:match("|H(keystone:[^|]+)|")
            if type(itemString) ~= "string" then
                return 0
            end
            local _, _, mapIDText, levelText = strsplit(":", itemString)
            local mapID = tonumber(mapIDText) or 0
            local level = tonumber(levelText) or 0
            if mapID > 0 and level > 0 then
                return math.floor(level)
            end
            return 0
        end

        local function KU_ReadOwnedKeystoneLevel()
            if C_MythicPlus and C_MythicPlus.GetOwnedKeystoneLevel then
                local okLevel, ownedLevel = pcall(C_MythicPlus.GetOwnedKeystoneLevel)
                if okLevel then
                    local n = tonumber(ownedLevel) or 0
                    if n > 0 then
                        return math.floor(n)
                    end
                end
            end
            return 0
        end

        local function KU_RefreshStatusStrip()
            if not (widgets.statusKeystone and widgets.statusLeader and widgets.statusAutomation) then
                return
            end
            local keystoneLink = KU_FindFirstKeystoneLinkInBags and KU_FindFirstKeystoneLinkInBags() or nil
            local hasKeystoneInBags = type(keystoneLink) == "string" and keystoneLink ~= ""
            local keystoneLevel = 0
            if hasKeystoneInBags then
                keystoneLevel = KU_ReadKeystoneLevelFromLink(keystoneLink)
                if keystoneLevel <= 0 then
                    keystoneLevel = KU_ReadOwnedKeystoneLevel()
                end
            end
            local leaderOrAssist = KU_ReadLeaderOrAssistState()
            local autoSlotEnabled = PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.keystoneAutoSlotEnabled)
            local autoStartEnabled = PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.keystoneAutoStartEnabled)

            local automationText = "Auto: Off"
            local automationTone = "warn"
            if autoSlotEnabled and autoStartEnabled then
                automationText = "Auto: Slot+Start"
                automationTone = "good"
            elseif autoSlotEnabled then
                automationText = "Auto: Slot"
                automationTone = "good"
            elseif autoStartEnabled then
                automationText = "Auto: Start"
                automationTone = "good"
            end

            local keystoneText = "Missing"
            local keystoneTone = "warn"
            if hasKeystoneInBags then
                local levelText = (keystoneLevel > 0) and tostring(keystoneLevel) or "?"
                keystoneText = "In Bags (m+" .. levelText .. ")"
                keystoneTone = "good"
            end

            widgets.statusKeystone:SetState(keystoneText, keystoneTone)
            widgets.statusLeader:SetState(leaderOrAssist and "Yes" or "No", leaderOrAssist and "good" or "warn")
            widgets.statusAutomation:SetState(automationText, automationTone)
        end

        local function refreshVisuals()
            if not PortalAuthorityDB then
                ensureDatabase()
                if not PortalAuthorityDB then
                    return
                end
            end

            if widgets.keystoneHelperEnabled and widgets.keystoneHelperEnabled.Refresh then
                widgets.keystoneHelperEnabled:Refresh()
            end
            if widgets.keystoneAutoSlotEnabled and widgets.keystoneAutoSlotEnabled.Refresh then
                widgets.keystoneAutoSlotEnabled:Refresh()
            end
            if widgets.keystoneAutoStartEnabled and widgets.keystoneAutoStartEnabled.Refresh then
                widgets.keystoneAutoStartEnabled:Refresh()
            end
            if widgets.releaseGateEnabled and widgets.releaseGateEnabled.Refresh then
                widgets.releaseGateEnabled:Refresh()
            end
            if widgets.releaseGateModifier and widgets.releaseGateModifier.Refresh then
                widgets.releaseGateModifier:Refresh()
            end
            if widgets.releaseHoldStepper and widgets.releaseHoldStepper.Refresh then
                widgets.releaseHoldStepper:Refresh()
            end

            local releaseEnabled = PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.releaseGateEnabled)
            if widgets.releaseGateModifier and widgets.releaseGateModifier.SetEnabled then
                widgets.releaseGateModifier:SetEnabled(releaseEnabled)
            end
            holdLabel:SetTextColor(releaseEnabled and 1 or 0.6, releaseEnabled and 1 or 0.6, releaseEnabled and 1 or 0.6, 1)
            releaseHoldDesc:SetTextColor(releaseEnabled and 0.72 or 0.58, releaseEnabled and 0.72 or 0.58, releaseEnabled and 0.72 or 0.58, 1)
            if widgets.releaseHoldStepper and widgets.releaseHoldStepper.SetEnabled then
                widgets.releaseHoldStepper:SetEnabled(releaseEnabled)
            end

            KU_RefreshStatusStrip()

            if panelRef and panelRef._kuHydrateKeystoneTooltipVisualOnly then
                panelRef._kuHydrateKeystoneTooltipVisualOnly()
            end
        end

        local function refresh()
            refreshVisuals()
        end

        local function fullRefresh(reason)
            local needsBootstrap = not self._kuBootstrapComplete
            if needsBootstrap then
                refreshVisuals()
                local didLayout = ensureLayoutCurrent("bootstrap")
                refreshVisuals()
                if didLayout then
                    self._kuBootstrapComplete = true
                end
                return
            end
            ensureLayoutCurrent(reason or "full-refresh")
            refreshVisuals()
        end

        local function layout()
            local T = KEYSTONE_UTILITY_LAYOUT
            local P = T.PAGE
            local S = T.SECTION
            local C = T.CARD
            local ST = T.STATUS
            local TT = T.TOOLTIP
            local contentW = KU_ComputeContentWidth()
            local useHostedChrome = isPanelUsingCustomSettingsWindowHost(panelRef)
            scrollChild:SetWidth(contentW)

            local contentLeft = P.CONTENT_LEFT
            local contentRight = contentW - P.CONTENT_RIGHT
            local contentSpan = math.max(0, contentRight - contentLeft)
            local headerSpan = math.max(0, contentRight - P.HEADER_LEFT)
            local y = -P.TOP_PAD
            if useHostedChrome then
                y = y - SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE
            end

            if useHostedChrome then
                setSettingsWindowChromeVisible(header, false, scrollChild)
                setSettingsWindowChromeVisible(widgets.sectionDescriptor, false, scrollChild)
            else
                setSettingsWindowChromeVisible(header, true)
                setSettingsWindowChromeVisible(widgets.sectionDescriptor, true, scrollChild)
                header:ClearAllPoints()
                header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", P.HEADER_LEFT, y)
                header:SetWidth(math.max(T.HEADER_MIN_W, headerSpan))
                if header.SetJustifyH then
                    header:SetJustifyH("LEFT")
                end
                local headerH = KU_MeasureFontStringHeight(header, P.TITLE_FLOOR)
                y = y - headerH - P.TITLE_TO_SECTION_GAP
                y = layoutSettingsSectionDescriptor(
                    widgets.sectionDescriptor,
                    scrollChild,
                    P.HEADER_LEFT,
                    y,
                    math.max(T.HEADER_MIN_W, headerSpan)
                )
            end

            helperHeader:ClearAllPoints()
            helperHeader:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", P.CONTENT_LEFT, y)
            helperHeader:SetWidth(math.max(T.HEADER_MIN_W, contentSpan))
            if helperHeader.SetJustifyH then
                helperHeader:SetJustifyH("LEFT")
            end
            local assistantHeaderH = KU_MeasureFontStringHeight(helperHeader, S.SUBHEADER_FLOOR)
            y = y - assistantHeaderH - S.SUBHEADER_GAP

            widgets.assistantCard:ClearAllPoints()
            widgets.assistantCard:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", contentLeft, y)
            widgets.assistantCard:SetWidth(contentSpan)
            local assistantColumns = KU_ComputeSectionColumns(contentSpan, assistantRows)
            local assistantBottomY = KU_LayoutRows(widgets.assistantCard, assistantRows, assistantColumns)
            local assistantRowsBottomY = assistantBottomY + assistantColumns.rowGap

            local statusStripW = math.max(0, contentSpan - (C.PAD_X * 2))
            local chipGap = ST.CHIP_GAP
            local equalChipW = math.max(T.STATUS_CHIP_MIN_W, math.floor((statusStripW - (chipGap * 2)) / 3))
            local chipTextW = T.STATUS_CHIP_MIN_W
            for _, chip in ipairs(statusChips) do
                chipTextW = math.max(
                    chipTextW,
                    KU_MeasureFontStringWidth(chip and chip.title or nil) + T.STATUS_CHIP_TEXT_PAD,
                    KU_MeasureFontStringWidth(chip and chip.value or nil) + T.STATUS_CHIP_TEXT_PAD
                )
            end
            local chipW = math.max(T.STATUS_CHIP_MIN_W, chipTextW, equalChipW)
            if (chipW * 3) + (chipGap * 2) > statusStripW then
                chipW = math.max(T.STATUS_CHIP_MIN_W, math.floor((statusStripW - (chipGap * 2)) / 3))
            end
            local statusTopY = assistantBottomY + ST.STRIP_Y_NUDGE
            widgets.statusStrip:ClearAllPoints()
            widgets.statusStrip:SetPoint("TOPLEFT", widgets.assistantCard, "TOPLEFT", C.PAD_X, statusTopY)
            widgets.statusStrip:SetSize(math.max(0, (chipW * 3) + (chipGap * 2)), ST.CHIP_H)
            for index, chip in ipairs(statusChips) do
                local chipX = (index - 1) * (chipW + chipGap)
                chip:ClearAllPoints()
                chip:SetPoint("TOPLEFT", widgets.statusStrip, "TOPLEFT", chipX, 0)
                chip:SetSize(chipW, ST.CHIP_H)
            end

            local assistantCardBottomY = math.min(assistantRowsBottomY, statusTopY - ST.CHIP_H)
            local assistantCardH = math.abs(assistantCardBottomY) + C.PAD_BOTTOM
            widgets.assistantCard:SetHeight(assistantCardH)
            y = y - assistantCardH - S.STACK_GAP

            widgets.topSectionDivider:ClearAllPoints()
            widgets.topSectionDivider:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", contentLeft, y + S.DIVIDER_Y_OFFSET)
            widgets.topSectionDivider:SetPoint("TOPRIGHT", scrollChild, "TOPLEFT", contentRight, y + S.DIVIDER_Y_OFFSET)
            widgets.topSectionDivider:SetHeight(S.DIVIDER_H)
            widgets.topSectionDivider:Show()

            releaseHeader:ClearAllPoints()
            releaseHeader:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", P.CONTENT_LEFT, y)
            releaseHeader:SetWidth(math.max(T.HEADER_MIN_W, contentSpan))
            if releaseHeader.SetJustifyH then
                releaseHeader:SetJustifyH("LEFT")
            end
            local releaseHeaderH = KU_MeasureFontStringHeight(releaseHeader, S.SUBHEADER_FLOOR)
            y = y - releaseHeaderH - S.SUBHEADER_GAP

            widgets.releaseCard:ClearAllPoints()
            widgets.releaseCard:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", contentLeft, y)
            widgets.releaseCard:SetWidth(contentSpan)
            local releaseColumns = KU_ComputeSectionColumns(contentSpan, releaseRows)
            local releaseBottomY = KU_LayoutRows(widgets.releaseCard, releaseRows, releaseColumns)
            local releaseRowsBottomY = releaseBottomY + releaseColumns.rowGap
            local releaseCardH = math.abs(releaseRowsBottomY) + C.PAD_BOTTOM
            widgets.releaseCard:SetHeight(releaseCardH)
            y = y - releaseCardH - S.RELEASE_TO_TOOLTIP_GAP

            tooltipHeader:ClearAllPoints()
            tooltipHeader:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", P.CONTENT_LEFT, y)
            tooltipHeader:SetWidth(math.max(T.HEADER_MIN_W, contentSpan))
            if tooltipHeader.SetJustifyH then
                tooltipHeader:SetJustifyH("LEFT")
            end
            local tooltipHeaderH = KU_MeasureFontStringHeight(tooltipHeader, S.TITLE_FLOOR)
            y = y - tooltipHeaderH - S.TOOLTIP_TITLE_TO_SUBHEADER_GAP

            tooltipSubheader:ClearAllPoints()
            tooltipSubheader:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", P.CONTENT_LEFT, y)
            tooltipSubheader:SetWidth(math.max(T.HEADER_MIN_W, contentSpan))
            if tooltipSubheader.SetJustifyH then
                tooltipSubheader:SetJustifyH("LEFT")
            end
            local tooltipSubheaderH = KU_MeasureFontStringHeight(tooltipSubheader, S.SUBHEADER_FLOOR)
            y = y - tooltipSubheaderH - S.TOOLTIP_SUBHEADER_TO_CONTENT_GAP

            local tooltipGeo = KU_ComputeTooltipGeometry(contentSpan)
            local inspectorContentW = tooltipGeo.inspectorContentW
            local availableInlineW = tooltipGeo.availableInlineW
            local inlineBlockW = tooltipGeo.inlineBlockW
            local inspectorPaneH = 0

            tooltipBuilder.root:ClearAllPoints()
            tooltipBuilder.root:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", contentLeft, y)
            tooltipBuilder.root:SetWidth(tooltipGeo.rootW)

            tooltipBuilder.inspectorPane:ClearAllPoints()
            tooltipBuilder.inspectorPane:SetPoint("TOPLEFT", tooltipBuilder.root, "TOPLEFT", 0, 0)
            tooltipBuilder.inspectorPane:SetWidth(tooltipGeo.inspectorW)

            tooltipBuilder.statusSlot:ClearAllPoints()
            tooltipBuilder.statusSlot:SetPoint("TOPLEFT", tooltipBuilder.inspectorPane, "TOPLEFT", TT.INSPECTOR_PAD_X, -TT.INSPECTOR_PAD_Y)
            tooltipBuilder.statusSlot:SetPoint("TOPRIGHT", tooltipBuilder.inspectorPane, "TOPRIGHT", -TT.INSPECTOR_PAD_X, -TT.INSPECTOR_PAD_Y)
            tooltipBuilder.statusSlot:SetHeight(TT.STATUS_H)

            tooltipBuilder.inspectorContent:ClearAllPoints()
            tooltipBuilder.inspectorContent:SetPoint("TOPLEFT", tooltipBuilder.statusSlot, "BOTTOMLEFT", 0, -TT.STATUS_TO_CONTENT_GAP)
            tooltipBuilder.inspectorContent:SetPoint("TOPRIGHT", tooltipBuilder.statusSlot, "BOTTOMRIGHT", 0, -TT.STATUS_TO_CONTENT_GAP)

            tooltipBuilder.inspectorHeader:ClearAllPoints()
            tooltipBuilder.inspectorHeader:SetPoint("TOPLEFT", tooltipBuilder.root, "TOPLEFT", TT.INSPECTOR_PAD_X, -TT.TITLE_TOP_PAD)
            tooltipBuilder.inspectorHeader:SetWidth(math.max(1, tooltipGeo.inspectorW - (TT.INSPECTOR_PAD_X * 2)))
            if tooltipBuilder.inspectorHeader.SetJustifyH then
                tooltipBuilder.inspectorHeader:SetJustifyH("LEFT")
            end

            local rowY = 0

            for _, row in ipairs(tooltipBuilder.rows) do
                local rowW = inspectorContentW
                local rowContentYNudge = 0
                local inlineDrop = false
                if row.inline then
                    inlineDrop = availableInlineW < inlineBlockW
                    if row.cfg and row.cfg.inline and row.cfg.inline.layout == "subline" then
                        inlineDrop = true
                    end
                end
                local rowH = inlineDrop and TT.ROW_H_COMPOUND_DROPPED or TT.BASE_ROW_H
                local topAnchoredMain = inlineDrop
                local mainControlH = KU_MeasureControlHeight(row.main and row.main.control or nil, TT.CONTROL_FLOOR)
                local inlineLabelH = 0
                local inlineControlH = 0
                if inlineDrop and row.inline and row.inline.control and row.inlineLabel then
                    inlineLabelH = KU_MeasureFontStringHeight(row.inlineLabel, TT.INLINE_LABEL_FLOOR)
                    inlineControlH = KU_MeasureControlHeight(row.inline.control, TT.CONTROL_FLOOR)
                    rowH = math.max(
                        TT.BASE_ROW_H,
                        TT.DROPPED_ROW_TOP_PAD + mainControlH + TT.SUBLINE_MAIN_TO_LABEL_GAP + inlineLabelH + TT.SUBLINE_LABEL_TO_CONTROL_GAP + inlineControlH + TT.DROPPED_ROW_BOTTOM_PAD
                    )
                end
                local swatchDropped = false
                if row.colorSwatch then
                    local swatchW = tonumber(row.colorSwatch:GetWidth()) or 22
                    local swatchRight = tooltipGeo.controlColX + tooltipGeo.mainControlW + TT.SWATCH_GAP + swatchW
                    if swatchRight > (rowW - 2) then
                        swatchDropped = true
                        rowH = math.max(rowH, TT.ROW_H_SWATCH_DROPPED)
                    end
                end
                row.container:ClearAllPoints()
                row.container:SetPoint("TOPLEFT", tooltipBuilder.inspectorContent, "TOPLEFT", 0, rowY)
                row.container:SetWidth(rowW)
                row.container:SetHeight(rowH)

                row.label:ClearAllPoints()
                if topAnchoredMain then
                    row.label:SetPoint("TOPLEFT", row.container, "TOPLEFT", tooltipGeo.labelColX, -TT.TOP_LABEL_Y_INSET)
                else
                    row.label:SetPoint("LEFT", row.container, "LEFT", tooltipGeo.labelColX, rowContentYNudge)
                end
                row.label:SetWidth(math.max(T.TOOLTIP_LABEL_MIN_W, tooltipGeo.labelW))

                if row.main and row.main.control then
                    row.main.control:ClearAllPoints()
                    if topAnchoredMain then
                        row.main.control:SetPoint("TOPLEFT", row.container, "TOPLEFT", tooltipGeo.controlColX, -TT.MAIN_TOP_PAD)
                    else
                        row.main.control:SetPoint("LEFT", row.container, "LEFT", tooltipGeo.controlColX, rowContentYNudge)
                    end
                    if row.main.SetWidth then
                        row.main:SetWidth(tooltipGeo.mainControlW)
                    elseif row.main.Layout then
                        row.main:Layout(tooltipGeo.mainControlW)
                    end
                end

                if row.inline and row.inline.control and row.inlineLabel then
                    if inlineDrop then
                        if row.inlineAccent then
                            row.inlineAccent:Show()
                        end
                        local droppedLabelY = -(TT.MAIN_TOP_PAD + mainControlH + TT.SUBLINE_MAIN_TO_LABEL_GAP)
                        local inlineControlY = droppedLabelY - inlineLabelH - TT.SUBLINE_LABEL_TO_CONTROL_GAP
                        row.inlineLabel:ClearAllPoints()
                        row.inlineLabel:SetPoint("TOPLEFT", row.container, "TOPLEFT", tooltipGeo.controlColX + TT.SUBLINE_LABEL_X_INSET, droppedLabelY)
                        row.inlineLabel:SetWidth(math.max(TT.SUBLINE_LABEL_MIN_W, rowW - tooltipGeo.controlColX - TT.SUBLINE_LABEL_RIGHT_PAD))
                        if row.inlineAccent then
                            row.inlineAccent:ClearAllPoints()
                            row.inlineAccent:SetPoint("TOPLEFT", row.container, "TOPLEFT", tooltipGeo.controlColX + TT.SUBLINE_ACCENT_X_INSET, droppedLabelY - TT.SUBLINE_ACCENT_Y_NUDGE)
                            row.inlineAccent:SetHeight(math.max(TT.SUBLINE_ACCENT_MIN_H, inlineLabelH + TT.SUBLINE_ACCENT_HEIGHT_PAD))
                        end
                        row.inline.control:ClearAllPoints()
                        row.inline.control:SetPoint("TOPLEFT", row.container, "TOPLEFT", tooltipGeo.controlColX + TT.SUBLINE_LABEL_X_INSET, inlineControlY)
                    else
                        if row.inlineAccent then
                            row.inlineAccent:Hide()
                        end
                        row.inlineLabel:ClearAllPoints()
                        row.inlineLabel:SetPoint("LEFT", row.container, "LEFT", tooltipGeo.inlineRegionX, 0)
                        row.inlineLabel:SetWidth(TOOLTIP_BUILDER_INLINE_LABEL_W)
                        row.inline.control:ClearAllPoints()
                        row.inline.control:SetPoint(
                            "LEFT",
                            row.container,
                            "LEFT",
                            tooltipGeo.inlineRegionX + TOOLTIP_BUILDER_INLINE_LABEL_W + TT.INLINE_BLOCK_GAP,
                            0
                        )
                    end
                    row.inline:Layout(TOOLTIP_BUILDER_INLINE_TOGGLE_W)
                end

                if row.colorSwatch then
                    row.colorSwatch:ClearAllPoints()
                    if swatchDropped then
                        row.colorSwatch:SetPoint("TOPLEFT", row.container, "TOPLEFT", tooltipGeo.controlColX, -(TT.BASE_ROW_H + TT.DROPPED_ROW_BOTTOM_PAD))
                    else
                        row.colorSwatch:SetPoint(
                            "LEFT",
                            row.container,
                            "LEFT",
                            tooltipGeo.controlColX + tooltipGeo.mainControlW + TT.SWATCH_GAP,
                            0
                        )
                    end
                end

                rowY = rowY - rowH - TT.ROW_GAP
            end

            local usedInspectorH = math.max(0, math.abs(rowY) + TT.INSPECTOR_PAD_Y)
            tooltipBuilder.inspectorContent:SetHeight(usedInspectorH)
            inspectorPaneH = TT.STATUS_H + TT.INSPECTOR_PAD_Y + TT.STATUS_TO_CONTENT_GAP + usedInspectorH + TT.INSPECTOR_PAD_Y
            if inspectorPaneH < TOOLTIP_BUILDER_PREVIEW_H then
                inspectorPaneH = TOOLTIP_BUILDER_PREVIEW_H
            end
            tooltipBuilder.inspectorPane:SetHeight(inspectorPaneH)

            if tooltipGeo.sideBySide then
                tooltipBuilder.previewPane:ClearAllPoints()
                tooltipBuilder.previewPane:SetSize(tooltipGeo.previewW, TOOLTIP_BUILDER_PREVIEW_H)
                tooltipBuilder.previewPane:SetPoint("TOPLEFT", tooltipBuilder.root, "TOPLEFT", tooltipGeo.inspectorW + TT.PANE_GAP, -TT.STICKY_TOP_PAD)
                tooltipBuilder.root:SetHeight(math.max(inspectorPaneH, TOOLTIP_BUILDER_PREVIEW_H))
            else
                tooltipBuilder.previewPane:ClearAllPoints()
                tooltipBuilder.previewPane:SetPoint("TOPLEFT", tooltipBuilder.root, "TOPLEFT", 0, -(inspectorPaneH + TT.PANE_GAP))
                tooltipBuilder.previewPane:SetSize(tooltipGeo.previewW, TOOLTIP_BUILDER_PREVIEW_H)
                tooltipBuilder.root:SetHeight(inspectorPaneH + TT.PANE_GAP + TOOLTIP_BUILDER_PREVIEW_H)
            end

            tooltipBuilder.previewTitle:ClearAllPoints()
            if tooltipGeo.sideBySide then
                tooltipBuilder.previewTitle:SetPoint("TOPLEFT", tooltipBuilder.root, "TOPLEFT", tooltipGeo.inspectorW + TT.PANE_GAP + TT.PREVIEW_TITLE_PAD_X, -TT.TITLE_TOP_PAD)
            else
                tooltipBuilder.previewTitle:SetPoint("TOPLEFT", tooltipBuilder.previewPane, "TOPLEFT", TT.PREVIEW_TITLE_PAD_X, -TT.TITLE_TOP_PAD)
            end

            widgets.keystoneTooltipPreviewAnchor:ClearAllPoints()
            widgets.keystoneTooltipPreviewAnchor:SetPoint("TOPLEFT", tooltipBuilder.previewPane, "TOPLEFT", TT.PREVIEW_BODY_PAD_X, -tooltipGeo.previewAnchorTopInset)
            widgets.keystoneTooltipPreviewAnchor:SetPoint("BOTTOMRIGHT", tooltipBuilder.previewPane, "BOTTOMRIGHT", -TT.PREVIEW_BODY_PAD_X, TT.PREVIEW_BODY_BOTTOM_PAD)

            tooltipBuilder.previewHitLayer:ClearAllPoints()
            tooltipBuilder.previewHitLayer:SetPoint("TOPLEFT", widgets.keystoneTooltipPreviewAnchor, "TOPLEFT", 0, 0)
            tooltipBuilder.previewHitLayer:SetPoint("BOTTOMRIGHT", widgets.keystoneTooltipPreviewAnchor, "BOTTOMRIGHT", 0, 0)

            do
                local firstRow = tooltipBuilder.rows and tooltipBuilder.rows[1] or nil
                local firstRowTop = firstRow and firstRow.container and firstRow.container.GetTop and firstRow.container:GetTop() or nil
                if tooltipGeo.sideBySide and firstRowTop and firstRowTop > 0 then
                    tooltipBuilder._desiredPreviewBodyTopAbs = firstRowTop
                else
                    tooltipBuilder._desiredPreviewBodyTopAbs = nil
                end
            end

            y = y - tooltipBuilder.root:GetHeight() - S.TOOLTIP_BOTTOM_GAP

            scrollChild:SetHeight(math.max(scrollFrame:GetHeight(), math.abs(y) + P.BOTTOM_PAD))
            updateScrollBehavior(scrollFrame, scrollChild)
        end

        self._layout = layout
        self._refreshVisuals = refreshVisuals
        self._refresh = refresh
        self._fullRefresh = fullRefresh
        self._invalidateLayout = invalidateLayout
        self._kuBuildMetricSignature = KU_BuildMetricSignature
        invalidateLayout("initial-build")

        if not self._kuTooltipPreviewEventFrame then
            local eventFrame = CreateFrame("Frame")
            eventFrame:SetScript("OnEvent", function(frameEvent)
                local owner = frameEvent._owner
                if not owner or not owner.IsShown or not owner:IsShown() then
                    return
                end
                if owner._refresh then
                    owner._refresh()
                end
            end)
            self._kuTooltipPreviewEventFrame = eventFrame
        end
        self._kuTooltipPreviewEventFrame._owner = self

        if not self._kuMetricWatcher then
            local metricWatcher = CreateFrame("Frame", nil, self)
            metricWatcher:Hide()
            metricWatcher:SetScript("OnUpdate", function(frameWatcher, elapsed)
                local owner = frameWatcher._owner
                if not owner or not owner.IsShown or not owner:IsShown() then
                    frameWatcher:Hide()
                    return
                end
                frameWatcher._elapsed = (tonumber(frameWatcher._elapsed) or 0) + (tonumber(elapsed) or 0)
                if frameWatcher._elapsed < KEYSTONE_UTILITY_LAYOUT.METRIC_WATCH_INTERVAL then
                    return
                end
                frameWatcher._elapsed = 0
                if not (owner._kuBuildMetricSignature and owner._invalidateLayout and owner._fullRefresh) then
                    return
                end
                if not KU_HasSizedLayoutSurface() then
                    owner._invalidateLayout("metric-unsized")
                    return
                end
                local currentSignature = owner._kuBuildMetricSignature()
                if currentSignature ~= owner._kuMetricSignatureCache then
                    owner._invalidateLayout("metric-signature")
                    owner._fullRefresh("metric-signature")
                end
            end)
            metricWatcher:SetScript("OnHide", function(frameWatcher)
                frameWatcher._elapsed = 0
            end)
            self._kuMetricWatcher = metricWatcher
        end
        self._kuMetricWatcher._owner = self

        registerRefreshCallback(function()
            if self._refresh then
                self._refresh()
            end
        end, self)
        scrollFrame:SetScript("OnSizeChanged", function()
            invalidateLayout("size-changed")
            local useHostedFirstOpen = isPanelUsingCustomSettingsWindowHost(self)
            if useHostedFirstOpen and handleSettingsFirstOpenSizeReady(self, "size_changed") then
                return
            end
            if useHostedFirstOpen and shouldSuppressSettingsFirstOpenExternalRefresh(self) then
                return
            end
            if not (self and self.IsShown and self:IsShown()) then
                return
            end
            if self._fullRefresh then
                self._fullRefresh("size-changed")
            end
        end)

        self._settingsFirstOpenKey = "keystone"
        self._settingsFirstOpenSizeTarget = scrollFrame
        self._settingsFirstOpenRender = function(panel)
            ensureKeystonePanelAnchored(panel)
            ensureDatabase()
            if not (panel and panel._initialized and panel._layout and panel._refresh and panel._fullRefresh) then
                if panel and panel.EnsureBuilt then
                    panel:EnsureBuilt()
                end
            end
            if panel and PortalAuthorityDB and panel._initialized and panel._layout and panel._refresh and panel._fullRefresh and keystoneHasSizedViewport(panel) then
                renderKeystoneWhenReady(panel)
                return
            end
            if panel and panel._fullRefresh then
                panel._fullRefresh("bootstrap")
            end
            startKeystoneRenderBootstrap(panel)
        end
        self._settingsFirstOpenIsReady = function(panel)
            return isPanelUsingCustomSettingsWindowHost(panel)
                and panel ~= nil
                and panel._initialized == true
                and type(panel._layout) == "function"
                and type(panel._refresh) == "function"
                and type(panel._fullRefresh) == "function"
                and keystoneHasSizedViewport(panel)
                and panel._kuRenderBootstrapActive ~= true
                and panel._kuScrollChild ~= nil
                and panel._kuScrollChild.IsShown
                and panel._kuScrollChild:IsShown()
        end
        self._initialized = true
        settingsSearchRuntime.endDescriptorCapture(self)
    end

    ensureKeystonePanelAnchored = function(self)
        local p = self:GetParent()
        if not p then
            return false
        end
        if self._paAnchorParent ~= p or not self._paAnchored then
            self:ClearAllPoints()
            self:SetAllPoints(p)
            self._paAnchorParent = p
        end
        self._paAnchored = true
        return true
    end

    renderKeystoneWhenReady = function(self)
        if not self or not self.IsShown or not self:IsShown() then
            return
        end
        if not (self._initialized and self._layout and self._refresh and self._fullRefresh) then
            return
        end
        if not PortalAuthorityDB then
            return
        end
        ensureKeystonePanelAnchored(self)
        if self._sizingFrame and self._sizingFrame.Show then
            self._sizingFrame:Show()
            if self._sizingFrame.SetVerticalScroll then
                self._sizingFrame:SetVerticalScroll(0)
            end
        end
        if self._kuScrollChild and self._kuScrollChild.Show then
            self._kuScrollChild:Show()
        end
        if self._fullRefresh then
            self._fullRefresh("render-ready")
        end
    end

    keystoneHasSizedViewport = function(self)
        local readyFrame = (self and self._sizingFrame) or self
        if not readyFrame then
            return false
        end
        local w = tonumber(readyFrame:GetWidth()) or 0
        local h = tonumber(readyFrame:GetHeight()) or 0
        return (w > 1 and h > 1)
    end

    startKeystoneRenderBootstrap = function(self)
        if not self then
            return
        end
        local watcher = self._kuRenderBootstrapWatcher
        if not watcher then
            watcher = CreateFrame("Frame", nil, self)
            watcher:Hide()
            watcher:SetScript("OnUpdate", function(frameWatcher, elapsed)
                local owner = frameWatcher._owner
                if not owner or not owner.IsShown or not owner:IsShown() then
                    frameWatcher:Hide()
                    return
                end
                frameWatcher._elapsed = (tonumber(frameWatcher._elapsed) or 0) + (tonumber(elapsed) or 0)
                ensureDatabase()
                if not (owner._initialized and owner._layout and owner._refresh and owner._fullRefresh) then
                    owner:EnsureBuilt()
                end
                ensureKeystonePanelAnchored(owner)
                if PortalAuthorityDB and owner._initialized and owner._layout and owner._refresh and owner._fullRefresh and keystoneHasSizedViewport(owner) then
                    renderKeystoneWhenReady(owner)
                    frameWatcher:Hide()
                    return
                end
                -- Intentionally no hard timeout: keep retrying while this panel stays shown,
                -- so first-open can recover without requiring a section switch.
            end)
            watcher:SetScript("OnHide", function(frameWatcher)
                frameWatcher._elapsed = 0
                if frameWatcher._owner then
                    frameWatcher._owner._kuRenderBootstrapActive = false
                end
            end)
            self._kuRenderBootstrapWatcher = watcher
        end
        watcher._owner = self
        watcher._elapsed = 0
        if not self._kuRenderBootstrapActive then
            self._kuRenderBootstrapActive = true
            watcher:Show()
        end
    end

    panel:SetScript("OnShow", function(self)
        ensureKeystonePanelAnchored(self)
        ensureDatabase()
        self:EnsureBuilt()
        if self._kuTooltipPreviewEventFrame then
            self._kuTooltipPreviewEventFrame._owner = self
            self._kuTooltipPreviewEventFrame:RegisterEvent("GET_ITEM_INFO_RECEIVED")
            self._kuTooltipPreviewEventFrame:RegisterEvent("BAG_UPDATE_DELAYED")
            self._kuTooltipPreviewEventFrame:RegisterEvent("CHALLENGE_MODE_MAPS_UPDATE")
            self._kuTooltipPreviewEventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
        end
        if self._kuMetricWatcher then
            self._kuMetricWatcher._owner = self
            self._kuMetricWatcher._elapsed = 0
            self._kuMetricWatcher:Show()
        end

        if isPanelUsingCustomSettingsWindowHost(self) and self._paFirstOpenState == "pending" then
            resetSettingsFirstOpenPanelState(self)
        end
        if isPanelUsingCustomSettingsWindowHost(self) and handleSettingsFirstOpenPanelShow(self) then
            return
        end

        if PortalAuthorityDB and self._initialized and self._layout and self._refresh and self._fullRefresh and keystoneHasSizedViewport(self) then
            renderKeystoneWhenReady(self)
        else
            if self._fullRefresh then
                self._fullRefresh("bootstrap")
            end
            startKeystoneRenderBootstrap(self)
        end

        if C_Timer and C_Timer.After then
            C_Timer.After(0, function()
                if not self or not self:IsShown() then return end
                ensureDatabase()
                if not (self._initialized and self._layout and self._refresh and self._fullRefresh) then
                    self:EnsureBuilt()
                end
                if PortalAuthorityDB and self._initialized and self._layout and self._refresh and self._fullRefresh and keystoneHasSizedViewport(self) then
                    renderKeystoneWhenReady(self)
                else
                    if self._fullRefresh then
                        self._fullRefresh("bootstrap")
                    end
                    startKeystoneRenderBootstrap(self)
                end
            end)
        end
    end)
    panel:HookScript("OnHide", function(self)
        if isPanelUsingCustomSettingsWindowHost(self) or isSettingsFirstOpenSettlePending(self) then
            handleSettingsFirstOpenPanelHide(self)
        end
        if self and self._kuRenderBootstrapWatcher then
            self._kuRenderBootstrapWatcher:Hide()
        end
        if self and self._kuMetricWatcher then
            self._kuMetricWatcher:Hide()
        end
        if self and self._kuTooltipPreviewEventFrame then
            self._kuTooltipPreviewEventFrame:UnregisterAllEvents()
        end
        if self and self._kuCloseTooltipBuilderPickers then
            self._kuCloseTooltipBuilderPickers()
        end
    end)

    return panel
end

local function createCombatAlertsPanel()
    local panel = CreateFrame("Frame")
    panel.name = "Combat Alerts"
    panel._paSearchSectionKey = "combat"
    panel._paSearchSectionName = panel.name

    panel.EnsureBuilt = function(self)
        -- Only treat as initialized if the panel actually finished wiring layout/refresh.
        if self._initialized and self._layout and self._refresh then return end
        resetSettingsFirstOpenPanelState(self)
        ensureDatabase()
        settingsSearchRuntime.beginDescriptorCapture(self)

        local scrollFrame, scrollChild = createScrollableChild(self)
        if not scrollFrame or not scrollChild then
            settingsSearchRuntime.endDescriptorCapture(self)
            return
        end
        self._sizingFrame = scrollFrame

        local widgets = {}
        local panelRef = self

        local function onApply()
            if PortalAuthority and PortalAuthority.ApplyCombatAlertsSettings then
                PortalAuthority:ApplyCombatAlertsSettings()
            end

            -- If test mode is currently active, immediately re-render the test message so changes are visible live.
            if PortalAuthority
                and PortalAuthority.DeathAlerts_IsTestModeActive
                and PortalAuthority.DeathAlerts_RefreshTestMode
                and PortalAuthority:DeathAlerts_IsTestModeActive()
            then
                PortalAuthority:DeathAlerts_RefreshTestMode()
            end

            if panelRef and panelRef._refresh then
                panelRef._refresh()
            end
        end

        local function getDeathAlertSoundChoices(currentValue)
            local media = getPortalMedia()
            if media and media.GetChoices then
                return media.GetChoices("sound", {
                    includeNone = true,
                    includeBuiltinIDs = true,
                    currentValue = currentValue,
                }) or {}
            end
            return buildFallbackSoundChoices(currentValue, {
                includeNone = true,
                includeBuiltinIDs = true,
            })
        end

        local function previewDeathAlertSound(value)
            if value == nil or value == "" then
                return
            end

            local soundFile = value
            if PortalAuthority and PortalAuthority.GetDeathAlertSoundFile then
                soundFile = PortalAuthority:GetDeathAlertSoundFile(value)
            end
            if not soundFile or soundFile == "" then
                return
            end

            local channel = "Master"
            if PortalAuthorityDB and type(PortalAuthorityDB.deathAlertSoundChannel) == "string" and PortalAuthorityDB.deathAlertSoundChannel ~= "" then
                channel = PortalAuthorityDB.deathAlertSoundChannel
            elseif PortalAuthority and PortalAuthority.defaults and type(PortalAuthority.defaults.deathAlertSoundChannel) == "string" and PortalAuthority.defaults.deathAlertSoundChannel ~= "" then
                channel = PortalAuthority.defaults.deathAlertSoundChannel
            end

            if type(soundFile) == "number" and PlaySound then
                PlaySound(soundFile, channel)
            elseif PlaySoundFile then
                PlaySoundFile(soundFile, channel)
            end
        end

        local function stylePremiumEditBox(edit, textSize)
            if not edit then
                return
            end
            textSize = tonumber(textSize) or 12
            edit:SetAutoFocus(false)
            edit:SetMultiLine(false)
            edit:SetTextInsets(8, 8, 0, 0)
            edit:SetTextColor(1, 1, 1, 1)
            edit:SetHighlightColor(1, 1, 1, 0.25)
            applyGlobalFontToObject(edit, textSize)

            if not edit._paPremiumBg then
                edit._paPremiumBg = edit:CreateTexture(nil, "ARTWORK")
                edit._paPremiumBg:SetAllPoints(edit)
                edit._paPremiumBg:SetTexture("Interface\\Buttons\\WHITE8x8")
                edit._paPremiumBg:SetVertexColor(0.10, 0.11, 0.14, 0.95)

                edit._paPremiumBorder = CreateFrame("Frame", nil, edit, "BackdropTemplate")
                edit._paPremiumBorder:SetPoint("TOPLEFT", edit, "TOPLEFT", -1, 1)
                edit._paPremiumBorder:SetPoint("BOTTOMRIGHT", edit, "BOTTOMRIGHT", 1, -1)
                edit._paPremiumBorder:SetBackdrop({
                    edgeFile = "Interface\\Buttons\\WHITE8x8",
                    edgeSize = 1,
                })
                edit._paPremiumBorder:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
            end

            local function hideTemplateChrome()
                if edit.Left then edit.Left:SetAlpha(0) end
                if edit.Middle then edit.Middle:SetAlpha(0) end
                if edit.Right then edit.Right:SetAlpha(0) end
            end

            local function applyVisual()
                hideTemplateChrome()
                if edit:HasFocus() then
                    edit._paPremiumBg:SetVertexColor(0.12, 0.13, 0.17, 0.95)
                    edit._paPremiumBorder:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                else
                    edit._paPremiumBg:SetVertexColor(0.10, 0.11, 0.14, 0.95)
                    edit._paPremiumBorder:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                end
            end

            edit:HookScript("OnShow", applyVisual)
            edit:HookScript("OnEditFocusGained", applyVisual)
            edit:HookScript("OnEditFocusLost", applyVisual)
            applyVisual()
        end

        local function createPremiumPickerButton(parent, labelText, optionsProvider, getter, setter, onApplyCallback, pickerOpts)
            pickerOpts = type(pickerOpts) == "table" and pickerOpts or {}
            local label = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
            label:SetText(labelText or "")

            local button = CreateFrame("Button", nil, parent, "BackdropTemplate")
            button:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
            button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
            button:SetHeight(22)
            button:SetWidth(math.max(132, math.floor(tonumber(pickerOpts.width) or 180)))

            local text = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 11)
            text:SetPoint("LEFT", button, "LEFT", 8, 0)
            text:SetPoint("RIGHT", button, "RIGHT", -18, 0)
            text:SetJustifyH("LEFT")
            text:SetTextColor(0.92, 0.92, 0.92, 1)

            local caret = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 10)
            caret:SetPoint("RIGHT", button, "RIGHT", -7, 0)
            caret:SetText("v")
            caret:SetTextColor(0.76, 0.76, 0.78, 1)
            button._paSelectEnabled = true
            local currentButtonLabel = ""

            local function setButtonLabel(labelText)
                currentButtonLabel = tostring(labelText or "")
                text:SetWordWrap(false)
                if text.SetMaxLines then
                    text:SetMaxLines(1)
                end
                local maxWidth = math.max(20, (button:GetWidth() or 0) - 26)
                text:SetWidth(maxWidth)
                text:SetText(currentButtonLabel)
                if pickerOpts and pickerOpts.ellipsis == false then
                    return
                end
                if text:GetStringWidth() <= maxWidth then
                    return
                end

                local source = currentButtonLabel
                local cut = string.len(source)
                while cut > 0 do
                    local candidate = string.sub(source, 1, cut) .. "..."
                    text:SetText(candidate)
                    if text:GetStringWidth() <= maxWidth then
                        return
                    end
                    cut = cut - 1
                end
                text:SetText("...")
            end

            local picker = CreatePicker(UIParent, {}, function(value)
                local selectedValue = value
                if selectedValue == nil then
                    selectedValue = ""
                end
                if setter then
                    setter(selectedValue)
                end
                if onApplyCallback then
                    onApplyCallback()
                end
            end, {
                title = tostring(pickerOpts.title or "Select Option"),
                searchHint = tostring(pickerOpts.searchHint or "Search"),
                width = tonumber(pickerOpts.pickerWidth) or 420,
                height = tonumber(pickerOpts.pickerHeight) or 360,
                minHeight = tonumber(pickerOpts.minHeight),
                showSecondary = false,
                useOptionFontPreview = pickerOpts.useOptionFontPreview and true or false,
                useOptionTexturePreview = pickerOpts.useOptionTexturePreview and true or false,
                previewFontSize = tonumber(pickerOpts.previewFontSize) or 12,
                rowHeight = tonumber(pickerOpts.rowHeight) or 26,
                showClearButton = false,
                noSearch = pickerOpts.noSearch and true or false,
                hideTitle = pickerOpts.hideTitle and true or false,
                hideScrollBar = pickerOpts.hideScrollBar and true or false,
                onOptionRightClick = pickerOpts.onOptionRightClick,
                footerHint = tostring(pickerOpts.footerHint or ""),
            })

            local function applyVisual(hovered)
                applySettingsWindowSelectButtonChrome(
                    button,
                    text,
                    caret,
                    hovered,
                    false,
                    button._paSelectEnabled ~= false,
                    function()
                        if hovered then
                            button:SetBackdropColor(0.16, 0.17, 0.20, 0.95)
                            button:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                            caret:SetTextColor(0.88, 0.88, 0.90, 1)
                        else
                            button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
                            button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                            caret:SetTextColor(0.76, 0.76, 0.78, 1)
                        end
                    end
                )
            end

            button:SetScript("OnEnter", function()
                applyVisual(true)
            end)
            button:SetScript("OnLeave", function()
                applyVisual(false)
            end)

            local function buildPickerOptions()
                local built = {}
                for _, option in ipairs(optionsProvider and optionsProvider() or {}) do
                    local value = option.value
                    if value == nil then
                        value = ""
                    end
                    built[#built + 1] = {
                        value = value,
                        label = tostring(option.label or value),
                        buttonLabel = tostring(option.buttonLabel or option.label or value),
                        secondary = tostring(option.secondary or ""),
                        previewFontPath = option.previewFontPath,
                        previewTexturePath = option.previewTexturePath or option.path,
                        aliases = option.aliases,
                    }
                end
                if #built == 0 then
                    built[1] = { value = "", label = "None", buttonLabel = "None", secondary = "" }
                end
                return built
            end

            local function resolveSelection(rawValue, options)
                local selected = rawValue
                if selected == nil then
                    selected = ""
                end
                local selectedKey = tostring(selected)
                local selectedLabel = nil
                local emptyFallbackLabel = tostring(pickerOpts.emptyLabel or "None")
                for _, option in ipairs(options or {}) do
                    if tostring(option.value or "") == selectedKey then
                        selected = option.value
                        selectedLabel = tostring(option.buttonLabel or option.label or selectedKey)
                        break
                    end
                end
                if not selectedLabel then
                    if selectedKey == "" then
                        selected = ""
                        selectedLabel = emptyFallbackLabel
                    else
                        local first = options and options[1] or nil
                        if first then
                            selected = first.value
                            selectedLabel = tostring(first.buttonLabel or first.label or tostring(selected or ""))
                            if setter then
                                setter(selected)
                            end
                        else
                            selected = ""
                            selectedLabel = "None"
                        end
                    end
                end
                return selected, selectedLabel
            end

            local spec = { kind = "picker_button", label = label, control = button, text = text, picker = picker }

            spec.SetWidth = function(_, newWidth)
                button:SetWidth(math.max(132, math.floor(tonumber(newWidth) or pickerOpts.width or 180)))
                setButtonLabel(currentButtonLabel)
            end

            spec.SetEnabled = function(_, enabled)
                local allow = enabled and true or false
                button._paSelectEnabled = allow
                button:EnableMouse(allow)
                button:SetAlpha(allow and 1 or 0.6)
                text:SetAlpha(allow and 1 or 0.65)
                caret:SetAlpha(allow and 1 or 0.65)
                applyVisual(false)
            end

            spec.Refresh = function()
                local options = buildPickerOptions()
                picker:SetOptions(options)
                local selectedValue, selectedLabel = resolveSelection(getter and getter() or "", options)
                picker:SetSelectedValue(selectedValue)
                setButtonLabel(selectedLabel ~= "" and selectedLabel or "None")
            end

            button:SetScript("OnClick", function()
                if picker and picker.IsShown and picker:IsShown() then
                    picker:Close()
                    return
                end
                spec.Refresh()
                picker:Open(button)
            end)
            button:HookScript("OnSizeChanged", function()
                setButtonLabel(currentButtonLabel)
            end)
            registerSettingsWindowVisualRefresh(button, function()
                applyVisual(button.IsMouseOver and button:IsMouseOver() or false)
            end)

            spec.Refresh()
            return spec
        end

        local header = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormalLarge", 14)
        header:SetText("|cffffd100Combat Alerts|r")
        widgets.sectionDescriptor = createSettingsSectionDescriptor(scrollChild, "Control death alerts, audio, and on-screen messaging.")
        local deathHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        deathHeader:SetText("Death Alerts")
        local deathDesc = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        deathDesc:SetText("Audio and/or on-screen alerts when a Tank/Healer/DPS (or you) dies in your party/raid.")
        deathDesc:SetTextColor(0.72, 0.72, 0.72, 1)
        deathDesc:SetJustifyH("LEFT")

        widgets.soundColumnLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.soundColumnLabel:SetText("Alert Sound |cff7f7f7f(select NONE for visual only)|r")
        widgets.soundColumnLabel:SetJustifyH("LEFT")
        widgets.screenColumnLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.screenColumnLabel:SetText("On-screen")
        widgets.screenColumnLabel:SetJustifyH("LEFT")
        widgets.roleHeaderRow = CreateFrame("Frame", nil, scrollChild)
        local applyOnScreenRuleWrite
        local COMBAT_ALERTS_LAYOUT = {
            GRID_UNIT = 8,
            TOP_PAD = 20,
            CONTENT_LEFT = 20,
            CONTENT_RIGHT = 20,
            HEADER_LEFT = 16,
            HEADER_FLOOR = 16,
            HEADER_BOTTOM_GAP = 14,
            DEATH_HEADER_FLOOR = 12,
            DEATH_HEADER_BOTTOM_GAP = 8,
            DEATH_DESC_FLOOR = 11,
            DEATH_DESC_BOTTOM_GAP = 17,
            LOCK_LABEL_TO_TOGGLE_GAP = 12,
            LOCK_TOGGLE_TO_RESET_GAP = 12,
            LOCK_HELPER_MULTIPLIER = 0.625,
            LOCK_DIVIDER_MULTIPLIER = 1.25,
            LOCK_ROW_FLOOR = 22,
            LOCK_SEGMENT_BUTTON_TEXT_PAD_X = 20,
            RESET_W = 102,
            RESET_H = 22,
            LOCK_BUTTON_TEXT_FALLBACK_W = 36,
            LOCK_TOGGLE_MIN_W = 96,
            LOCK_ROW_SEED_H = 22,
            ROLE_BADGE_TEXT_INSET_X = 8,
            FORCED_HELPER_Y_NUDGE = -3,
            ROLE_HEADER_Y_NUDGE = -2,
            ROLE_LABEL_PREF_W = 72,
            ROLE_LABEL_MID_W = 56,
            ROLE_LABEL_MIN_W = 48,
            ENABLE_PREF_W = 148,
            ENABLE_NARROW_W = 132,
            SCREEN_W = 128,
            ROLE_TO_ENABLE_GAP = 10,
            ENABLE_TO_SOUND_GAP = 14,
            SOUND_TO_SCREEN_GAP = 12,
            SOUND_TARGET_MIN_W = 176,
            SOUND_MIN_W = 120,
            ROLE_ROW_FLOOR = 44,
            ROLE_ROW_SEED_H = 44,
            ROLE_TOGGLE_LAYOUT_W = 124,
            ROLE_HELPER_LEFT_Y_NUDGE = -1,
            ROLE_HELPER_MIN_W = 16,
            SOUND_CONTROL_SEED_W = 196,
            SOUND_TEXT_MIN_W = 20,
            SOUND_TEXT_RIGHT_PAD = 26,
            ROLE_HEADER_ROW_FLOOR = 16,
            ROLE_HEADER_BOTTOM_GAP = 4,
            ROLE_BADGE_MIN_W = 56,
            ROLE_BADGE_H = 24,
            ROLE_HELPER_TOP_GAP = 6,
            ROLE_TO_MESSAGE_GAP = 18,
            MESSAGE_AREA_MIN_W = 260,
            MESSAGE_RIGHT_RAIL_W = 190,
            MESSAGE_INTER_BLOCK_GAP = 16,
            MESSAGE_INPUT_MIN_W = 300,
            MESSAGE_PREVIEW_MIN_W = 250,
            MESSAGE_INSERT_MIN_W = 236,
            MESSAGE_EDIT_FLOOR = 22,
            MESSAGE_EDIT_SEED_W = 170,
            MESSAGE_EDIT_SEED_H = 22,
            PREVIEW_LABEL_MIN_W = 30,
            PREVIEW_HELP_MIN_W = 60,
            INSERT_LABEL_MIN_W = 24,
            TOKEN_CHIP_SEED_W = 58,
            PREVIEW_ROW_GAP_FLOOR = 4,
            PREVIEW_LABEL_TO_HELP_GAP = 6,
            PREVIEW_HELP_WIDTH_PAD = 8,
            CHIPS_ROW_GAP_FLOOR = 4,
            INSERT_LABEL_TO_CHIPS_GAP = 6,
            TOKEN_CHIP_H = 19,
            TOKEN_CHIP_GAP = 5,
            MESSAGE_BRANCH_STACK_GAP = 16,
            MESSAGE_TO_SETTINGS_GAP = 16,
            RIGHT_TOGGLE_W = 124,
            RIGHT_LABEL_GAP = 8,
            RIGHT_CONTROL_GAP = 8,
            RIGHT_STACK_GAP = 8,
            RIGHT_LABEL_FLOOR = 12,
            RIGHT_CONTROL_FLOOR = 22,
            SETTINGS_CONTROL_OFFSET = 172,
            SETTINGS_DROPDOWN_MIN_W = 140,
            SETTINGS_DROPDOWN_MAX_W = 190,
            SETTINGS_ROW_FLOOR = 32,
            SETTINGS_LABEL_MIN_W = 80,
            SETTINGS_ROW_MIN_W = 260,
            FONT_CONTROL_MIN_W = 120,
            CHANNEL_HINT_MIN_W = 20,
            COORDS_W = 112,
            FONT_STEPPER_W = 52,
            COORDS_EDIT_SEED_W = 72,
            COORDS_EDIT_SEED_H = 22,
            FONT_PICKER_SEED_W = 154,
            FONT_SIZE_EDIT_SEED_W = 36,
            FONT_SIZE_EDIT_SEED_H = 22,
            FONT_SIZE_FALLBACK_MIN_W = 44,
            FONT_ROW_SEED_H = 30,
            CHANNEL_PICKER_SEED_W = 190,
            HELPER_FLOOR = 10,
            LABEL_FLOOR = 12,
            CHANNEL_HINT_GAP = 6,
            BOTTOM_PAD = 20,
            HEADER_MIN_W = 220,
            HELPER_MIN_W = 120,
            DIVIDER_H = 1,
            FALLBACK_CONTENT_W = 620,
            OFFSCREEN_X = -5000,
            OFFSCREEN_Y = -5000,
        }
        local ROLE_BADGE_TEXT_INSET_X = COMBAT_ALERTS_LAYOUT.ROLE_BADGE_TEXT_INSET_X
        local FORCED_HELPER_Y_NUDGE = COMBAT_ALERTS_LAYOUT.FORCED_HELPER_Y_NUDGE
        local HEADER_Y_NUDGE = COMBAT_ALERTS_LAYOUT.ROLE_HEADER_Y_NUDGE
        local TOKEN_CHIP_H = COMBAT_ALERTS_LAYOUT.TOKEN_CHIP_H
        local TOKEN_CHIP_GAP = COMBAT_ALERTS_LAYOUT.TOKEN_CHIP_GAP

        local function safeSetDropWidth(dd, w)
            if dd == nil then return end
            local name = dd.GetName and dd:GetName() or nil
            if UIDropDownMenu_SetWidth and name and _G[name .. "Button"] then
                UIDropDownMenu_SetWidth(dd, w)
                return
            end
            if dd.SetWidth then
                dd:SetWidth(w)
            end
        end

        local function setSingleLineEllipsis(fs, fullText, maxWidth)
            if not fs then
                return
            end
            local source = tostring(fullText or "")
            fs:SetWordWrap(false)
            if fs.SetMaxLines then
                fs:SetMaxLines(1)
            end
            fs:SetWidth(maxWidth or 0)
            fs:SetText(source)
            if (maxWidth or 0) <= 0 then
                return
            end
            if (fs.GetStringWidth and fs:GetStringWidth() or 0) <= maxWidth then
                return
            end
            local cut = string.len(source)
            while cut > 0 do
                local candidate = string.sub(source, 1, cut) .. "..."
                fs:SetText(candidate)
                if (fs.GetStringWidth and fs:GetStringWidth() or 0) <= maxWidth then
                    return
                end
                cut = cut - 1
            end
            fs:SetText("...")
        end

        local function measureFontStringHeight(fs, floor)
            local measured = 0
            if fs and fs.GetStringHeight then
                measured = math.ceil(fs:GetStringHeight() or 0)
            end
            return math.max(tonumber(floor) or 0, measured)
        end

        local function measureControlHeight(widget, floor)
            local measured = 0
            if widget and widget.GetHeight then
                measured = math.ceil(widget:GetHeight() or 0)
            end
            return math.max(tonumber(floor) or 0, measured)
        end

        local function setOffscreenTopLeft(frame)
            if not frame then
                return
            end
            if frame.Hide then
                frame:Hide()
            end
            frame:ClearAllPoints()
            frame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", COMBAT_ALERTS_LAYOUT.OFFSCREEN_X, COMBAT_ALERTS_LAYOUT.OFFSCREEN_Y)
        end

        local function setCombatWidgetVisible(frame, visible)
            if not frame then
                return
            end
            if visible then
                if frame.Show then
                    frame:Show()
                end
            else
                if frame.Hide then
                    frame:Hide()
                end
            end
        end

        local function computeCombatAlertsRoleGeometry(contentW)
            local T = COMBAT_ALERTS_LAYOUT
            local G = {
                contentW = contentW,
                contentLeft = T.CONTENT_LEFT,
                contentRight = contentW - T.CONTENT_RIGHT,
                roleLabelW = T.ROLE_LABEL_PREF_W,
                enableW = T.ENABLE_PREF_W,
                screenW = T.SCREEN_W,
            }
            G.roleX = G.contentLeft
            G.screenX = G.contentRight - G.screenW
            local function recompute()
                G.enableX = G.roleX + G.roleLabelW + T.ROLE_TO_ENABLE_GAP
                G.soundX = G.enableX + G.enableW + T.ENABLE_TO_SOUND_GAP
                G.soundW = G.screenX - T.SOUND_TO_SCREEN_GAP - G.soundX
            end
            recompute()
            if G.soundW < T.SOUND_TARGET_MIN_W then
                G.roleLabelW = T.ROLE_LABEL_MID_W
                recompute()
            end
            if G.soundW < T.SOUND_TARGET_MIN_W then
                G.roleLabelW = T.ROLE_LABEL_MIN_W
                recompute()
            end
            if G.soundW < T.SOUND_TARGET_MIN_W then
                G.enableW = T.ENABLE_NARROW_W
                recompute()
            end
            if G.soundW < T.SOUND_MIN_W then
                G.soundW = T.SOUND_MIN_W
                G.soundX = math.min(G.soundX, G.screenX - T.SOUND_TO_SCREEN_GAP - G.soundW)
            end
            return G
        end

        local function computeCombatAlertsLockGeometry(contentW, lockLabel)
            local T = COMBAT_ALERTS_LAYOUT
            local lockLabelW = lockLabel and math.ceil(lockLabel:GetStringWidth() or 0) or 0
            local lockLabelH = lockLabel and math.ceil(lockLabel:GetStringHeight() or 0) or T.LABEL_FLOOR
            local unit = math.max(1, lockLabelH)
            local lockBtnTextW = 0
            if widgets.lockPosition and type(widgets.lockPosition.buttons) == "table" then
                for _, btn in ipairs(widgets.lockPosition.buttons) do
                    if btn and btn.Text then
                        lockBtnTextW = math.max(lockBtnTextW, math.ceil(btn.Text:GetStringWidth() or 0))
                    end
                end
            end
            lockBtnTextW = math.max(lockBtnTextW, T.LOCK_BUTTON_TEXT_FALLBACK_W)
            local lockToggleWFromContent = ((lockBtnTextW + (T.LOCK_SEGMENT_BUTTON_TEXT_PAD_X * 2)) * 2) + 4
            local lockToggleWMax = math.max(
                T.LOCK_TOGGLE_MIN_W,
                (contentW - T.CONTENT_RIGHT) - (T.CONTENT_LEFT + lockLabelW + T.LOCK_LABEL_TO_TOGGLE_GAP + T.LOCK_TOGGLE_TO_RESET_GAP + T.RESET_W)
            )
            local lockToggleW = math.max(T.LOCK_TOGGLE_MIN_W, math.min(lockToggleWFromContent, lockToggleWMax))
            local toggleX = (lockLabelW > 0) and (lockLabelW + T.LOCK_LABEL_TO_TOGGLE_GAP) or 0
            local resetX = toggleX + lockToggleW + T.LOCK_TOGGLE_TO_RESET_GAP
            return {
                labelW = lockLabelW,
                labelH = lockLabelH,
                helperGap = unit * T.LOCK_HELPER_MULTIPLIER,
                dividerGap = unit * T.LOCK_DIVIDER_MULTIPLIER,
                toggleW = lockToggleW,
                toggleX = toggleX,
                resetX = resetX,
                rowW = math.max(1, contentW - T.CONTENT_RIGHT - T.CONTENT_LEFT),
            }
        end

        local function computeCombatAlertsMessageGeometry(contentW)
            local T = COMBAT_ALERTS_LAYOUT
            local messageAreaW = math.max(T.MESSAGE_AREA_MIN_W, contentW - T.CONTENT_LEFT - T.CONTENT_RIGHT)
            local leftBlockMinW = math.max(T.MESSAGE_INPUT_MIN_W, T.MESSAGE_PREVIEW_MIN_W, T.MESSAGE_INSERT_MIN_W)
            local canSideBySide = messageAreaW >= (leftBlockMinW + T.MESSAGE_RIGHT_RAIL_W + T.MESSAGE_INTER_BLOCK_GAP)
            return {
                areaW = messageAreaW,
                canSideBySide = canSideBySide,
                leftGroupW = canSideBySide and (messageAreaW - T.MESSAGE_RIGHT_RAIL_W - T.MESSAGE_INTER_BLOCK_GAP) or messageAreaW,
                rightRailW = T.MESSAGE_RIGHT_RAIL_W,
                interBlockGap = T.MESSAGE_INTER_BLOCK_GAP,
            }
        end

        local function computeCombatAlertsSettingsGeometry(contentW)
            local T = COMBAT_ALERTS_LAYOUT
            local controlX = T.CONTENT_LEFT + T.SETTINGS_CONTROL_OFFSET
            local dropdownW = math.max(
                T.SETTINGS_DROPDOWN_MIN_W,
                math.min(T.SETTINGS_DROPDOWN_MAX_W, contentW - controlX - T.CONTENT_RIGHT)
            )
            return {
                labelX = T.CONTENT_LEFT,
                controlX = controlX,
                labelW = math.max(T.SETTINGS_LABEL_MIN_W, T.SETTINGS_CONTROL_OFFSET - T.GRID_UNIT),
                rowW = math.max(T.SETTINGS_ROW_MIN_W, contentW - T.CONTENT_LEFT - T.CONTENT_RIGHT),
                dropdownW = dropdownW,
            }
        end

        local function createRoleRow(prefix, roleKey, roleLabel)
            local row = {}
            row.prefix = prefix
            row.roleKey = roleKey
            row.roleLabel = roleLabel
            row.enabledValue = false
            row._helperFallbackText = nil
            row._helperFallbackColor = nil
            row._roleHelperFullText = ""
            row._roleHelperColor = nil
            row._onScreenHelperFullText = ""
            row._paWasForcedByNone = false
            row.container = CreateFrame("Frame", nil, scrollChild)
            row.container:SetSize(1, COMBAT_ALERTS_LAYOUT.ROLE_ROW_SEED_H)
            row.enabled = createPremiumSegmentedChoice(scrollChild, "", nil, {
                { label = "Disabled", value = false, toggleState = "off" },
                { label = "Enabled", value = true, toggleState = "on" },
            }, function(v)
                if PortalAuthorityDB then
                    PortalAuthorityDB[prefix .. "Enabled"] = PA_SafeBool(v)
                end
                row.enabledValue = PA_SafeBool(v)
                if applyOnScreenRuleWrite and PortalAuthorityDB then
                    applyOnScreenRuleWrite(row, PortalAuthorityDB, row.enabledValue)
                end
                onApply()
            end, {
                semantic = "toggle",
                normalizeValue = function(v)
                    return PA_SafeBool(v)
                end,
                getValue = function()
                    return PA_SafeBool(row.enabledValue)
                end,
                setValue = function(v)
                    row.enabledValue = PA_SafeBool(v)
                end,
            })
            if row.enabled and row.enabled.label then
                row.enabled.label:SetText("")
                row.enabled.label:Hide()
            end
            if row.enabled and row.enabled.Layout then
                row.enabled:Layout(COMBAT_ALERTS_LAYOUT.ROLE_TOGGLE_LAYOUT_W)
            end
            row.icon = scrollChild:CreateTexture(nil, "ARTWORK")
            row.icon:Hide()
            row.roleBadge = CreateFrame("Frame", nil, row.container, "BackdropTemplate")
            row.roleBadge:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            row.roleBadge:SetBackdropColor(0.07, 0.08, 0.10, 0.78)
            row.roleBadge:SetBackdropBorderColor(0.18, 0.20, 0.24, 0.56)
            row.roleBadge:EnableMouse(false)
            row.roleText = createStyledFontString(row.roleBadge, "ARTWORK", "GameFontHighlight", 12)
            row.roleText:SetJustifyH("LEFT")
            row.roleText:SetWordWrap(false)
            row.roleText:SetPoint("LEFT", row.roleBadge, "LEFT", ROLE_BADGE_TEXT_INSET_X, 0)
            row.roleText:SetPoint("RIGHT", row.roleBadge, "RIGHT", -ROLE_BADGE_TEXT_INSET_X, 0)
            row._roleDisplayText = roleLabel
            row._roleTextColor = { 0.94, 0.95, 0.97, 1 }
            row.sound = createPremiumPickerButton(
                scrollChild,
                "",
                function()
                    return getDeathAlertSoundChoices(PortalAuthorityDB and PortalAuthorityDB[prefix .. "Sound"] or "")
                end,
                function()
                    return normalizeSoundChoiceValue(PortalAuthorityDB and PortalAuthorityDB[prefix .. "Sound"] or "")
                end,
                function(v)
                    if PortalAuthorityDB then
                        PortalAuthorityDB[prefix .. "Sound"] = v
                    end
                end,
                function()
                    if applyOnScreenRuleWrite and PortalAuthorityDB then
                        applyOnScreenRuleWrite(row, PortalAuthorityDB, PA_SafeBool(PortalAuthorityDB[prefix .. "Enabled"]))
                    end
                    onApply()
                end,
                {
                    width = COMBAT_ALERTS_LAYOUT.SOUND_CONTROL_SEED_W,
                    title = "Select Alert Sound",
                    searchHint = "Search sounds",
                    pickerWidth = 460,
                    pickerHeight = 390,
                    onOptionRightClick = function(value)
                        previewDeathAlertSound(value)
                    end,
                    footerHint = "Right-click to preview - Left-click selects",
                }
            )
            if row.sound and row.sound.label then
                row.sound.label:SetText("")
                row.sound.label:Hide()
            end
            row._onScreenValue = false
            row.onScreen = createPremiumSegmentedChoice(scrollChild, "", nil, {
                { label = "Off", value = false, toggleState = "off" },
                { label = "On", value = true, toggleState = "on" },
            }, function(v)
                if PortalAuthorityDB then
                    PortalAuthorityDB[prefix .. "OnScreen"] = PA_SafeBool(v)
                end
                row._paOnScreenForcedByNone = false
                row._onScreenValue = PA_SafeBool(v)
                onApply()
            end, {
                semantic = "toggle",
                normalizeValue = function(v)
                    return PA_SafeBool(v)
                end,
                getValue = function()
                    return PA_SafeBool(row._onScreenValue)
                end,
                setValue = function(v)
                    row._onScreenValue = PA_SafeBool(v)
                end,
            })
            if row.onScreen and row.onScreen.label then
                row.onScreen.label:SetText("")
                row.onScreen.label:Hide()
            end
            if row.onScreen and row.onScreen.Layout then
                row.onScreen:Layout(COMBAT_ALERTS_LAYOUT.ROLE_TOGGLE_LAYOUT_W)
            end
            row.roleHelper = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
            row.roleHelper:SetText("")
            row.roleHelper:SetTextColor(0.58, 0.58, 0.58, 0.92)
            row.roleHelper:SetJustifyH("LEFT")
            row.roleHelper:SetWordWrap(false)
            if row.roleHelper.SetMaxLines then
                row.roleHelper:SetMaxLines(1)
            end
            row.onScreenHelper = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
            row.onScreenHelper:SetText("")
            row.onScreenHelper:SetTextColor(0.58, 0.58, 0.58, 0.92)
            row.onScreenHelper:SetJustifyH("LEFT")
            row.onScreenHelper:SetWordWrap(false)
            if row.onScreenHelper.SetMaxLines then
                row.onScreenHelper:SetMaxLines(1)
            end
            return row
        end

        widgets.rowTank = createRoleRow("deathAlertTank", "TANK", "Tank")
        widgets.rowHealer = createRoleRow("deathAlertHealer", "HEALER", "Healer")
        widgets.rowDps = createRoleRow("deathAlertDps", "DAMAGER", "DPS")
        widgets.rowSelf = createRoleRow("deathAlertSelf", "SELF", "Self")
        local rows = { widgets.rowTank, widgets.rowHealer, widgets.rowDps, widgets.rowSelf }

        widgets.messageLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        widgets.messageLabel:SetText("On-screen Alert Message")
        widgets.messageLabel:SetJustifyH("LEFT")
        widgets.messageEdit = CreateFrame("EditBox", nil, scrollChild)
        widgets.messageEdit:SetAutoFocus(false)
        widgets.messageEdit:SetSize(COMBAT_ALERTS_LAYOUT.MESSAGE_EDIT_SEED_W, COMBAT_ALERTS_LAYOUT.MESSAGE_EDIT_SEED_H)
        widgets.messageEdit:SetTextInsets(8, 8, 0, 0)
        widgets.messageEdit:SetTextColor(1, 1, 1, 1)
        widgets.messageEdit:SetHighlightColor(1, 1, 1, 0.25)
        applyGlobalFontToObject(widgets.messageEdit, 12)
        stylePremiumEditBox(widgets.messageEdit, 12)
        local defaults = (PortalAuthority and PortalAuthority.defaults) or {}
        local tmpl = trim((PortalAuthorityDB and PortalAuthorityDB.deathAlertMessageTemplate) or "")
        if tmpl == "" then
            tmpl = defaults.deathAlertMessageTemplate or "[role] Died: [name]"
            if PortalAuthorityDB then
                PortalAuthorityDB.deathAlertMessageTemplate = tmpl
            end
        end
        widgets.messageEdit:SetText(tmpl)
        if widgets.messageEdit.SetCursorPosition then widgets.messageEdit:SetCursorPosition(0) end
        if widgets.messageEdit.HighlightText then widgets.messageEdit:HighlightText(0, 0) end
        widgets.messagePreviewLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.messagePreviewLabel:SetText("Preview")
        widgets.messagePreviewLabel:SetTextColor(0.70, 0.70, 0.72, 0.90)
        widgets.messagePreviewLabel:SetJustifyH("LEFT")
        widgets.messageHelp = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        local tankIconInline = "|TInterface\\LFGFrame\\UI-LFG-ICON-ROLES:18:18:0:0:64:64:0:19:22:41|t"
        if C_Texture and C_Texture.GetAtlasInfo and C_Texture.GetAtlasInfo("groupfinder-icon-role-large-tank") then
            -- Atlas render avoids artifacting from cropped sprite coordinates.
            tankIconInline = "|A:groupfinder-icon-role-large-tank:16:16:0:-1|a"
        end
        widgets.messageHelp:SetText(string.format(
            "%s Tank Died: |c%sStreetxo|r",
            tankIconInline,
            getClassHex("PALADIN")
        ))
        widgets.messageHelp:SetTextColor(0.82, 0.82, 0.84, 0.90)
        widgets.messageHelp:SetJustifyH("LEFT")
        widgets.messageHelp:SetWordWrap(false)
        if widgets.messageHelp.SetMaxLines then
            widgets.messageHelp:SetMaxLines(1)
        end
        widgets.messageHelp._paFullText = widgets.messageHelp:GetText() or ""
        widgets.insertLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.insertLabel:SetText("Insert:")
        widgets.insertLabel:SetTextColor(0.70, 0.70, 0.72, 0.90)
        widgets.insertLabel:SetJustifyH("LEFT")
        widgets.showRoleIcon = createPremiumSegmentedChoice(scrollChild, "Show Role Icon", "deathAlertShowRoleIcon", {
            { label = "Off", value = false, toggleState = "off" },
            { label = "On", value = true, toggleState = "on" },
        }, function()
            onApply()
        end, {
            semantic = "toggle",
            normalizeValue = function(v)
                return PA_SafeBool(v)
            end,
            getValue = function()
                return PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.deathAlertShowRoleIcon)
            end,
            setValue = function(v)
                if PortalAuthorityDB then
                    PortalAuthorityDB.deathAlertShowRoleIcon = PA_SafeBool(v)
                end
            end,
        })
        widgets.tokenChipsLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.tokenChipsLabel:SetText("")
        widgets.tokenChipsLabel:Hide()

        local function upsertMessageTemplateFromText(rawText)
            if not PortalAuthorityDB then
                return
            end
            local defaultsRef = (PortalAuthority and PortalAuthority.defaults) or {}
            local text = trim(rawText or "")
            if text == "" then
                text = defaultsRef.deathAlertMessageTemplate or "[role] Died: [name]"
            end
            PortalAuthorityDB.deathAlertMessageTemplate = text
        end

        local function insertMessageToken(token)
            local edit = widgets.messageEdit
            if not edit then
                return
            end
            local current = tostring(edit:GetText() or "")
            local cursor = edit.GetCursorPosition and edit:GetCursorPosition() or nil
            cursor = tonumber(cursor) or #current
            if cursor < 0 then
                cursor = 0
            elseif cursor > #current then
                cursor = #current
            end
            local updated = string.sub(current, 1, cursor) .. tostring(token or "") .. string.sub(current, cursor + 1)
            edit:SetText(updated)
            if edit.SetCursorPosition then
                edit:SetCursorPosition(cursor + string.len(tostring(token or "")))
            end
            if edit.SetFocus then
                edit:SetFocus()
            end
            upsertMessageTemplateFromText(updated)
            onApply()
        end

        local function createTokenChip(labelText, tokenText, width)
            local chip = createActionButton(scrollChild, tostring(labelText or ""), nil, width or 62)
            styleSecondaryActionButtonShared(chip, {
                baseBg = { 0.06, 0.07, 0.09, 0.95 },
                hoverBg = { 0.08, 0.09, 0.11, 0.95 },
                pressedBg = { 0.05, 0.06, 0.08, 0.96 },
                baseBorder = { 0.17, 0.19, 0.23, 0.54 },
                hoverBorder = { 0.21, 0.24, 0.28, 0.60 },
                pressedBorder = { 0.19, 0.22, 0.26, 0.58 },
                textColor = { 0.78, 0.79, 0.83, 1 },
            })
            chip:SetScript("OnClick", function()
                insertMessageToken(tokenText)
            end)
            chip:SetHeight(TOKEN_CHIP_H)
            local chipText = chip.Text or (chip.GetFontString and chip:GetFontString()) or nil
            if chipText then
                applyGlobalFontToObject(chipText, 10)
            end
            return chip
        end

        widgets.tokenChipRole = createTokenChip("[role]", "[role]", COMBAT_ALERTS_LAYOUT.TOKEN_CHIP_SEED_W)
        widgets.tokenChipName = createTokenChip("[name]", "[name]", COMBAT_ALERTS_LAYOUT.TOKEN_CHIP_SEED_W)
        widgets.tokenChipClass = createTokenChip("[class]", "[class]", COMBAT_ALERTS_LAYOUT.TOKEN_CHIP_SEED_W)

        widgets.settingsHeader = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        widgets.settingsHeader:SetText("")
        widgets.roleMessageDivider = scrollChild:CreateTexture(nil, "ARTWORK")
        widgets.roleMessageDivider:SetColorTexture(0.24, 0.27, 0.32, 0.10)
        widgets.messageLeftGroup = CreateFrame("Frame", nil, scrollChild)
        widgets.messageRightGroup = CreateFrame("Frame", nil, scrollChild)
        widgets.coordsRowContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.channelRowContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.masterRowContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.masterRowContainer:SetSize(1, COMBAT_ALERTS_LAYOUT.LOCK_ROW_SEED_H)
        widgets.lockRowContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.lockRowContainer:SetSize(1, COMBAT_ALERTS_LAYOUT.LOCK_ROW_SEED_H)
        widgets.lockStateHelper = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 10)
        widgets.lockStateHelper:SetText("")
        widgets.lockStateHelper:SetTextColor(0.58, 0.58, 0.58, 0.92)
        widgets.lockStateHelper:SetWordWrap(false)
        widgets.lockStateHelper:SetJustifyH("LEFT")
        widgets.moduleEnabled = createPremiumSegmentedChoice(scrollChild, "Module", nil, {
            { label = "Off", value = false, toggleState = "off" },
            { label = "On", value = true, toggleState = "on" },
        }, function(v)
            if PortalAuthorityDB then
                PortalAuthorityDB.combatAlertsEnabled = PA_SafeBool(v)
            end
            onApply()
        end, {
            semantic = "toggle",
            normalizeValue = function(v)
                return PA_SafeBool(v)
            end,
            getValue = function()
                return PortalAuthorityDB == nil or PortalAuthorityDB.combatAlertsEnabled ~= false
            end,
            setValue = function(v)
                if PortalAuthorityDB then
                    PortalAuthorityDB.combatAlertsEnabled = PA_SafeBool(v)
                end
            end,
        })
        self._settingsWindowHeaderToggleSource = widgets.moduleEnabled
        widgets.lockPosition = createPremiumSegmentedChoice(scrollChild, "Lock Position", nil, {
            { label = "Unlocked", value = false },
            { label = "Locked", value = true },
        }, function(v)
            if PortalAuthorityDB then
                PortalAuthorityDB.deathAlertLocked = PA_SafeBool(v)
            end
            onApply()
        end, {
            semantic = "selection",
            selectionVariant = "lock_meta",
            normalizeValue = function(v)
                return PA_SafeBool(v)
            end,
            getValue = function()
                return PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.deathAlertLocked)
            end,
            setValue = function(v)
                if PortalAuthorityDB then
                    PortalAuthorityDB.deathAlertLocked = PA_SafeBool(v)
                end
            end,
        })

        widgets.settingsDivider = scrollChild:CreateTexture(nil, "ARTWORK")
        widgets.settingsDivider:SetColorTexture(0.24, 0.27, 0.32, 0.10)
        widgets.antiSpam = createPremiumSegmentedChoice(scrollChild, "Anti-spam Raid Wipe", "deathAlertAntiSpamWipeEnabled", {
            { label = "Off", value = false, toggleState = "off" },
            { label = "On", value = true, toggleState = "on" },
        }, function()
            onApply()
        end, {
            semantic = "toggle",
            normalizeValue = function(v)
                return PA_SafeBool(v)
            end,
            getValue = function()
                return PA_SafeBool(PortalAuthorityDB and PortalAuthorityDB.deathAlertAntiSpamWipeEnabled)
            end,
            setValue = function(v)
                if PortalAuthorityDB then
                    PortalAuthorityDB.deathAlertAntiSpamWipeEnabled = PA_SafeBool(v)
                end
            end,
        })
        do
            local antiSpamTooltip = "Suppresses repeated death alerts during a raid wipe."
            local antiSpamLabel = widgets.antiSpam and widgets.antiSpam.label or nil
            if antiSpamLabel then
                local hit = antiSpamLabel._paAntiSpamTooltipHit
                if not hit then
                    hit = CreateFrame("Frame", nil, scrollChild)
                    hit:SetPoint("TOPLEFT", antiSpamLabel, "TOPLEFT", -2, 2)
                    hit:SetPoint("BOTTOMRIGHT", antiSpamLabel, "BOTTOMRIGHT", 2, -2)
                    hit:EnableMouse(true)
                    hit:SetScript("OnEnter", function(selfHit)
                        GameTooltip:SetOwner(selfHit, "ANCHOR_TOP")
                        GameTooltip:SetText(antiSpamTooltip, 1, 1, 1, 1)
                        GameTooltip:Show()
                    end)
                    hit:SetScript("OnLeave", function()
                        GameTooltip:Hide()
                    end)
                    antiSpamLabel._paAntiSpamTooltipHit = hit
                end
                hit:SetShown(antiSpamLabel:IsShown())
            end
        end

        widgets.coordsLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        widgets.coordsLabel:SetText("Coordinates")
        widgets.coordsLabel:SetJustifyH("LEFT")
        widgets.coordsEdit = CreateFrame("EditBox", nil, scrollChild)
        widgets.coordsEdit:SetAutoFocus(false)
        widgets.coordsEdit:SetSize(COMBAT_ALERTS_LAYOUT.COORDS_EDIT_SEED_W, COMBAT_ALERTS_LAYOUT.COORDS_EDIT_SEED_H)
        widgets.coordsEdit:SetEnabled(true)
        widgets.coordsEdit:EnableMouse(true)
        widgets.coordsEdit:SetTextColor(0.86, 0.86, 0.88, 1)
        widgets.coordsEdit:SetAlpha(0.90)
        widgets.coordsEdit:SetJustifyH("CENTER")
        applyGlobalFontToObject(widgets.coordsEdit, 12)
        stylePremiumEditBox(widgets.coordsEdit, 12)
        widgets.resetAnchor = createActionButton(scrollChild, "Reset Anchor", function()
            if PortalAuthorityDB then
                PortalAuthorityDB.deathAlertLocked = false
                PortalAuthorityDB.deathAlertX = 0
                PortalAuthorityDB.deathAlertY = 0
            end
            onApply()
        end, COMBAT_ALERTS_LAYOUT.RESET_W)
        styleSecondaryActionButtonShared(widgets.resetAnchor, {
            baseBg = { 0.06, 0.07, 0.09, 0.95 },
            hoverBg = { 0.08, 0.09, 0.11, 0.95 },
            pressedBg = { 0.05, 0.06, 0.08, 0.96 },
            baseBorder = { 0.21, 0.24, 0.28, 0.62 },
            hoverBorder = { 0.25, 0.28, 0.33, 0.68 },
            pressedBorder = { 0.23, 0.26, 0.30, 0.66 },
            textColor = { 0.82, 0.83, 0.86, 1 },
        })

        local channelChoices = SUMMON_SOUND_CHANNEL_CHOICES
        if type(channelChoices) ~= "table" or #channelChoices == 0 then
            channelChoices = {
                { label = "Master", value = "Master" },
                { label = "SFX", value = "SFX" },
                { label = "Music", value = "Music" },
                { label = "Ambience", value = "Ambience" },
                { label = "Dialog", value = "Dialog" },
            }
        end

        widgets.font = createPremiumPickerButton(
            scrollChild,
            "Font / Size",
            buildSharedFontPickerChoices,
            function()
                return tostring((PortalAuthorityDB and PortalAuthorityDB.deathAlertFontPath) or "")
            end,
            function(v)
                if PortalAuthorityDB then
                    PortalAuthorityDB.deathAlertFontPath = tostring(v or "")
                end
            end,
            onApply,
            {
                width = COMBAT_ALERTS_LAYOUT.FONT_PICKER_SEED_W,
                title = "Select Font Face",
                searchHint = "Search fonts by name",
                pickerWidth = 420,
                pickerHeight = 380,
                useOptionFontPreview = true,
                previewFontSize = 13,
                emptyLabel = "Global UI Font",
            }
        )
        widgets.fontSizeLabel = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlight", 12)
        widgets.fontSizeLabel:SetText("")
        widgets.fontSizeStepper = nil
        if type(createCanonicalDockFontSizeStepperControl) == "function" then
            widgets.fontSizeStepper = createCanonicalDockFontSizeStepperControl(
                scrollChild,
                "",
                8,
                72,
                1,
                "deathAlertFontSize",
                52,
                function()
                    onApply()
                end,
                nil,
                { micro = true, shiftMultiplier = 5 }
            )
            if widgets.fontSizeStepper and widgets.fontSizeStepper.label then
                widgets.fontSizeStepper.label:SetText("")
                widgets.fontSizeStepper.label:Hide()
            end
        else
            widgets.fontSizeEdit = CreateFrame("EditBox", nil, scrollChild)
            widgets.fontSizeEdit:SetAutoFocus(false)
            widgets.fontSizeEdit:SetSize(COMBAT_ALERTS_LAYOUT.FONT_SIZE_EDIT_SEED_W, COMBAT_ALERTS_LAYOUT.FONT_SIZE_EDIT_SEED_H)
            widgets.fontSizeEdit:SetNumeric(true)
            widgets.fontSizeEdit:SetTextInsets(8, 8, 0, 0)
            widgets.fontSizeEdit:SetTextColor(1, 1, 1, 1)
            applyGlobalFontToObject(widgets.fontSizeEdit, 12)
            stylePremiumEditBox(widgets.fontSizeEdit, 12)
        end
        widgets.fontRowContainer = CreateFrame("Frame", nil, scrollChild)
        widgets.fontRowContainer:SetSize(1, COMBAT_ALERTS_LAYOUT.FONT_ROW_SEED_H)

        widgets.channel = createPremiumPickerButton(
            scrollChild,
            "Audio Channel",
            function()
                return channelChoices
            end,
            function()
                return tostring((PortalAuthorityDB and PortalAuthorityDB.deathAlertSoundChannel) or "")
            end,
            function(v)
                if PortalAuthorityDB then
                    PortalAuthorityDB.deathAlertSoundChannel = tostring(v or "")
                end
            end,
            onApply,
            {
                -- 5 visible rows in compact popup mode.
                rowHeight = 26,
                pickerHeight = 192,
                minHeight = 192,
                width = COMBAT_ALERTS_LAYOUT.CHANNEL_PICKER_SEED_W,
                title = "Select Audio Channel",
                searchHint = "Search channels",
                pickerWidth = 380,
                noSearch = true,
                hideTitle = true,
                hideScrollBar = true,
            }
        )
        widgets.channelHint = createStyledFontString(scrollChild, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.channelHint:SetText("")
        widgets.channelHint:SetTextColor(0.72, 0.72, 0.72, 1)
        widgets.channelHint:SetJustifyH("LEFT")
        widgets.channelHint:Hide()

        local function setDropdownEnabled(spec, enabled)
            if not (spec and spec.control) then return end
            if spec.SetEnabled then
                spec:SetEnabled(enabled)
                return
            end
            local dd = spec.control
            if UIDropDownMenu_EnableDropDown and UIDropDownMenu_DisableDropDown then
                if enabled then UIDropDownMenu_EnableDropDown(dd) else UIDropDownMenu_DisableDropDown(dd) end
            end
            if dd.EnableMouse then dd:EnableMouse(enabled) end
            local alpha = enabled and 1 or 0.6
            dd:SetAlpha(alpha)
            local name = dd.GetName and dd:GetName()
            if name then
                local button = _G[name .. "Button"]
                local text = _G[name .. "Text"]
                if button then
                    button:SetAlpha(alpha)
                    if button.EnableMouse then button:EnableMouse(enabled) end
                    if button.SetEnabled then button:SetEnabled(enabled) end
                end
                if text then
                    text:SetAlpha(alpha)
                end
            end
        end

        local function updateCoordsDisplay()
            if not widgets.coordsEdit then return end
            if widgets._coordsEditing and widgets.coordsEdit:HasFocus() then
                return
            end
            local x = math.floor(tonumber(PortalAuthorityDB and PortalAuthorityDB.deathAlertX) or 0)
            local y = math.floor(tonumber(PortalAuthorityDB and PortalAuthorityDB.deathAlertY) or 0)
            widgets.coordsEdit:SetText(string.format("%d, %d", x, y))
            widgets.coordsEdit:SetJustifyH("CENTER")
            if widgets.coordsEdit.SetCursorPosition then widgets.coordsEdit:SetCursorPosition(0) end
            if widgets.coordsEdit.HighlightText then widgets.coordsEdit:HighlightText(0, 0) end
            widgets.coordsEdit:SetTextColor(0.86, 0.86, 0.88, 1)
            widgets.coordsEdit:SetAlpha(0.90)
            if widgets.coordsEdit.EnableKeyboard then
                widgets.coordsEdit:EnableKeyboard(false)
            end
        end

        local function setCoordsEditMode(editing)
            widgets._coordsEditing = editing and true or false
            if not widgets.coordsEdit then
                return
            end
            if widgets.coordsEdit.EnableKeyboard then
                widgets.coordsEdit:EnableKeyboard(widgets._coordsEditing)
            end
            if widgets._coordsEditing then
                widgets.coordsEdit:SetJustifyH("CENTER")
                widgets.coordsEdit:SetTextColor(1, 1, 1, 1)
                widgets.coordsEdit:SetAlpha(1)
            else
                widgets.coordsEdit:SetJustifyH("CENTER")
                widgets.coordsEdit:SetTextColor(0.86, 0.86, 0.88, 1)
                widgets.coordsEdit:SetAlpha(0.90)
            end
        end

        local function flashCoordsInvalid()
            local border = widgets.coordsEdit and widgets.coordsEdit._paPremiumBorder
            if not border or not border.SetBackdropBorderColor then
                return
            end
            border:SetBackdropBorderColor(0.42, 0.20, 0.20, 1)
            if C_Timer and C_Timer.After then
                C_Timer.After(0.12, function()
                    if not widgets.coordsEdit or (widgets._coordsEditing and widgets.coordsEdit:HasFocus()) then
                        return
                    end
                    if widgets.coordsEdit._paPremiumBorder and widgets.coordsEdit._paPremiumBorder.SetBackdropBorderColor then
                        widgets.coordsEdit._paPremiumBorder:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                    end
                end)
            end
        end

        local function parseCoordsInput(raw)
            local values = {}
            for token in string.gmatch(tostring(raw or ""), "[-+]?%d+%.?%d*") do
                values[#values + 1] = tonumber(token)
            end
            if #values ~= 2 or not values[1] or not values[2] then
                return nil, nil
            end
            return math.floor(values[1]), math.floor(values[2])
        end

        local function beginCoordsEdit()
            if not widgets.coordsEdit or widgets._coordsEditing then
                return
            end
            setCoordsEditMode(true)
            widgets.coordsEdit:SetFocus()
            if widgets.coordsEdit.HighlightText then
                widgets.coordsEdit:HighlightText()
            end
        end

        local function finishCoordsEdit(commit)
            if not widgets.coordsEdit or not widgets._coordsEditing then
                return
            end

            if commit then
                local x, y = parseCoordsInput(widgets.coordsEdit:GetText())
                if x ~= nil and y ~= nil and PortalAuthorityDB then
                    PortalAuthorityDB.deathAlertX = x
                    PortalAuthorityDB.deathAlertY = y
                    setCoordsEditMode(false)
                    widgets.coordsEdit:ClearFocus()
                    onApply()
                    return
                end
                flashCoordsInvalid()
            end

            setCoordsEditMode(false)
            widgets.coordsEdit:ClearFocus()
            updateCoordsDisplay()
        end

        local function SetRoleIcon(row, role)
            if not row or not row.icon then return end
            if role == "HEALER" then
                if row.icon.SetAtlas then row.icon:SetAtlas(nil) end
                row.icon:SetTexture("Interface\\LFGFrame\\UI-LFG-ICON-ROLES")
                if GetTexCoordsForRole then
                    local l, r, t, b = GetTexCoordsForRole("HEALER")
                    if l and r and t and b then
                        row.icon:SetTexCoord(l, r, t, b)
                    else
                        row.icon:SetTexCoord(0, 1, 0, 1)
                    end
                else
                    row.icon:SetTexCoord(0, 1, 0, 1)
                end
                return
            end
            local atlasName = nil
            if role == "TANK" then
                atlasName = "groupfinder-icon-role-large-tank"
            else
                atlasName = "groupfinder-icon-role-large-dps"
            end

            local atlasOk = false
            if C_Texture and C_Texture.GetAtlasInfo and atlasName then
                atlasOk = (C_Texture.GetAtlasInfo(atlasName) ~= nil)
            end

            if atlasOk and row.icon.SetAtlas then
                row.icon:SetAtlas(atlasName)
                row.icon:SetTexCoord(0, 1, 0, 1)
                return
            end

            if row.icon.SetAtlas then
                row.icon:SetAtlas(nil)
            end
            row.icon:SetTexture("Interface\\LFGFrame\\UI-LFG-ICON-ROLES")
            if GetTexCoordsForRole then
                local l, r, t, b = GetTexCoordsForRole(role)
                if l and r and t and b then
                    row.icon:SetTexCoord(l, r, t, b)
                    return
                end
            end
            row.icon:SetTexCoord(0, 1, 0, 1)
        end

        local function updateSelfVisual(row)
            local playerName = UnitName and UnitName("player") or "Player"
            if Ambiguate then
                playerName = Ambiguate(playerName, "short")
            end
            local _, classFile = nil, nil
            if UnitClass then
                _, classFile = UnitClass("player")
            end
            local classColor = (classFile and RAID_CLASS_COLORS and RAID_CLASS_COLORS[classFile]) or NORMAL_FONT_COLOR
            local helperText = tostring(playerName or "Player")
            row._roleDisplayText = "Player"
            row._roleTextColor = { 0.94, 0.95, 0.97, 1 }
            row._helperFallbackText = helperText
            row._helperFallbackColor = {
                math.max(0, math.min(1, ((classColor and classColor.r) or 1) * 0.80)),
                math.max(0, math.min(1, ((classColor and classColor.g) or 1) * 0.80)),
                math.max(0, math.min(1, ((classColor and classColor.b) or 1) * 0.80)),
                0.85,
            }
            row._roleHelperFullText = helperText
            row._roleHelperColor = {
                row._helperFallbackColor[1],
                row._helperFallbackColor[2],
                row._helperFallbackColor[3],
                row._helperFallbackColor[4],
            }
            local specIndex = GetSpecialization and GetSpecialization()
            if specIndex and GetSpecializationInfo then
                local _, _, _, specIcon = GetSpecializationInfo(specIndex)
                if specIcon then
                    if row.icon.SetAtlas then
                        row.icon:SetAtlas(nil)
                    end
                    row.icon:SetTexture(specIcon)
                    row.icon:SetTexCoord(0, 1, 0, 1)
                    return
                end
            end
            if classFile and CLASS_ICON_TCOORDS and CLASS_ICON_TCOORDS[classFile] then
                if row.icon.SetAtlas then
                    row.icon:SetAtlas(nil)
                end
                row.icon:SetTexture("Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES")
                local coords = CLASS_ICON_TCOORDS[classFile]
                row.icon:SetTexCoord(coords[1], coords[2], coords[3], coords[4])
            else
                if row.icon.SetAtlas then
                    row.icon:SetAtlas(nil)
                end
                row.icon:SetTexture("Interface\\ICONS\\INV_Misc_QuestionMark")
                row.icon:SetTexCoord(0, 1, 0, 1)
            end
        end
        local function updateRoleIcon(row)
            if row.roleKey == "SELF" then
                updateSelfVisual(row)
                return
            end
            row._roleDisplayText = tostring(row.roleLabel or "")
            row._roleTextColor = { 0.94, 0.95, 0.97, 1 }
            row._helperFallbackText = nil
            row._helperFallbackColor = nil
            row._roleHelperFullText = ""
            row._roleHelperColor = nil
            SetRoleIcon(row, row.roleKey)
        end

        local function getRowSoundValue(db, prefix)
            if not db then
                return ""
            end
            local value = db[prefix .. "Sound"]
            if value == nil then
                return ""
            end
            if type(value) == "number" then
                return tostring(value)
            end
            return tostring(value)
        end

        applyOnScreenRuleWrite = function(row, db, enabled)
            if not row or not db then
                return
            end
            local onScreenKey = row.prefix .. "OnScreen"
            local isEnabled = PA_SafeBool(enabled)
            local soundIsNone = (getRowSoundValue(db, row.prefix) == "")
            local isForced = isEnabled and soundIsNone
            local wasForced = row._paWasForcedByNone and true or false

            if not isEnabled then
                db[onScreenKey] = false
                row._paOnScreenForcedByNone = false
                row._paWasForcedByNone = false
                row._onScreenValue = false
                return
            end

            if isForced then
                if (not wasForced) and (not PA_SafeBool(db[onScreenKey])) then
                    db[onScreenKey] = true
                elseif db[onScreenKey] == nil then
                    db[onScreenKey] = true
                end
                row._paOnScreenForcedByNone = true
                row._paWasForcedByNone = true
                row._onScreenValue = true
                return
            end

            if wasForced or row._paOnScreenForcedByNone then
                db[onScreenKey] = false
            end
            db[onScreenKey] = PA_SafeBool(db[onScreenKey])
            row._paOnScreenForcedByNone = false
            row._paWasForcedByNone = false
            row._onScreenValue = PA_SafeBool(db[onScreenKey])
        end

        local function applyOnScreenRuleVisual(row, db, enabled)
            if not row or not db then
                return
            end
            local isEnabled = PA_SafeBool(enabled)
            local soundIsNone = (getRowSoundValue(db, row.prefix) == "")
            local isForced = isEnabled and soundIsNone
            local visualValue = false
            local allowInteraction = isEnabled

            if isForced then
                visualValue = true
                row._paOnScreenForcedByNone = true
                row._paWasForcedByNone = true
            elseif not isEnabled then
                visualValue = false
                row._paOnScreenForcedByNone = false
                row._paWasForcedByNone = false
            else
                visualValue = PA_SafeBool(db[row.prefix .. "OnScreen"])
                row._paOnScreenForcedByNone = false
                row._paWasForcedByNone = false
            end

            row._onScreenValue = visualValue
            if row.onScreen and row.onScreen.SetChoiceEnabled then
                row.onScreen:SetChoiceEnabled(false, not isForced)
                row.onScreen:SetChoiceEnabled(true, true)
            end
            if row.onScreen and row.onScreen.SetVisualSelectedValue then
                row.onScreen:SetVisualSelectedValue(visualValue)
            elseif row.onScreen and row.onScreen.SetSelectedValue then
                row.onScreen:SetSelectedValue(visualValue, false)
            end
            if row.onScreen and row.onScreen.SetEnabled then
                row.onScreen:SetEnabled(allowInteraction)
            end
            if row.onScreenHelper then
                if soundIsNone then
                    row.onScreenHelper:SetText("Required when Sound=None")
                    row.onScreenHelper:SetTextColor(0.58, 0.58, 0.58, 0.92)
                    row._onScreenHelperFullText = "Required when Sound=None"
                else
                    row.onScreenHelper:SetText("")
                    row.onScreenHelper:SetTextColor(0.58, 0.58, 0.58, 0.92)
                    row._onScreenHelperFullText = ""
                end
            end
        end

        local function updateMessagePreviewLine(db)
            if not widgets.messageHelp then
                return
            end
            local iconPart = ""
            if PA_SafeBool(db and db.deathAlertShowRoleIcon) then
                iconPart = (tankIconInline or "") .. " "
            end
            local previewText = string.format("%sTank Died: |c%sStreetxo|r", iconPart, getClassHex("PALADIN"))
            widgets.messageHelp._paFullText = previewText
            widgets.messageHelp:SetText(previewText)
        end

        local function syncCombatAlertsSelectionControl(spec, value)
            if not spec then
                return
            end
            local normalized = PA_SafeBool(value)
            if spec.SetVisualSelectedValue then
                spec:SetVisualSelectedValue(normalized)
            elseif spec.SetSelectedValue then
                spec:SetSelectedValue(normalized, false)
            end
        end

        local function applyCombatAlertsModuleEnabledState(moduleEnabled)
            setSettingsControlEnabled(widgets.lockPosition, moduleEnabled)
            setSettingsControlEnabled(widgets.resetAnchor, moduleEnabled)
            setSettingsControlEnabled(widgets.antiSpam, moduleEnabled)
            setSettingsControlEnabled(widgets.showRoleIcon, moduleEnabled)
            setSettingsControlEnabled(widgets.coordsEdit, moduleEnabled)
            setSettingsControlEnabled(widgets.font, moduleEnabled)
            setSettingsControlEnabled(widgets.fontSizeStepper or widgets.fontSizeEdit, moduleEnabled)
            setSettingsControlEnabled(widgets.channel, moduleEnabled)
            setSettingsControlEnabled(widgets.messageEdit, moduleEnabled)
            setSettingsControlEnabled(widgets.tokenChipRole, moduleEnabled)
            setSettingsControlEnabled(widgets.tokenChipName, moduleEnabled)
            setSettingsControlEnabled(widgets.tokenChipClass, moduleEnabled)

            if not moduleEnabled then
                if widgets.messageEdit and widgets.messageEdit.ClearFocus then
                    widgets.messageEdit:ClearFocus()
                end
                if widgets.coordsEdit and widgets.coordsEdit.ClearFocus then
                    widgets.coordsEdit:ClearFocus()
                end
                if widgets.fontSizeEdit and widgets.fontSizeEdit.ClearFocus then
                    widgets.fontSizeEdit:ClearFocus()
                end
            end

            if widgets.lockRowContainer and widgets.lockRowContainer.SetAlpha then
                widgets.lockRowContainer:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.messageLeftGroup and widgets.messageLeftGroup.SetAlpha then
                widgets.messageLeftGroup:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.messageRightGroup and widgets.messageRightGroup.SetAlpha then
                widgets.messageRightGroup:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.coordsRowContainer and widgets.coordsRowContainer.SetAlpha then
                widgets.coordsRowContainer:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.fontRowContainer and widgets.fontRowContainer.SetAlpha then
                widgets.fontRowContainer:SetAlpha(moduleEnabled and 1 or 0.55)
            end
            if widgets.channelRowContainer and widgets.channelRowContainer.SetAlpha then
                widgets.channelRowContainer:SetAlpha(moduleEnabled and 1 or 0.55)
            end

            for _, textWidget in ipairs({
                widgets.lockStateHelper,
                widgets.soundColumnLabel,
                widgets.screenColumnLabel,
                widgets.messageLabel,
                widgets.messagePreviewLabel,
                widgets.messageHelp,
                widgets.insertLabel,
                widgets.coordsLabel,
                widgets.fontSizeLabel,
                widgets.channelHint,
            }) do
                setSettingsTextEnabled(textWidget, moduleEnabled)
            end

            for _, row in ipairs(rows) do
                local rowEnabled = row and row.enabledValue and true or false
                local rowInteractive = moduleEnabled
                local subControlInteractive = moduleEnabled and rowEnabled

                setSettingsControlEnabled(row and row.enabled or nil, rowInteractive)
                setSettingsControlEnabled(row and row.sound or nil, subControlInteractive)
                setSettingsControlEnabled(row and row.onScreen or nil, subControlInteractive)

                if row and row.container and row.container.SetAlpha then
                    row.container:SetAlpha(moduleEnabled and 1 or 0.55)
                end
                if row and row.icon then
                    row.icon:SetAlpha((moduleEnabled and rowEnabled) and 1 or 0.55)
                end
                if row and row.roleBadge then
                    row.roleBadge:SetAlpha((moduleEnabled and rowEnabled) and 1 or 0.92)
                end
                if row and row.roleText then
                    row.roleText:SetAlpha((moduleEnabled and rowEnabled) and 1 or 0.88)
                end
                setSettingsTextEnabled(row and row.roleHelper or nil, moduleEnabled)
                setSettingsTextEnabled(row and row.onScreenHelper or nil, moduleEnabled)
            end
        end

        local function refresh()
            if ensureDatabase then ensureDatabase() end
            local db = PortalAuthorityDB or {}
            local moduleEnabled = db.combatAlertsEnabled ~= false

            syncCombatAlertsSelectionControl(widgets.moduleEnabled, moduleEnabled)

            for _, row in ipairs(rows) do
                local prefix = row.prefix
                local enabled = PA_SafeBool(db[prefix .. "Enabled"])
                local rowActive = moduleEnabled and enabled
                row.enabledValue = enabled
                if row.enabled and row.enabled.SetVisualSelectedValue then
                    row.enabled:SetVisualSelectedValue(enabled)
                elseif row.enabled and row.enabled.SetSelectedValue then
                    row.enabled:SetSelectedValue(enabled, false)
                end
                if row.sound and row.sound.Refresh then
                    row.sound:Refresh()
                end
                setDropdownEnabled(row.sound, rowActive)
                updateRoleIcon(row)
                applyOnScreenRuleVisual(row, db, enabled)
                if row.roleText then
                    row.roleText:SetText(row._roleDisplayText or row.roleLabel or "")
                end
                row.icon:SetAlpha(rowActive and 1 or 0.55)
                if row.roleBadge then
                    row.roleBadge:SetAlpha(rowActive and 1 or 0.92)
                end
                row.roleText:SetAlpha(rowActive and 1 or 0.88)
                if row._roleTextColor and row.roleText then
                    row.roleText:SetTextColor(row._roleTextColor[1], row._roleTextColor[2], row._roleTextColor[3], row._roleTextColor[4] or 1)
                end
                if row.roleHelper then
                    local roleHelperText = tostring(row._roleHelperFullText or "")
                    if roleHelperText ~= "" then
                        local c = row._roleHelperColor or { 0.58, 0.58, 0.58, 0.92 }
                        row.roleHelper:SetText(roleHelperText)
                        row.roleHelper:SetTextColor(c[1], c[2], c[3], c[4] or 0.92)
                    else
                        row.roleHelper:SetText("")
                        row.roleHelper:SetTextColor(0.58, 0.58, 0.58, 0.92)
                    end
                end
            end

            syncCombatAlertsSelectionControl(widgets.lockPosition, db.deathAlertLocked)
            if widgets.lockStateHelper then
                if not moduleEnabled then
                    widgets.lockStateHelper:SetText("Combat Alerts are disabled. Re-enable to edit settings.")
                elseif PA_SafeBool(db.deathAlertLocked) then
                    widgets.lockStateHelper:SetText("Combat Alerts are locked.")
                else
                    widgets.lockStateHelper:SetText("Combat Alerts are unlocked - drag to reposition.")
                end
            end
            if widgets.antiSpam and widgets.antiSpam.Refresh then
                widgets.antiSpam:Refresh()
            end
            if widgets.channel and widgets.channel.Refresh then widgets.channel:Refresh() end
            if widgets.font and widgets.font.Refresh then widgets.font:Refresh() end
            if widgets.showRoleIcon and widgets.showRoleIcon.Refresh then
                widgets.showRoleIcon:Refresh()
            end
            updateMessagePreviewLine(db)
            updateCoordsDisplay()

            if widgets.messageEdit and not widgets.messageEdit:HasFocus() then
                widgets.messageEdit:SetText(tostring(db.deathAlertMessageTemplate or (PortalAuthority and PortalAuthority.defaults and PortalAuthority.defaults.deathAlertMessageTemplate) or ""))
                if widgets.messageEdit.HighlightText then
                    widgets.messageEdit:HighlightText(0, 0)
                end
            end

            if widgets.fontSizeStepper and widgets.fontSizeStepper.SetVisualValue then
                local v = math.floor(tonumber(db.deathAlertFontSize) or 36)
                if v < 8 then v = 8 end
                if v > 72 then v = 72 end
                widgets.fontSizeStepper:SetVisualValue(v)
            elseif widgets.fontSizeEdit and not widgets.fontSizeEdit:HasFocus() then
                local v = math.floor(tonumber(db.deathAlertFontSize) or 36)
                widgets.fontSizeEdit:SetText(tostring(v))
                if widgets.fontSizeEdit.SetCursorPosition then widgets.fontSizeEdit:SetCursorPosition(0) end
                if widgets.fontSizeEdit.HighlightText then
                    widgets.fontSizeEdit:HighlightText(0, 0)
                end
                widgets.fontSizeEdit:SetTextColor(1, 1, 1, 1)
            end

            applyCombatAlertsModuleEnabledState(moduleEnabled)
            refreshSettingsWindowHeaderAccessoryIfHosted(panelRef)
        end

        local function layout()
            local T = COMBAT_ALERTS_LAYOUT
            local contentW = scrollFrame:GetWidth()
            if not contentW or contentW <= 1 then
                contentW = self:GetWidth()
            end
            if not contentW or contentW <= 1 then
                contentW = T.FALLBACK_CONTENT_W
            end
            scrollChild:SetWidth(contentW)

            for _, control in ipairs({
                header,
                widgets.masterRowContainer,
                widgets.moduleEnabled and widgets.moduleEnabled.label or nil,
                widgets.moduleEnabled and widgets.moduleEnabled.control or nil,
                widgets.lockRowContainer,
                widgets.lockPosition and widgets.lockPosition.label or nil,
                widgets.lockPosition and widgets.lockPosition.control or nil,
                widgets.resetAnchor,
                widgets.lockStateHelper,
                widgets.settingsDivider,
                deathHeader,
                deathDesc,
                widgets.soundColumnLabel,
                widgets.screenColumnLabel,
                widgets.roleHeaderRow,
                widgets.roleMessageDivider,
                widgets.messageLeftGroup,
                widgets.messageLabel,
                widgets.messageEdit,
                widgets.messagePreviewLabel,
                widgets.messageHelp,
                widgets.insertLabel,
                widgets.tokenChipRole,
                widgets.tokenChipName,
                widgets.tokenChipClass,
                widgets.messageRightGroup,
                widgets.showRoleIcon and widgets.showRoleIcon.label or nil,
                widgets.showRoleIcon and widgets.showRoleIcon.control or nil,
                widgets.antiSpam and widgets.antiSpam.label or nil,
                widgets.antiSpam and widgets.antiSpam.control or nil,
                widgets.coordsRowContainer,
                widgets.coordsLabel,
                widgets.coordsEdit,
                widgets.fontRowContainer,
                widgets.font and widgets.font.label or nil,
                widgets.font and widgets.font.control or nil,
                widgets.fontSizeStepper and widgets.fontSizeStepper.control or widgets.fontSizeEdit,
                widgets.channelRowContainer,
                widgets.channel and widgets.channel.label or nil,
                widgets.channelHint,
                widgets.channel and widgets.channel.control or nil,
            }) do
                setCombatWidgetVisible(control, true)
            end
            for _, row in ipairs(rows) do
                if row then
                    setCombatWidgetVisible(row.container, true)
                    setCombatWidgetVisible(row.roleBadge, true)
                    setCombatWidgetVisible(row.roleText, true)
                    setCombatWidgetVisible(row.enabled and row.enabled.control or nil, true)
                    setCombatWidgetVisible(row.sound and row.sound.control or nil, true)
                    setCombatWidgetVisible(row.onScreen and row.onScreen.control or nil, true)
                    setCombatWidgetVisible(row.roleHelper, true)
                    setCombatWidgetVisible(row.onScreenHelper, true)
                end
            end

            local roleGeo = computeCombatAlertsRoleGeometry(contentW)
            local messageGeo = computeCombatAlertsMessageGeometry(contentW)
            local settingsGeo = computeCombatAlertsSettingsGeometry(contentW)
            local headerWidth = math.max(T.HEADER_MIN_W, contentW - T.HEADER_LEFT - T.CONTENT_RIGHT)
            local useHostedChrome = isPanelUsingCustomSettingsWindowHost(panelRef)
            local y = -T.TOP_PAD
            if useHostedChrome then
                y = y - SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE
            end

            if useHostedChrome then
                setCombatWidgetVisible(header, false)
                setCombatWidgetVisible(widgets.sectionDescriptor, false)
                setOffscreenTopLeft(header)
                setOffscreenTopLeft(widgets.sectionDescriptor)
            else
                setCombatWidgetVisible(header, true)
                setCombatWidgetVisible(widgets.sectionDescriptor, true)
                header:ClearAllPoints()
                header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.HEADER_LEFT, y)
                header:SetWidth(headerWidth)
                if header.SetJustifyH then
                    header:SetJustifyH("LEFT")
                end
                local headerH = measureFontStringHeight(header, T.HEADER_FLOOR)
                y = y - headerH - T.HEADER_BOTTOM_GAP
                y = layoutSettingsSectionDescriptor(
                    widgets.sectionDescriptor,
                    scrollChild,
                    T.HEADER_LEFT,
                    y,
                    headerWidth
                )
            end

            local lockLabel = widgets.lockPosition and widgets.lockPosition.label or nil
            local lockGeom = computeCombatAlertsLockGeometry(contentW, lockLabel)
            if useHostedChrome then
                setCombatWidgetVisible(widgets.masterRowContainer, false)
                setCombatWidgetVisible(widgets.moduleEnabled and widgets.moduleEnabled.label or nil, false)
                setCombatWidgetVisible(widgets.moduleEnabled and widgets.moduleEnabled.control or nil, false)
                setOffscreenTopLeft(widgets.masterRowContainer)
                setOffscreenTopLeft(widgets.moduleEnabled and widgets.moduleEnabled.label or nil)
                setOffscreenTopLeft(widgets.moduleEnabled and widgets.moduleEnabled.control or nil)
            else
                setCombatWidgetVisible(widgets.masterRowContainer, true)
                setCombatWidgetVisible(widgets.moduleEnabled and widgets.moduleEnabled.label or nil, true)
                setCombatWidgetVisible(widgets.moduleEnabled and widgets.moduleEnabled.control or nil, true)
                if widgets.moduleEnabled and widgets.moduleEnabled.Layout then
                    widgets.moduleEnabled:Layout(math.max(lockGeom.toggleW, 150))
                end
                local masterLabel = widgets.moduleEnabled and widgets.moduleEnabled.label or nil
                local masterLabelH = measureFontStringHeight(masterLabel, T.LABEL_FLOOR)
                local masterToggleH = measureControlHeight(widgets.moduleEnabled and widgets.moduleEnabled.control, T.RIGHT_CONTROL_FLOOR)
                local masterRowH = math.max(T.LOCK_ROW_FLOOR, masterLabelH, masterToggleH)

                widgets.masterRowContainer:ClearAllPoints()
                widgets.masterRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.CONTENT_LEFT, y)
                widgets.masterRowContainer:SetSize(lockGeom.rowW, masterRowH)
                if masterLabel then
                    masterLabel:ClearAllPoints()
                    masterLabel:SetPoint("LEFT", widgets.masterRowContainer, "LEFT", 0, 0)
                end
                if widgets.moduleEnabled and widgets.moduleEnabled.control then
                    widgets.moduleEnabled.control:ClearAllPoints()
                    widgets.moduleEnabled.control:SetPoint("LEFT", widgets.masterRowContainer, "LEFT", lockGeom.toggleX, 0)
                end
                y = y - masterRowH - 4
            end

            if widgets.lockPosition and widgets.lockPosition.Layout then
                widgets.lockPosition:Layout(lockGeom.toggleW)
            end
            local lockToggleH = measureControlHeight(widgets.lockPosition and widgets.lockPosition.control, T.RIGHT_CONTROL_FLOOR)
            local lockRowH = math.max(T.LOCK_ROW_FLOOR, lockGeom.labelH, lockToggleH, T.RESET_H)

            widgets.lockRowContainer:ClearAllPoints()
            widgets.lockRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.CONTENT_LEFT, y)
            widgets.lockRowContainer:SetSize(lockGeom.rowW, lockRowH)
            if lockLabel then
                lockLabel:ClearAllPoints()
                lockLabel:SetPoint("LEFT", widgets.lockRowContainer, "LEFT", 0, 0)
            end
            if widgets.lockPosition and widgets.lockPosition.control then
                widgets.lockPosition.control:ClearAllPoints()
                widgets.lockPosition.control:SetPoint("LEFT", widgets.lockRowContainer, "LEFT", lockGeom.toggleX, 0)
            end
            if widgets.resetAnchor then
                widgets.resetAnchor:ClearAllPoints()
                widgets.resetAnchor:SetSize(T.RESET_W, T.RESET_H)
                widgets.resetAnchor:SetPoint("LEFT", widgets.lockRowContainer, "LEFT", lockGeom.resetX, 0)
            end
            y = y - lockRowH

            widgets.lockStateHelper:ClearAllPoints()
            widgets.lockStateHelper:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.CONTENT_LEFT, y - lockGeom.helperGap)
            widgets.lockStateHelper:SetWidth(math.max(T.HELPER_MIN_W, contentW - T.CONTENT_LEFT - T.CONTENT_RIGHT))
            if widgets.lockStateHelper.SetJustifyH then widgets.lockStateHelper:SetJustifyH("LEFT") end
            local lockHelperText = tostring(widgets.lockStateHelper:GetText() or "")
            if lockHelperText ~= "" then
                setSingleLineEllipsis(widgets.lockStateHelper, lockHelperText, math.max(T.HELPER_MIN_W, contentW - T.CONTENT_LEFT - T.CONTENT_RIGHT))
            else
            end
            local lockHelperH = measureFontStringHeight(widgets.lockStateHelper, T.HELPER_FLOOR)
            y = y - lockGeom.helperGap - lockHelperH

            if widgets.settingsDivider then
                widgets.settingsDivider:ClearAllPoints()
                local dividerY = y - (lockGeom.dividerGap * 0.5)
                widgets.settingsDivider:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.CONTENT_LEFT, dividerY)
                widgets.settingsDivider:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", -T.CONTENT_RIGHT, dividerY)
                widgets.settingsDivider:SetHeight(T.DIVIDER_H)
            end
            y = y - lockGeom.dividerGap

            deathHeader:ClearAllPoints()
            deathHeader:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.CONTENT_LEFT, y)
            deathHeader:SetWidth(headerWidth)
            if deathHeader.SetJustifyH then
                deathHeader:SetJustifyH("LEFT")
            end
            local deathHeaderH = measureFontStringHeight(deathHeader, T.DEATH_HEADER_FLOOR)
            y = y - deathHeaderH - T.DEATH_HEADER_BOTTOM_GAP

            deathDesc:ClearAllPoints()
            deathDesc:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.CONTENT_LEFT, y)
            deathDesc:SetWidth(math.max(T.HEADER_MIN_W, contentW - T.CONTENT_LEFT - T.CONTENT_RIGHT))
            local deathDescH = measureFontStringHeight(deathDesc, T.DEATH_DESC_FLOOR)
            y = y - deathDescH - T.DEATH_DESC_BOTTOM_GAP

            widgets.soundColumnLabel:SetWidth(math.max(T.SOUND_MIN_W, roleGeo.soundW))
            widgets.screenColumnLabel:SetWidth(roleGeo.screenW)
            local roleHeaderH = math.max(
                T.ROLE_HEADER_ROW_FLOOR,
                measureFontStringHeight(widgets.soundColumnLabel, T.HELPER_FLOOR),
                measureFontStringHeight(widgets.screenColumnLabel, T.HELPER_FLOOR)
            )
            widgets.roleHeaderRow:ClearAllPoints()
            widgets.roleHeaderRow:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, y)
            widgets.roleHeaderRow:SetSize(contentW, roleHeaderH)
            widgets.soundColumnLabel:ClearAllPoints()
            widgets.soundColumnLabel:SetPoint("LEFT", widgets.roleHeaderRow, "LEFT", roleGeo.soundX, HEADER_Y_NUDGE)
            widgets.screenColumnLabel:ClearAllPoints()
            widgets.screenColumnLabel:SetPoint("LEFT", widgets.roleHeaderRow, "LEFT", roleGeo.screenX, HEADER_Y_NUDGE)
            y = y - roleHeaderH - T.ROLE_HEADER_BOTTOM_GAP

            local function placeRow(row, topY)
                local badgeW = math.max(T.ROLE_BADGE_MIN_W, roleGeo.roleLabelW)
                if row.enabled and row.enabled.Layout then
                    row.enabled:Layout(roleGeo.enableW)
                end
                if row.onScreen and row.onScreen.Layout then
                    row.onScreen:Layout(roleGeo.screenW)
                end
                if row.sound and row.sound.SetWidth then
                    row.sound:SetWidth(roleGeo.soundW)
                elseif row.sound and row.sound.control then
                    safeSetDropWidth(row.sound.control, roleGeo.soundW)
                end
                if row.sound and row.sound.text then
                    row.sound.text:SetWidth(math.max(T.SOUND_TEXT_MIN_W, roleGeo.soundW - T.SOUND_TEXT_RIGHT_PAD))
                    row.sound.text:SetWordWrap(false)
                    if row.sound.text.SetMaxLines then
                        row.sound.text:SetMaxLines(1)
                    end
                end

                local leftHelperWidth = math.max(T.ROLE_HELPER_MIN_W, badgeW - (T.ROLE_BADGE_TEXT_INSET_X * 2))
                local leftHelperText = tostring(row._roleHelperFullText or "")
                local leftHelperH = 0
                if row.roleHelper then
                    row.roleHelper:SetWidth(leftHelperWidth)
                    row.roleHelper:SetJustifyH("LEFT")
                    row.roleHelper:SetWordWrap(false)
                    if row.roleHelper.SetMaxLines then
                        row.roleHelper:SetMaxLines(1)
                    end
                    if leftHelperText ~= "" then
                        setSingleLineEllipsis(row.roleHelper, leftHelperText, leftHelperWidth)
                        leftHelperH = measureFontStringHeight(row.roleHelper, T.HELPER_FLOOR)
                    else
                        row.roleHelper:SetText("")
                    end
                end

                local rightHelperText = tostring(row._onScreenHelperFullText or "")
                local rightHelperH = 0
                if row.onScreenHelper then
                    row.onScreenHelper:SetWidth(roleGeo.screenW)
                    row.onScreenHelper:SetJustifyH("LEFT")
                    row.onScreenHelper:SetWordWrap(false)
                    if row.onScreenHelper.SetMaxLines then
                        row.onScreenHelper:SetMaxLines(1)
                    end
                    if rightHelperText ~= "" then
                        setSingleLineEllipsis(row.onScreenHelper, rightHelperText, roleGeo.screenW)
                        rightHelperH = measureFontStringHeight(row.onScreenHelper, T.HELPER_FLOOR)
                    else
                        row.onScreenHelper:SetText("")
                    end
                end

                local helperH = math.max(leftHelperH, rightHelperH)
                local rowH = math.max(
                    T.ROLE_ROW_FLOOR,
                    math.max(
                        T.ROLE_BADGE_H,
                        measureControlHeight(row.enabled and row.enabled.control, T.RIGHT_CONTROL_FLOOR),
                        measureControlHeight(row.sound and row.sound.control, T.RIGHT_CONTROL_FLOOR),
                        measureControlHeight(row.onScreen and row.onScreen.control, T.RIGHT_CONTROL_FLOOR)
                    ) + ((helperH > 0) and (helperH + T.ROLE_HELPER_TOP_GAP) or 0)
                )

                row.container:ClearAllPoints()
                row.container:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, topY)
                row.container:SetSize(contentW, rowH)

                if row.icon then
                    row.icon:Hide()
                end

                if row.roleBadge then
                    row.roleBadge:ClearAllPoints()
                    row.roleBadge:SetPoint("LEFT", row.container, "LEFT", roleGeo.roleX, 0)
                    row.roleBadge:SetSize(badgeW, T.ROLE_BADGE_H)
                end
                if row.roleText then
                    row.roleText:ClearAllPoints()
                    row.roleText:SetPoint("LEFT", row.roleBadge or row.container, "LEFT", T.ROLE_BADGE_TEXT_INSET_X, 0)
                    row.roleText:SetPoint("RIGHT", row.roleBadge or row.container, "RIGHT", -T.ROLE_BADGE_TEXT_INSET_X, 0)
                end

                if row.enabled and row.enabled.control then
                    row.enabled.control:ClearAllPoints()
                    row.enabled.control:SetPoint("LEFT", row.container, "LEFT", roleGeo.enableX, 0)
                end

                if row.sound and row.sound.control then
                    row.sound.control:ClearAllPoints()
                    row.sound.control:SetPoint("LEFT", row.container, "LEFT", roleGeo.soundX, 0)
                end

                if row.onScreen and row.onScreen.control then
                    row.onScreen.control:ClearAllPoints()
                    row.onScreen.control:SetPoint("LEFT", row.container, "LEFT", roleGeo.screenX, 0)
                end

                if row.roleHelper then
                    row.roleHelper:ClearAllPoints()
                    if leftHelperText ~= "" then
                        setCombatWidgetVisible(row.roleHelper, true)
                        row.roleHelper:SetPoint("BOTTOMLEFT", row.container, "BOTTOMLEFT", roleGeo.roleX + T.ROLE_BADGE_TEXT_INSET_X, T.ROLE_HELPER_LEFT_Y_NUDGE)
                    else
                        setCombatWidgetVisible(row.roleHelper, false)
                        row.roleHelper:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.OFFSCREEN_X, T.OFFSCREEN_Y)
                    end
                end

                if row.onScreenHelper then
                    row.onScreenHelper:ClearAllPoints()
                    if rightHelperText ~= "" then
                        setCombatWidgetVisible(row.onScreenHelper, true)
                        row.onScreenHelper:SetPoint("BOTTOMLEFT", row.container, "BOTTOMLEFT", roleGeo.screenX, T.FORCED_HELPER_Y_NUDGE)
                    else
                        setCombatWidgetVisible(row.onScreenHelper, false)
                        row.onScreenHelper:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.OFFSCREEN_X, T.OFFSCREEN_Y)
                    end
                end

                return rowH
            end

            y = y - placeRow(widgets.rowTank, y)
            y = y - placeRow(widgets.rowHealer, y)
            y = y - placeRow(widgets.rowDps, y)
            y = y - placeRow(widgets.rowSelf, y)

            local roleDividerY = y - (T.ROLE_TO_MESSAGE_GAP * 0.5)
            widgets.roleMessageDivider:ClearAllPoints()
            widgets.roleMessageDivider:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.CONTENT_LEFT, roleDividerY)
            widgets.roleMessageDivider:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", -T.CONTENT_RIGHT, roleDividerY)
            widgets.roleMessageDivider:SetHeight(T.DIVIDER_H)
            y = y - T.ROLE_TO_MESSAGE_GAP

            widgets.messageLeftGroup:ClearAllPoints()
            widgets.messageLeftGroup:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", T.CONTENT_LEFT, y)
            widgets.messageLeftGroup:SetSize(messageGeo.leftGroupW, 1)

            widgets.messageLabel:ClearAllPoints()
            widgets.messageLabel:SetPoint("TOPLEFT", widgets.messageLeftGroup, "TOPLEFT", 0, 0)
            widgets.messageLabel:SetWidth(messageGeo.leftGroupW)
            if widgets.messageLabel.SetJustifyH then widgets.messageLabel:SetJustifyH("LEFT") end
            local messageLabelH = measureFontStringHeight(widgets.messageLabel, T.LABEL_FLOOR)

            widgets.messageEdit:ClearAllPoints()
            widgets.messageEdit:SetPoint("TOPLEFT", widgets.messageLeftGroup, "TOPLEFT", 0, -(messageLabelH + T.GRID_UNIT))
            widgets.messageEdit:SetWidth(messageGeo.leftGroupW)
            local editH = measureControlHeight(widgets.messageEdit, T.MESSAGE_EDIT_FLOOR)

            setOffscreenTopLeft(widgets.tokenChipsLabel)

            local previewRowGap = math.max(T.PREVIEW_ROW_GAP_FLOOR, math.floor(T.GRID_UNIT * 0.5))
            local previewRowY = -(messageLabelH + T.GRID_UNIT + editH + previewRowGap)
            widgets.messagePreviewLabel:ClearAllPoints()
            widgets.messagePreviewLabel:SetPoint("TOPLEFT", widgets.messageLeftGroup, "TOPLEFT", 0, previewRowY)
            local previewLabelW = math.max(T.PREVIEW_LABEL_MIN_W, math.ceil((widgets.messagePreviewLabel.GetStringWidth and widgets.messagePreviewLabel:GetStringWidth()) or 34))
            local previewLabelH = measureFontStringHeight(widgets.messagePreviewLabel, T.HELPER_FLOOR)

            local helpWidth = math.max(T.PREVIEW_HELP_MIN_W, messageGeo.leftGroupW - previewLabelW - T.PREVIEW_HELP_WIDTH_PAD)
            widgets.messageHelp:ClearAllPoints()
            widgets.messageHelp:SetPoint("TOPLEFT", widgets.messageLeftGroup, "TOPLEFT", previewLabelW + T.PREVIEW_LABEL_TO_HELP_GAP, previewRowY)
            setSingleLineEllipsis(widgets.messageHelp, widgets.messageHelp._paFullText, helpWidth)
            local helpH = measureFontStringHeight(widgets.messageHelp, T.HELPER_FLOOR)
            local previewRowH = math.max(previewLabelH, helpH)

            local chipsRowGap = math.max(T.CHIPS_ROW_GAP_FLOOR, math.floor(T.GRID_UNIT * 0.5))
            local insertRowY = previewRowY - previewRowH - chipsRowGap
            widgets.insertLabel:ClearAllPoints()
            widgets.insertLabel:SetPoint("TOPLEFT", widgets.messageLeftGroup, "TOPLEFT", 0, insertRowY)
            local insertLabelW = math.max(T.INSERT_LABEL_MIN_W, math.ceil((widgets.insertLabel.GetStringWidth and widgets.insertLabel:GetStringWidth()) or 0))
            local insertLabelH = measureFontStringHeight(widgets.insertLabel, T.HELPER_FLOOR)

            widgets.tokenChipRole:ClearAllPoints()
            widgets.tokenChipRole:SetPoint("TOPLEFT", widgets.messageLeftGroup, "TOPLEFT", insertLabelW + T.INSERT_LABEL_TO_CHIPS_GAP, insertRowY)
            widgets.tokenChipName:ClearAllPoints()
            widgets.tokenChipName:SetPoint("TOPLEFT", widgets.messageLeftGroup, "TOPLEFT", insertLabelW + T.INSERT_LABEL_TO_CHIPS_GAP + (widgets.tokenChipRole:GetWidth() or 0) + T.TOKEN_CHIP_GAP, insertRowY)
            widgets.tokenChipClass:ClearAllPoints()
            widgets.tokenChipClass:SetPoint(
                "TOPLEFT",
                widgets.messageLeftGroup,
                "TOPLEFT",
                insertLabelW + T.INSERT_LABEL_TO_CHIPS_GAP + (widgets.tokenChipRole:GetWidth() or 0) + T.TOKEN_CHIP_GAP + (widgets.tokenChipName:GetWidth() or 0) + T.TOKEN_CHIP_GAP,
                insertRowY
            )
            local chipH = math.max(
                T.TOKEN_CHIP_H,
                measureControlHeight(widgets.tokenChipRole, T.TOKEN_CHIP_H),
                measureControlHeight(widgets.tokenChipName, T.TOKEN_CHIP_H),
                measureControlHeight(widgets.tokenChipClass, T.TOKEN_CHIP_H)
            )
            local insertRowH = math.max(insertLabelH, chipH)
            local leftBlockH = messageLabelH + T.GRID_UNIT + editH + previewRowGap + previewRowH + chipsRowGap + insertRowH
            widgets.messageLeftGroup:SetSize(messageGeo.leftGroupW, math.max(1, leftBlockH))

            if widgets.showRoleIcon and widgets.showRoleIcon.Layout then
                widgets.showRoleIcon:Layout(T.RIGHT_TOGGLE_W)
            end
            if widgets.antiSpam and widgets.antiSpam.Layout then
                widgets.antiSpam:Layout(T.RIGHT_TOGGLE_W)
            end
            if widgets.showRoleIcon and widgets.showRoleIcon.label then
                widgets.showRoleIcon.label:SetWidth(messageGeo.rightRailW)
                if widgets.showRoleIcon.label.SetJustifyH then widgets.showRoleIcon.label:SetJustifyH("LEFT") end
            end
            if widgets.antiSpam and widgets.antiSpam.label then
                widgets.antiSpam.label:SetWidth(messageGeo.rightRailW)
                if widgets.antiSpam.label.SetJustifyH then widgets.antiSpam.label:SetJustifyH("LEFT") end
            end
            local showLabelH = measureFontStringHeight(widgets.showRoleIcon and widgets.showRoleIcon.label, T.RIGHT_LABEL_FLOOR)
            local showControlH = measureControlHeight(widgets.showRoleIcon and widgets.showRoleIcon.control, T.RIGHT_CONTROL_FLOOR)
            local antiLabelH = measureFontStringHeight(widgets.antiSpam and widgets.antiSpam.label, T.RIGHT_LABEL_FLOOR)
            local antiControlH = measureControlHeight(widgets.antiSpam and widgets.antiSpam.control, T.RIGHT_CONTROL_FLOOR)
            local firstControlTopOffset = -math.max(
                (messageLabelH + T.GRID_UNIT) + (editH * 0.5) - (showControlH * 0.5),
                showLabelH + T.RIGHT_LABEL_GAP
            )
            local antiLabelTopOffset = firstControlTopOffset - showControlH - T.RIGHT_STACK_GAP
            local antiControlTopOffset = antiLabelTopOffset - antiLabelH - T.RIGHT_CONTROL_GAP
            local rightBlockBottomY = antiControlTopOffset - antiControlH
            local rightBlockH = math.max(showLabelH, math.abs(rightBlockBottomY))

            widgets.messageRightGroup:ClearAllPoints()
            if messageGeo.canSideBySide then
                widgets.messageRightGroup:SetPoint(
                    "TOPLEFT",
                    scrollChild,
                    "TOPLEFT",
                    T.CONTENT_LEFT + messageGeo.leftGroupW + messageGeo.interBlockGap,
                    y
                )
            else
                widgets.messageRightGroup:SetPoint(
                    "TOPLEFT",
                    scrollChild,
                    "TOPLEFT",
                    T.CONTENT_LEFT,
                    y - (leftBlockH + T.MESSAGE_BRANCH_STACK_GAP)
                )
            end
            widgets.messageRightGroup:SetSize(messageGeo.rightRailW, rightBlockH)

            if widgets.showRoleIcon and widgets.showRoleIcon.label and widgets.showRoleIcon.control then
                widgets.showRoleIcon.label:ClearAllPoints()
                widgets.showRoleIcon.label:SetPoint("TOPLEFT", widgets.messageRightGroup, "TOPLEFT", 0, 0)
                widgets.showRoleIcon.control:ClearAllPoints()
                widgets.showRoleIcon.control:SetPoint("TOPLEFT", widgets.messageRightGroup, "TOPLEFT", 0, firstControlTopOffset)
            end
            if widgets.antiSpam and widgets.antiSpam.label and widgets.antiSpam.control then
                widgets.antiSpam.label:ClearAllPoints()
                widgets.antiSpam.label:SetPoint("TOPLEFT", widgets.messageRightGroup, "TOPLEFT", 0, antiLabelTopOffset)
                widgets.antiSpam.control:ClearAllPoints()
                widgets.antiSpam.control:SetPoint("TOPLEFT", widgets.messageRightGroup, "TOPLEFT", 0, antiControlTopOffset)
            end

            if messageGeo.canSideBySide then
                y = y - math.max(leftBlockH, rightBlockH)
            else
                y = y - (leftBlockH + T.MESSAGE_BRANCH_STACK_GAP + rightBlockH)
            end

            setOffscreenTopLeft(widgets.settingsHeader)
            y = y - T.MESSAGE_TO_SETTINGS_GAP

            local coordsLabelOffset = settingsGeo.controlX - settingsGeo.labelX

            widgets.coordsLabel:SetWidth(settingsGeo.labelW)
            if widgets.coordsLabel.SetJustifyH then widgets.coordsLabel:SetJustifyH("LEFT") end
            local coordsLabelH = measureFontStringHeight(widgets.coordsLabel, T.LABEL_FLOOR)
            local coordsEditH = measureControlHeight(widgets.coordsEdit, T.RIGHT_CONTROL_FLOOR)
            local coordsRowH = math.max(T.SETTINGS_ROW_FLOOR, coordsLabelH, coordsEditH)
            widgets.coordsRowContainer:ClearAllPoints()
            widgets.coordsRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", settingsGeo.labelX, y)
            widgets.coordsRowContainer:SetSize(settingsGeo.rowW, coordsRowH)
            widgets.coordsLabel:ClearAllPoints()
            widgets.coordsLabel:SetPoint("LEFT", widgets.coordsRowContainer, "LEFT", 0, 0)
            widgets.coordsEdit:ClearAllPoints()
            widgets.coordsEdit:SetPoint("LEFT", widgets.coordsRowContainer, "LEFT", coordsLabelOffset, 0)
            widgets.coordsEdit:SetSize(T.COORDS_W, T.RIGHT_CONTROL_FLOOR)
            y = y - coordsRowH

            if widgets.font and widgets.font.label then
                widgets.font.label:SetWidth(settingsGeo.labelW)
                if widgets.font.label.SetJustifyH then widgets.font.label:SetJustifyH("LEFT") end
            end
            local fontControlW = math.max(T.FONT_CONTROL_MIN_W, settingsGeo.dropdownW - (T.FONT_STEPPER_W + T.GRID_UNIT))
            if widgets.font and widgets.font.SetWidth then
                widgets.font:SetWidth(fontControlW)
            elseif widgets.font and widgets.font.control then
                safeSetDropWidth(widgets.font.control, fontControlW)
            end
            local fontLabelH = measureFontStringHeight(widgets.font and widgets.font.label, T.LABEL_FLOOR)
            local fontControlH = measureControlHeight(widgets.font and widgets.font.control, T.RIGHT_CONTROL_FLOOR)
            local fontSizeH = math.max(
                measureControlHeight(widgets.fontSizeStepper and widgets.fontSizeStepper.control, T.RIGHT_CONTROL_FLOOR),
                measureControlHeight(widgets.fontSizeEdit, T.RIGHT_CONTROL_FLOOR)
            )
            local fontRowH = math.max(T.SETTINGS_ROW_FLOOR, fontLabelH, fontControlH, fontSizeH)
            widgets.fontRowContainer:ClearAllPoints()
            widgets.fontRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", settingsGeo.labelX, y)
            widgets.fontRowContainer:SetSize(settingsGeo.rowW, fontRowH)
            if widgets.font and widgets.font.label then
                widgets.font.label:ClearAllPoints()
                widgets.font.label:SetPoint("LEFT", widgets.fontRowContainer, "LEFT", 0, 0)
            end
            if widgets.font and widgets.font.control then
                widgets.font.control:ClearAllPoints()
                widgets.font.control:SetPoint("LEFT", widgets.fontRowContainer, "LEFT", coordsLabelOffset, 0)
            end
            setOffscreenTopLeft(widgets.fontSizeLabel)
            if widgets.fontSizeStepper and widgets.fontSizeStepper.control then
                widgets.fontSizeStepper.control:ClearAllPoints()
                widgets.fontSizeStepper.control:SetPoint("LEFT", widgets.fontRowContainer, "LEFT", coordsLabelOffset + fontControlW + T.GRID_UNIT, 0)
                if widgets.fontSizeStepper.SetWidth then
                    widgets.fontSizeStepper:SetWidth(T.FONT_STEPPER_W)
                else
                    widgets.fontSizeStepper.control:SetWidth(T.FONT_STEPPER_W)
                end
            elseif widgets.fontSizeEdit then
                widgets.fontSizeEdit:ClearAllPoints()
                widgets.fontSizeEdit:SetPoint("LEFT", widgets.fontRowContainer, "LEFT", coordsLabelOffset + fontControlW + T.GRID_UNIT, 0)
                widgets.fontSizeEdit:SetSize(math.max(T.FONT_SIZE_FALLBACK_MIN_W, T.FONT_STEPPER_W - T.GRID_UNIT), T.RIGHT_CONTROL_FLOOR)
            end
            y = y - fontRowH

            if widgets.channel and widgets.channel.label then
                widgets.channel.label:SetWidth(settingsGeo.labelW)
                if widgets.channel.label.SetJustifyH then widgets.channel.label:SetJustifyH("LEFT") end
            end
            if widgets.channel and widgets.channel.SetWidth then
                widgets.channel:SetWidth(settingsGeo.dropdownW)
            elseif widgets.channel and widgets.channel.control then
                safeSetDropWidth(widgets.channel.control, settingsGeo.dropdownW)
            end
            local channelLabelH = measureFontStringHeight(widgets.channel and widgets.channel.label, T.LABEL_FLOOR)
            local channelControlH = measureControlHeight(widgets.channel and widgets.channel.control, T.RIGHT_CONTROL_FLOOR)
            local channelHintText = tostring(widgets.channelHint and widgets.channelHint:GetText() or "")
            local channelLabelW = math.max(0, math.ceil((widgets.channel and widgets.channel.label and widgets.channel.label.GetStringWidth and widgets.channel.label:GetStringWidth()) or 0))
            local channelHintMaxW = math.max(T.CHANNEL_HINT_MIN_W, settingsGeo.labelW - channelLabelW - T.CHANNEL_HINT_GAP)
            local channelHintH = 0
            if widgets.channelHint and widgets.channelHint:IsShown() and channelHintText ~= "" then
                setSingleLineEllipsis(widgets.channelHint, channelHintText, channelHintMaxW)
                channelHintH = measureFontStringHeight(widgets.channelHint, T.HELPER_FLOOR)
            end
            local channelRowH = math.max(T.SETTINGS_ROW_FLOOR, channelLabelH, channelControlH, channelHintH)
            widgets.channelRowContainer:ClearAllPoints()
            widgets.channelRowContainer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", settingsGeo.labelX, y)
            widgets.channelRowContainer:SetSize(settingsGeo.rowW, channelRowH)
            if widgets.channel and widgets.channel.label then
                widgets.channel.label:ClearAllPoints()
                widgets.channel.label:SetPoint("LEFT", widgets.channelRowContainer, "LEFT", 0, 0)
            end
            if widgets.channelHint then
                widgets.channelHint:ClearAllPoints()
                widgets.channelHint:SetPoint("LEFT", widgets.channelRowContainer, "LEFT", channelLabelW + T.CHANNEL_HINT_GAP, 0)
                widgets.channelHint:SetWidth(channelHintMaxW)
            end
            if widgets.channel and widgets.channel.control then
                widgets.channel.control:ClearAllPoints()
                widgets.channel.control:SetPoint("LEFT", widgets.channelRowContainer, "LEFT", coordsLabelOffset, 0)
            end
            y = y - channelRowH

            local extentObjects = {
                header,
                widgets.masterRowContainer,
                widgets.lockRowContainer,
                widgets.lockStateHelper,
                widgets.settingsDivider,
                deathHeader,
                deathDesc,
                widgets.roleHeaderRow,
                widgets.rowTank and widgets.rowTank.container or nil,
                widgets.rowHealer and widgets.rowHealer.container or nil,
                widgets.rowDps and widgets.rowDps.container or nil,
                widgets.rowSelf and widgets.rowSelf.container or nil,
                widgets.rowTank and widgets.rowTank.roleHelper or nil,
                widgets.rowHealer and widgets.rowHealer.roleHelper or nil,
                widgets.rowDps and widgets.rowDps.roleHelper or nil,
                widgets.rowSelf and widgets.rowSelf.roleHelper or nil,
                widgets.rowTank and widgets.rowTank.onScreenHelper or nil,
                widgets.rowHealer and widgets.rowHealer.onScreenHelper or nil,
                widgets.rowDps and widgets.rowDps.onScreenHelper or nil,
                widgets.rowSelf and widgets.rowSelf.onScreenHelper or nil,
                widgets.roleMessageDivider,
                widgets.messageLeftGroup,
                widgets.messageRightGroup,
                widgets.messageHelp,
                widgets.coordsRowContainer,
                widgets.fontRowContainer,
                widgets.channelRowContainer,
            }
            local measuredExtent = measureSettingsVisibleContentExtent(scrollChild, extentObjects)
            local visibleExtent = (measuredExtent and math.ceil(measuredExtent)) or nil
            local fallbackExtent = math.abs(y)
            local used = (visibleExtent or fallbackExtent) + T.BOTTOM_PAD
            local contentHeight = math.max(scrollFrame:GetHeight(), used)
            scrollChild:SetHeight(contentHeight)
            updateScrollBehavior(scrollFrame, scrollChild)
        end
        local function commitMessageTemplate()
            if not PortalAuthorityDB then return end
            local raw = widgets.messageEdit:GetText() or ""
            local text = trim(raw)
            if text == "" then
                text = (PortalAuthority and PortalAuthority.defaults and PortalAuthority.defaults.deathAlertMessageTemplate) or "[role] Died: [name]"
            end
            PortalAuthorityDB.deathAlertMessageTemplate = text
            onApply()
        end

        widgets.messageEdit:SetScript("OnTextChanged", function(edit, userInput)
            if not userInput or not PortalAuthorityDB then
                return
            end

            local text = trim(edit:GetText() or "")
            if text == "" then
                text = (PortalAuthority and PortalAuthority.defaults and PortalAuthority.defaults.deathAlertMessageTemplate) or "[role] Died: [name]"
            end
            PortalAuthorityDB.deathAlertMessageTemplate = text

            -- Real-time preview while unlocked.
            if not PA_SafeBool(PortalAuthorityDB.deathAlertLocked) then
                onApply()
            end
        end)

        widgets.messageEdit:SetScript("OnEditFocusGained", function(edit)
            if edit.HighlightText then
                -- Prevent InputBoxTemplate select-all on focus; keep normal cursor editing.
                edit:HighlightText(0, 0)
            end
        end)

        widgets.messageEdit:SetScript("OnEnterPressed", function(edit)
            commitMessageTemplate()
            edit:ClearFocus()
        end)
        widgets.messageEdit:SetScript("OnEditFocusLost", commitMessageTemplate)

        widgets.coordsEdit:SetScript("OnMouseDown", function()
            beginCoordsEdit()
        end)
        widgets.coordsEdit:SetScript("OnEditFocusGained", function(edit)
            if not widgets._coordsEditing then
                edit:ClearFocus()
                return
            end
            if edit.HighlightText then
                edit:HighlightText()
            end
        end)
        widgets.coordsEdit:SetScript("OnEnterPressed", function(edit)
            finishCoordsEdit(true)
            edit:ClearFocus()
        end)
        widgets.coordsEdit:SetScript("OnEscapePressed", function(edit)
            finishCoordsEdit(false)
            edit:ClearFocus()
        end)
        widgets.coordsEdit:SetScript("OnEditFocusLost", function()
            finishCoordsEdit(true)
        end)

        if widgets.fontSizeEdit then
            local function commitFontSize()
                if not PortalAuthorityDB then return end
                local v = tonumber(widgets.fontSizeEdit:GetText())
                if v == nil then
                    widgets.fontSizeEdit:SetText(tostring(PortalAuthorityDB.deathAlertFontSize or 36))
                    return
                end
                v = math.floor(v)
                if v < 8 then v = 8 end
                if v > 72 then v = 72 end
                PortalAuthorityDB.deathAlertFontSize = v
                onApply()
            end

            widgets.fontSizeEdit:SetScript("OnEnterPressed", function(edit)
                commitFontSize()
                edit:ClearFocus()
            end)
            widgets.fontSizeEdit:SetScript("OnEditFocusLost", commitFontSize)
        end

        self._refresh = refresh
        self._layout = layout
        registerRefreshCallback(function()
            if shouldSuppressSettingsFirstOpenExternalRefresh(self) then
                return
            end
            if self._refresh then
                self._refresh()
            end
        end, self)
        scrollFrame:SetScript("OnSizeChanged", function()
            if handleSettingsFirstOpenSizeReady(self, "size_changed") then
                return
            end
            if shouldSuppressSettingsFirstOpenExternalRefresh(self) then
                return
            end
            if self._layout then self._layout() end
            if self._refresh then self._refresh() end
        end)
        self._settingsFirstOpenKey = "combat"
        self._settingsFirstOpenSizeTarget = scrollFrame
        self._settingsFirstOpenRender = function(panel)
            if panel._layout then
                panel._layout()
            end
            if panel._refresh then
                panel._refresh()
            end
        end
        self._settingsFirstOpenIsReady = function(panel)
            return panelHasSizedViewport(scrollFrame)
                and widgets.rowTank ~= nil and widgets.rowTank.container ~= nil and widgets.rowTank.container:IsShown()
                and widgets.rowHealer ~= nil and widgets.rowHealer.container ~= nil and widgets.rowHealer.container:IsShown()
                and widgets.messageEdit ~= nil and widgets.messageEdit:IsShown()
                and widgets.coordsEdit ~= nil and widgets.coordsEdit:IsShown()
                and (tonumber(scrollChild:GetHeight()) or 0) >= math.max(tonumber(scrollFrame:GetHeight()) or 0, 1)
        end

        if PortalAuthority then
            PortalAuthority.DeathAlerts_OnPositionChanged = function(x, y)
                if not panelRef or not panelRef:IsShown() or not widgets.coordsEdit then
                    return
                end
                if widgets._coordsEditing and widgets.coordsEdit:HasFocus() then
                    return
                end
                widgets.coordsEdit:SetText(string.format("%d, %d", math.floor(tonumber(x) or 0), math.floor(tonumber(y) or 0)))
                widgets.coordsEdit:SetTextColor(0.86, 0.86, 0.88, 1)
            end
        end

        layout()
        refresh()

        self._initialized = true
        settingsSearchRuntime.endDescriptorCapture(self)
    end

    panel:SetScript("OnShow", function(self)
        -- Ensure this canvas panel fills the Settings subcategory canvas.
        if not self._paAnchored then
            local p = self:GetParent()
            if p then
                self:ClearAllPoints()
                self:SetAllPoints(p)
                self._paAnchored = true
            end
        end

        self:EnsureBuilt()
        if not handleSettingsFirstOpenPanelShow(self) then
            withPanelHydration(self, function()
                if self._layout then self._layout() end
                if self._refresh then self._refresh() end
            end)
        end
    end)

    panel:HookScript("OnHide", function(self)
        handleSettingsFirstOpenPanelHide(self)
    end)

    return panel
end


local function createProfilesPanel()
    local panel = CreateFrame("Frame")
    panel.name = "Profiles"
    panel._paSearchSectionKey = "profiles"
    panel._paSearchSectionName = panel.name

    panel.EnsureBuilt = function(self)
        if self._initialized then return end
        self._initialized = true
        resetSettingsFirstOpenPanelState(self)
        ensureDatabase()
        settingsSearchRuntime.beginDescriptorCapture(self)

        local scrollFrame, scrollChild = createScrollableChild(self)
        if not scrollFrame or not scrollChild then
            settingsSearchRuntime.endDescriptorCapture(self)
            return
        end
        self._sizingFrame = scrollFrame
        self._profilesScrollFrame = scrollFrame
        self._profilesScrollChild = scrollChild

        -- Profiles-local frozen layout tokens. Preserve values exactly in this pass.
        local PROFILES_LAYOUT = {
            page = {
                min_content_width = 320,
                module_lane_min_width = 320,
                max_module_width = 720,
                top_padding = 20,
                bottom_padding = 52,
                header_left = 16,
                header_bottom_gap = 30,
                content_left = 20,
                content_right = 20,
                module_gap = 12,
                scroll_width_adjust = 6,
            },
            module = {
                accent_width = 2,
                padding_x = 18,
                padding_top = 16,
                padding_bottom = 12,
                title_content_gap = 16,
                helper_min_height = 16,
                helper_pref_width = 300,
                actions_helper_gap = 10,
            },
            controls = {
                min_width = 120,
                segment_width = 240,
                segment_control_height = 24,
                segment_min_width = 92,
                picker_width = 240,
                picker_height = 22,
                shared_picker_menu_height = 220,
                action_button_width = 240,
                danger_button_width = 240,
                button_height = 24,
                button_gap = 8,
                field_gap = 8,
            },
            meta = {
                row_height = 14,
                row_bottom_gap = 8,
                status_size = 6,
                prefix_to_indicator_gap = 8,
                indicator_to_name_gap = 8,
            },
            profile_selection = {
                shared_label_gap = 18,
            },
            actions = {
                status_gap = 10,
                status_min_height = 12,
            },
            danger = {
                title_gap = 18,
                trailing_gap = 2,
            },
            value_button = {
                min_label_width = 20,
                text_left_inset = 8,
                text_right_inset = 18,
                caret_right_inset = 7,
                label_trim_reserve = 26,
            },
            dialog = {
                backdrop_edge_size = 12,
                backdrop_inset = 3,
                width = 476,
                min_height = 196,
                choice_button_width = 260,
                choice_picker_width = 420,
                choice_picker_height = 320,
                confirm_button_width = 140,
                cancel_button_width = 120,
                edit_text_inset_x = 8,
                inner_left = 18,
                inner_right = 18,
                title_top = 14,
                message_top = 40,
                title_body_gap = 14,
                section_gap = 14,
                label_control_gap = 18,
                feedback_gap = 12,
                feedback_min_height = 12,
                edit_height = 22,
                actions_gap = 16,
                button_gap = 10,
                bottom_padding = 18,
                min_title_height = 16,
                min_message_height = 20,
            },
        }

        local widgets = {}
        self._profilesWidgets = widgets
        self._profilesStatusText = ""
        self._profilesStatusColor = { 0.72, 0.72, 0.76, 1 }
        widgets.sectionDescriptor = createSettingsSectionDescriptor(scrollChild, "Manage your saved profiles.")

        local function helperTone(fs, alpha)
            if not fs then return end
            fs:SetTextColor(0.72, 0.72, 0.76, alpha or 1)
        end

        local function setStatus(text, r, g, b, a)
            self._profilesStatusText = tostring(text or "")
            self._profilesStatusColor = {
                tonumber(r) or 0.72,
                tonumber(g) or 0.72,
                tonumber(b) or 0.76,
                tonumber(a) or 1,
            }
            if widgets.status then
                widgets.status:SetText(self._profilesStatusText)
                widgets.status:SetTextColor(unpack(self._profilesStatusColor))
                if self._profilesStatusText == "" then
                    widgets.status:Hide()
                else
                    widgets.status:Show()
                end
            end
            if self._layout then
                self._layout()
            end
        end

        local function createSubtleCard(parent)
            local card = CreateFrame("Frame", nil, parent, "BackdropTemplate")
            card:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            card:SetBackdropColor(0.06, 0.07, 0.09, 0.42)
            card:SetBackdropBorderColor(0.20, 0.23, 0.29, 0.50)
            return card
        end

        local function createCard(parent, titleText, helperText, accentColor, titleColor)
            local card = createSubtleCard(parent)
            settingsSearchRuntime.markTextContainer(card)
            local accent = card:CreateTexture(nil, "BORDER")
            accent:SetTexture("Interface\\Buttons\\WHITE8x8")
            accent:SetPoint("TOPLEFT", card, "TOPLEFT", 0, 0)
            accent:SetPoint("BOTTOMLEFT", card, "BOTTOMLEFT", 0, 0)
            accent:SetWidth(PROFILES_LAYOUT.module.accent_width)
            accent:SetVertexColor(unpack(accentColor or { 0.27, 0.27, 0.27, 1 }))

            local title = createStyledFontString(card, "ARTWORK", "GameFontHighlightSmall", 10)
            title:SetJustifyH("LEFT")
            title:SetTextColor(unpack(titleColor or { 0.75, 0.77, 0.80, 1 }))
            title:SetText(string.upper(tostring(titleText or "")))

            local helper = createStyledFontString(card, "ARTWORK", "GameFontHighlightSmall", 11)
            helper:SetJustifyH("LEFT")
            helper:SetJustifyV("TOP")
            helper:SetWordWrap(true)
            helper:SetText(tostring(helperText or ""))
            helperTone(helper)

            return {
                frame = card,
                accent = accent,
                title = title,
                helper = helper,
            }
        end

        local function createValueButton(parent, width)
            local button = CreateFrame("Button", nil, parent, "BackdropTemplate")
            button:SetBackdrop({
                bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 },
            })
            button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
            button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
            button:SetSize(width or PROFILES_LAYOUT.controls.picker_width, PROFILES_LAYOUT.controls.picker_height)
            button:RegisterForClicks("LeftButtonUp")

            local text = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 11)
            text:SetPoint("LEFT", button, "LEFT", PROFILES_LAYOUT.value_button.text_left_inset, 0)
            text:SetPoint("RIGHT", button, "RIGHT", -PROFILES_LAYOUT.value_button.text_right_inset, 0)
            text:SetJustifyH("LEFT")
            text:SetTextColor(0.92, 0.92, 0.92, 1)
            text:SetWordWrap(false)
            if text.SetMaxLines then
                text:SetMaxLines(1)
            end

            local caret = createStyledFontString(button, "ARTWORK", "GameFontHighlightSmall", 10)
            caret:SetPoint("RIGHT", button, "RIGHT", -PROFILES_LAYOUT.value_button.caret_right_inset, 0)
            caret:SetText("v")
            caret:SetTextColor(0.76, 0.76, 0.78, 1)

            local function applyVisual(hovered)
                if hovered then
                    button:SetBackdropColor(0.16, 0.17, 0.20, 0.95)
                    button:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                    caret:SetTextColor(0.88, 0.88, 0.90, 1)
                else
                    button:SetBackdropColor(0.10, 0.11, 0.14, 0.95)
                    button:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                    caret:SetTextColor(0.76, 0.76, 0.78, 1)
                end
                if not button:IsEnabled() then
                    button:SetBackdropColor(0.08, 0.09, 0.11, 0.85)
                    button:SetBackdropBorderColor(0.18, 0.20, 0.24, 0.90)
                    text:SetTextColor(0.55, 0.55, 0.58, 1)
                    caret:SetTextColor(0.55, 0.55, 0.58, 1)
                else
                    text:SetTextColor(0.92, 0.92, 0.92, 1)
                end
            end

            function button:SetButtonLabel(labelText)
                local raw = tostring(labelText or "")
                local maxWidth = math.max(PROFILES_LAYOUT.value_button.min_label_width, (button:GetWidth() or 0) - PROFILES_LAYOUT.value_button.label_trim_reserve)
                text:SetWidth(maxWidth)
                text:SetText(raw)
                if text:GetStringWidth() <= maxWidth then
                    return
                end
                local cut = string.len(raw)
                while cut > 0 do
                    local candidate = string.sub(raw, 1, cut) .. "..."
                    text:SetText(candidate)
                    if text:GetStringWidth() <= maxWidth then
                        return
                    end
                    cut = cut - 1
                end
                text:SetText("...")
            end

            button:SetScript("OnEnter", function() applyVisual(true) end)
            button:SetScript("OnLeave", function() applyVisual(false) end)
            button:HookScript("OnShow", function() applyVisual(false) end)
            applyVisual(false)
            return button
        end

        local function skinEditBox(edit)
            if not edit then return end
            if not edit._paPremiumBg then
                edit._paPremiumBg = edit:CreateTexture(nil, "BACKGROUND")
                edit._paPremiumBg:SetAllPoints(edit)
                edit._paPremiumBg:SetTexture("Interface\\Buttons\\WHITE8x8")
                edit._paPremiumBorder = CreateFrame("Frame", nil, edit, "BackdropTemplate")
                edit._paPremiumBorder:SetPoint("TOPLEFT", edit, "TOPLEFT", -1, 1)
                edit._paPremiumBorder:SetPoint("BOTTOMRIGHT", edit, "BOTTOMRIGHT", 1, -1)
                edit._paPremiumBorder:SetBackdrop({
                    edgeFile = "Interface\\Buttons\\WHITE8x8",
                    edgeSize = 1,
                })
                edit._paPremiumBorder:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
            end

            local function applyVisual()
                if edit.Left then edit.Left:SetAlpha(0) end
                if edit.Middle then edit.Middle:SetAlpha(0) end
                if edit.Right then edit.Right:SetAlpha(0) end
                if edit:HasFocus() then
                    edit._paPremiumBg:SetVertexColor(0.12, 0.13, 0.17, 0.95)
                    edit._paPremiumBorder:SetBackdropBorderColor(0.30, 0.33, 0.38, 1.0)
                else
                    edit._paPremiumBg:SetVertexColor(0.10, 0.11, 0.14, 0.95)
                    edit._paPremiumBorder:SetBackdropBorderColor(0.24, 0.27, 0.32, 1.0)
                end
            end

            edit:HookScript("OnShow", applyVisual)
            edit:HookScript("OnEditFocusGained", applyVisual)
            edit:HookScript("OnEditFocusLost", applyVisual)
            applyVisual()
        end

        local function createActionButtonStyled(parent, text, width, styleOpts)
            local btn = createActionButton(parent, text, nil, width)
            styleSecondaryActionButtonShared(btn, styleOpts)
            btn:SetHeight(PROFILES_LAYOUT.controls.button_height)
            if btn.Text then
                applyGlobalFontToObject(btn.Text, 11)
            end
            return btn
        end

        local function refreshModeControlDeferred()
            if widgets.modeControl and widgets.modeControl.Refresh and C_Timer and C_Timer.After then
                C_Timer.After(0, function()
                    if widgets.modeControl and widgets.modeControl.Refresh then
                        widgets.modeControl:Refresh()
                    end
                end)
            end
        end

        local function buildActiveMetadataRow(parent)
            widgets.activeMetaRow = CreateFrame("Frame", nil, parent)
            widgets.activeMetaRow:EnableMouse(false)
            widgets.activeMetaPrefix = createStyledFontString(widgets.activeMetaRow, "ARTWORK", "GameFontHighlightSmall", 11)
            widgets.activeMetaPrefix:SetJustifyH("LEFT")
            widgets.activeMetaPrefix:SetWordWrap(false)
            widgets.activeMetaPrefix:SetTextColor(0.72, 0.72, 0.76, 1)
            if widgets.activeMetaPrefix.SetMaxLines then
                widgets.activeMetaPrefix:SetMaxLines(1)
            end
            widgets.activeMetaIndicator = widgets.activeMetaRow:CreateTexture(nil, "ARTWORK")
            widgets.activeMetaIndicator:SetTexture("Interface\\Buttons\\WHITE8x8")
            widgets.activeMetaIndicator:SetSize(PROFILES_LAYOUT.meta.status_size, PROFILES_LAYOUT.meta.status_size)
            widgets.activeMetaIndicator:SetVertexColor(0.435, 0.682, 0.420, 1)
            widgets.activeMetaName = createStyledFontString(widgets.activeMetaRow, "ARTWORK", "GameFontHighlightSmall", 11)
            widgets.activeMetaName:SetJustifyH("LEFT")
            widgets.activeMetaName:SetWordWrap(false)
            widgets.activeMetaName:SetTextColor(0.94, 0.94, 0.96, 1)
            if widgets.activeMetaName.SetMaxLines then
                widgets.activeMetaName:SetMaxLines(1)
            end
        end

        local function updateActiveMetadataRow(activeInfo)
            local activeDisplay = tostring(activeInfo and activeInfo.displayName or "Default")
            if activeInfo and activeInfo.isShared then
                widgets.activeMetaPrefix:SetText("Using Shared")
            else
                widgets.activeMetaPrefix:SetText("Using Character")
            end
            widgets.activeMetaName:SetText(activeDisplay)
        end

        local function layoutActiveMetadataRow(cardFrame, innerLeft, innerY, rowWidth)
            local row = widgets.activeMetaRow
            local prefix = widgets.activeMetaPrefix
            local indicator = widgets.activeMetaIndicator
            local name = widgets.activeMetaName
            local rowHeight = PROFILES_LAYOUT.meta.row_height

            row:ClearAllPoints()
            row:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            row:SetSize(rowWidth, rowHeight)

            prefix:ClearAllPoints()
            prefix:SetPoint("LEFT", row, "LEFT", 0, 0)
            local prefixWidth = math.ceil(prefix:GetStringWidth() or 0)

            indicator:ClearAllPoints()
            indicator:SetPoint("LEFT", prefix, "RIGHT", PROFILES_LAYOUT.meta.prefix_to_indicator_gap, 0)

            name:ClearAllPoints()
            name:SetPoint("LEFT", indicator, "RIGHT", PROFILES_LAYOUT.meta.indicator_to_name_gap, 0)
            local availableNameWidth = rowWidth
                - prefixWidth
                - PROFILES_LAYOUT.meta.prefix_to_indicator_gap
                - PROFILES_LAYOUT.meta.status_size
                - PROFILES_LAYOUT.meta.indicator_to_name_gap
            if availableNameWidth < 1 then
                availableNameWidth = 1
            end
            name:SetWidth(availableNameWidth)
            if type(setSingleLineEllipsis) == "function" then
                setSingleLineEllipsis(name, tostring(name:GetText() or ""), availableNameWidth)
            end

            return rowHeight
        end

        local function buildProfileSelectionModule()
            local currentCard = createCard(
                scrollChild,
                "Profile Selection",
                "",
                { 0.27, 0.27, 0.27, 1 },
                { 0.75, 0.77, 0.80, 1 }
            )
            widgets.currentCard = currentCard.frame
            widgets.currentCardTitle = currentCard.title
            widgets.currentCardHelper = currentCard.helper
            buildActiveMetadataRow(currentCard.frame)
            return currentCard
        end

        local function buildActionsModule()
            local actionsCard = createCard(
                scrollChild,
                "Actions",
                "All changes require a UI reload to take effect.",
                { 0.27, 0.27, 0.27, 1 },
                { 0.75, 0.77, 0.80, 1 }
            )
            widgets.actionsCard = actionsCard.frame
            widgets.actionsCardTitle = actionsCard.title
            widgets.actionsCardHelper = actionsCard.helper
            return actionsCard
        end

        local function buildDangerModule()
            local dangerCard = createCard(
                scrollChild,
                "Danger",
                "",
                { 0.54, 0.27, 0.27, 1 },
                { 0.78, 0.53, 0.53, 1 }
            )
            widgets.dangerCard = dangerCard.frame
            widgets.dangerCardTitle = dangerCard.title
            widgets.dangerCardHelper = dangerCard.helper
            return dangerCard
        end

        local currentCard = buildProfileSelectionModule()
        local actionsCard = buildActionsModule()
        local dangerCard = buildDangerModule()

        local function openSwitchToCharacterDialog()
            if self._profilesDialog and self._profilesDialog.Open then
                self._profilesDialog:Open({
                    title = "Switch to Character Profile",
                    message = "This character will start using its own local settings. Portal Authority will reload the UI.",
                    confirmText = "Switch & Reload",
                    onConfirm = function()
                        return PortalAuthority:Profiles_SwitchToCharacterAndReload()
                    end,
                })
            end
        end

        local function openSwitchToSharedDialog()
            if self._profilesDialog and self._profilesDialog.Open then
                local sharedChoices = PortalAuthority:Profiles_GetSharedChoices()
                local pickerOptions = {}
                local defaultValue = PortalAuthority:GetProfilesCanonicalDefaultID()
                for _, choice in ipairs(sharedChoices) do
                    pickerOptions[#pickerOptions + 1] = {
                        value = choice.id,
                        label = choice.label,
                    }
                end
                self._profilesDialog:Open({
                    title = "Switch to Shared Profile",
                    message = "Choose which shared profile this character should use. Portal Authority will reload the UI.",
                    confirmText = "Switch & Reload",
                    choiceLabel = "Shared Profile",
                    choiceOptions = pickerOptions,
                    choiceValue = defaultValue,
                    onConfirm = function(_, selectedValue)
                        return PortalAuthority:Profiles_SwitchToSharedAndReload(selectedValue)
                    end,
                })
            end
        end

        local function buildModeControl(parent)
            widgets.modeControl = createPremiumSegmentedChoice(parent, "", nil, {
                { label = "Character", value = "character" },
                { label = "Shared", value = "shared" },
            }, function(value)
                local activeInfo = PortalAuthority and PortalAuthority.Profiles_GetActiveInfo and PortalAuthority:Profiles_GetActiveInfo() or nil
                if not activeInfo or value == activeInfo.kind then
                    refreshModeControlDeferred()
                    return
                end

                if value == "character" then
                    openSwitchToCharacterDialog()
                else
                    openSwitchToSharedDialog()
                end

                refreshModeControlDeferred()
            end, {
                getValue = function()
                    local activeInfo = PortalAuthority and PortalAuthority.Profiles_GetActiveInfo and PortalAuthority:Profiles_GetActiveInfo() or nil
                    return activeInfo and activeInfo.kind or "shared"
                end,
                setValue = function() end,
                minWidth = PROFILES_LAYOUT.controls.segment_width,
                controlHeight = PROFILES_LAYOUT.controls.segment_control_height,
                segmentMinWidth = PROFILES_LAYOUT.controls.segment_min_width,
                selectionVariant = "lock_meta",
            })
            if widgets.modeControl and widgets.modeControl.label then
                widgets.modeControl.label:SetText("")
                widgets.modeControl.label:Hide()
            end
        end

        local function buildSharedPicker(parent)
            widgets.sharedPickerLabel = createStyledFontString(parent, "ARTWORK", "GameFontHighlight", 12)
            widgets.sharedPickerLabel:SetText("Shared Profile")
            widgets.sharedPickerLabel:SetTextColor(0.75, 0.77, 0.80, 1)
            widgets.sharedPicker = createValueButton(parent, PROFILES_LAYOUT.controls.picker_width)
            widgets.sharedPickerPicker = CreatePicker(UIParent, {}, function(value, option)
                local selectedValue = trim(tostring(value or ""))
                local activeInfo = PortalAuthority:Profiles_GetActiveInfo()
                if selectedValue == "" or selectedValue == tostring(activeInfo and activeInfo.sharedID or "") then
                    return
                end
                local displayName = option and option.label or PortalAuthority:Profiles_GetSharedDisplayName(selectedValue) or "Shared Profile"
                if self._profilesDialog and self._profilesDialog.Open then
                    self._profilesDialog:Open({
                        title = "Switch Shared Profile",
                        message = string.format("Switch this character to \"%s\"? Portal Authority will reload the UI.", tostring(displayName)),
                        confirmText = "Switch & Reload",
                        onConfirm = function()
                            return PortalAuthority:Profiles_SwitchToSharedAndReload(selectedValue)
                        end,
                    })
                end
            end, {
                width = PROFILES_LAYOUT.controls.picker_width,
                height = PROFILES_LAYOUT.controls.shared_picker_menu_height,
                noSearch = true,
                hideTitle = true,
                showClearButton = false,
                showCloseButton = false,
                ellipsizeRows = true,
                footerFlowWithRows = true,
                footerHint = "Only user-facing profile names are shown here.",
            })
            widgets.sharedPicker:SetScript("OnClick", function(btn)
                if ACTIVE_PORTAL_PICKER == widgets.sharedPickerPicker and widgets.sharedPickerPicker:IsShown() then
                    widgets.sharedPickerPicker:Close()
                    return
                end
                local sharedChoices = PortalAuthority:Profiles_GetSharedChoices()
                local options = {}
                for _, choice in ipairs(sharedChoices) do
                    options[#options + 1] = {
                        value = choice.id,
                        label = choice.label,
                    }
                end
                widgets.sharedPickerPicker:SetOptions(options)
                widgets.sharedPickerPicker:Open(btn)
            end)
        end

        local function buildActionsControls(parent)
            widgets.createSharedButton = createActionButtonStyled(parent, "Save as Shared Profile", PROFILES_LAYOUT.controls.action_button_width)
            widgets.copyFromButton = createActionButtonStyled(parent, "Copy from Profile", PROFILES_LAYOUT.controls.action_button_width)
            widgets.resetProfileButton = createActionButtonStyled(parent, "Reset Profile", PROFILES_LAYOUT.controls.action_button_width)

            widgets.status = createStyledFontString(parent, "ARTWORK", "GameFontHighlightSmall", 10)
            widgets.status:SetJustifyH("LEFT")
            widgets.status:SetWordWrap(true)
            helperTone(widgets.status)
            widgets.status:Hide()
        end

        local function buildDangerControls(parent)
            widgets.renameSharedButton = createActionButtonStyled(parent, "Rename Profile", PROFILES_LAYOUT.controls.danger_button_width, {
                baseBg = { 0.11, 0.08, 0.09, 0.95 },
                hoverBg = { 0.15, 0.10, 0.11, 0.95 },
                pressedBg = { 0.09, 0.06, 0.07, 0.96 },
                baseBorder = { 0.30, 0.18, 0.20, 0.90 },
                hoverBorder = { 0.38, 0.22, 0.24, 0.95 },
                pressedBorder = { 0.34, 0.20, 0.22, 0.90 },
                textColor = { 0.92, 0.82, 0.83, 1 },
            })
            widgets.deleteSharedButton = createActionButtonStyled(parent, "Delete Profile", PROFILES_LAYOUT.controls.danger_button_width, {
                baseBg = { 0.13, 0.08, 0.09, 0.95 },
                hoverBg = { 0.18, 0.10, 0.11, 0.95 },
                pressedBg = { 0.10, 0.06, 0.07, 0.96 },
                baseBorder = { 0.34, 0.18, 0.20, 0.90 },
                hoverBorder = { 0.44, 0.22, 0.24, 0.95 },
                pressedBorder = { 0.40, 0.20, 0.22, 0.90 },
                textColor = { 0.95, 0.84, 0.85, 1 },
            })
        end

        buildModeControl(currentCard.frame)
        buildSharedPicker(currentCard.frame)
        buildActionsControls(actionsCard.frame)
        buildDangerControls(dangerCard.frame)

        local refreshProfilesBindings = nil
        local layoutProfiles = nil
        local refreshAndLayoutProfiles = nil

        local dialog = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
        dialog:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            edgeSize = PROFILES_LAYOUT.dialog.backdrop_edge_size,
            insets = {
                left = PROFILES_LAYOUT.dialog.backdrop_inset,
                right = PROFILES_LAYOUT.dialog.backdrop_inset,
                top = PROFILES_LAYOUT.dialog.backdrop_inset,
                bottom = PROFILES_LAYOUT.dialog.backdrop_inset,
            },
        })
        dialog:SetBackdropColor(0.05, 0.06, 0.08, 0.985)
        dialog:SetBackdropBorderColor(0.32, 0.35, 0.40, 1)
        dialog:SetSize(PROFILES_LAYOUT.dialog.width, PROFILES_LAYOUT.dialog.min_height)
        dialog:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
        dialog:SetFrameStrata("DIALOG")
        dialog:SetToplevel(true)
        dialog:SetClampedToScreen(true)
        dialog:EnableMouse(true)
        dialog:Hide()
        self._profilesDialog = dialog

        dialog.title = createStyledFontString(dialog, "ARTWORK", "GameFontHighlight", 12)
        dialog.title:SetPoint("TOPLEFT", dialog, "TOPLEFT", PROFILES_LAYOUT.dialog.inner_left, -PROFILES_LAYOUT.dialog.title_top)
        dialog.title:SetTextColor(1, 0.82, 0, 1)
        dialog.title:SetJustifyH("LEFT")

        dialog.message = createStyledFontString(dialog, "ARTWORK", "GameFontHighlightSmall", 11)
        dialog.message:SetPoint("TOPLEFT", dialog, "TOPLEFT", PROFILES_LAYOUT.dialog.inner_left, -PROFILES_LAYOUT.dialog.message_top)
        dialog.message:SetPoint("TOPRIGHT", dialog, "TOPRIGHT", -PROFILES_LAYOUT.dialog.inner_right, -PROFILES_LAYOUT.dialog.message_top)
        dialog.message:SetJustifyH("LEFT")
        dialog.message:SetJustifyV("TOP")
        dialog.message:SetWordWrap(true)
        helperTone(dialog.message)

        dialog.choiceLabel = createStyledFontString(dialog, "ARTWORK", "GameFontHighlight", 12)
        dialog.choiceLabel:SetText("")
        dialog.choiceButton = createValueButton(dialog, PROFILES_LAYOUT.dialog.choice_button_width)

        dialog.editLabel = createStyledFontString(dialog, "ARTWORK", "GameFontHighlight", 12)
        dialog.editLabel:SetText("")
        dialog.edit = CreateFrame("EditBox", nil, dialog, "InputBoxTemplate")
        dialog.edit:SetAutoFocus(false)
        dialog.edit:SetTextInsets(PROFILES_LAYOUT.dialog.edit_text_inset_x, PROFILES_LAYOUT.dialog.edit_text_inset_x, 0, 0)
        dialog.edit:SetTextColor(1, 1, 1, 1)
        dialog.edit:SetHighlightColor(1, 1, 1, 0.25)
        dialog.edit:SetMaxLetters(80)
        applyGlobalFontToObject(dialog.edit, 11)
        skinEditBox(dialog.edit)

        dialog.feedback = createStyledFontString(dialog, "ARTWORK", "GameFontHighlightSmall", 10)
        dialog.feedback:SetJustifyH("LEFT")
        dialog.feedback:SetWordWrap(true)
        dialog.feedback:SetText("")
        dialog.feedback:Hide()

        dialog.confirm = createActionButtonStyled(dialog, "Confirm", PROFILES_LAYOUT.dialog.confirm_button_width)
        dialog.cancel = createActionButtonStyled(dialog, "Cancel", PROFILES_LAYOUT.dialog.cancel_button_width)

        dialog.choicePicker = CreatePicker(UIParent, {}, function(value, option)
            dialog._selectedChoiceValue = value
            dialog._selectedChoiceLabel = option and option.label or ""
            dialog.choiceButton:SetButtonLabel(dialog._selectedChoiceLabel ~= "" and dialog._selectedChoiceLabel or "Select profile")
            dialog.feedback:Hide()
            if dialog._layout then
                dialog._layout()
            end
        end, {
            title = "Choose Profile",
            searchHint = "Search profiles",
            width = PROFILES_LAYOUT.dialog.choice_picker_width,
            height = PROFILES_LAYOUT.dialog.choice_picker_height,
            footerHint = "Only user-facing profile names are shown here.",
        })

        function dialog:Close()
            if self.choicePicker and self.choicePicker.Close then
                self.choicePicker:Close()
            end
            self._onConfirm = nil
            self._selectedChoiceValue = nil
            self._selectedChoiceLabel = ""
            self.feedback:SetText("")
            self.feedback:Hide()
            self:Hide()
        end

        function dialog:Open(spec)
            spec = type(spec) == "table" and spec or {}
            self._onConfirm = spec.onConfirm
            self._selectedChoiceValue = spec.choiceValue
            self._selectedChoiceLabel = spec.choiceLabelText or ""
            self.title:SetText(tostring(spec.title or "Profiles"))
            self.message:SetText(tostring(spec.message or ""))
            self.confirm:SetText(tostring(spec.confirmText or "Confirm"))
            self.cancel:SetText(tostring(spec.cancelText or "Cancel"))
            if self.confirm.Text then applyGlobalFontToObject(self.confirm.Text, 11) end
            if self.cancel.Text then applyGlobalFontToObject(self.cancel.Text, 11) end

            self._hasChoice = spec.choiceOptions ~= nil
            self._hasEdit = spec.editLabel ~= nil

            if self._hasChoice then
                self.choiceLabel:SetText(tostring(spec.choiceLabel or "Profile"))
                self.choiceLabel:Show()
                self.choiceButton:Show()
                self.choicePicker:SetOptions(type(spec.choiceOptions) == "table" and spec.choiceOptions or {})
                local labelText = tostring(spec.choiceLabelText or "")
                if labelText == "" and spec.choiceValue ~= nil then
                    for _, option in ipairs(spec.choiceOptions or {}) do
                        if option.value == spec.choiceValue then
                            labelText = tostring(option.label or "")
                            break
                        end
                    end
                end
                if labelText == "" then
                    labelText = "Select profile"
                end
                self.choiceButton:SetButtonLabel(labelText)
                self.choiceButton:SetScript("OnClick", function(btn)
                    self.choicePicker:Open(btn)
                end)
            else
                self.choiceLabel:Hide()
                self.choiceButton:Hide()
            end

            if self._hasEdit then
                self.editLabel:SetText(tostring(spec.editLabel or "Name"))
                self.editLabel:Show()
                self.edit:Show()
                self.edit:SetText(tostring(spec.editValue or ""))
                self.edit:SetCursorPosition(string.len(self.edit:GetText() or ""))
                self.edit:SetMaxLetters(math.max(1, tonumber(spec.editMaxLetters) or 80))
            else
                self.editLabel:Hide()
                self.edit:Hide()
                self.edit:SetText("")
            end

            self.feedback:SetText("")
            self.feedback:Hide()
            self:Show()
            if self._hasEdit then
                self.edit:SetFocus()
                self.edit:HighlightText(0, string.len(self.edit:GetText() or ""))
            else
                self.edit:ClearFocus()
            end
            if self._layout then
                self._layout()
            end
        end

        local function layoutDialogChoiceSection(innerLeft, y)
            if not dialog._hasChoice then
                return y
            end
            y = y - PROFILES_LAYOUT.dialog.section_gap
            dialog.choiceLabel:ClearAllPoints()
            dialog.choiceLabel:SetPoint("TOPLEFT", dialog, "TOPLEFT", innerLeft, y)
            y = y - PROFILES_LAYOUT.dialog.label_control_gap
            dialog.choiceButton:ClearAllPoints()
            dialog.choiceButton:SetPoint("TOPLEFT", dialog, "TOPLEFT", innerLeft, y)
            return y - PROFILES_LAYOUT.controls.picker_height
        end

        local function layoutDialogEditSection(innerLeft, width, y)
            if not dialog._hasEdit then
                return y
            end
            y = y - PROFILES_LAYOUT.dialog.section_gap
            dialog.editLabel:ClearAllPoints()
            dialog.editLabel:SetPoint("TOPLEFT", dialog, "TOPLEFT", innerLeft, y)
            y = y - PROFILES_LAYOUT.dialog.label_control_gap
            dialog.edit:ClearAllPoints()
            dialog.edit:SetPoint("TOPLEFT", dialog, "TOPLEFT", innerLeft, y)
            dialog.edit:SetWidth(width)
            dialog.edit:SetHeight(PROFILES_LAYOUT.dialog.edit_height)
            return y - PROFILES_LAYOUT.dialog.edit_height
        end

        local function layoutDialogFeedbackSection(innerLeft, innerRight, y)
            local feedbackText = trim(dialog.feedback:GetText() or "")
            if not dialog.feedback:IsShown() or feedbackText == "" then
                return y
            end
            y = y - PROFILES_LAYOUT.dialog.feedback_gap
            dialog.feedback:ClearAllPoints()
            dialog.feedback:SetPoint("TOPLEFT", dialog, "TOPLEFT", innerLeft, y)
            dialog.feedback:SetPoint("TOPRIGHT", dialog, "TOPRIGHT", -innerRight, y)
            return y - math.max(PROFILES_LAYOUT.dialog.feedback_min_height, dialog.feedback:GetStringHeight())
        end

        dialog._layout = function()
            local innerLeft = PROFILES_LAYOUT.dialog.inner_left
            local innerRight = PROFILES_LAYOUT.dialog.inner_right
            local topPad = PROFILES_LAYOUT.dialog.title_top
            local titleGap = PROFILES_LAYOUT.dialog.title_body_gap
            local actionsGap = PROFILES_LAYOUT.dialog.actions_gap
            local bottomPad = PROFILES_LAYOUT.dialog.bottom_padding
            local minHeight = PROFILES_LAYOUT.dialog.min_height
            local width = (dialog:GetWidth() or PROFILES_LAYOUT.dialog.width) - innerLeft - innerRight
            local titleH = math.max(PROFILES_LAYOUT.dialog.min_title_height, dialog.title:GetStringHeight() or 0)
            local y = -(topPad + titleH + titleGap)

            dialog.message:ClearAllPoints()
            dialog.message:SetPoint("TOPLEFT", dialog, "TOPLEFT", innerLeft, y)
            dialog.message:SetWidth(width)
            local messageH = math.max(PROFILES_LAYOUT.dialog.min_message_height, dialog.message:GetStringHeight())
            y = y - messageH
            y = layoutDialogChoiceSection(innerLeft, y)
            y = layoutDialogEditSection(innerLeft, width, y)
            y = layoutDialogFeedbackSection(innerLeft, innerRight, y)

            local buttonRowH = math.max(
                dialog.confirm:GetHeight() or PROFILES_LAYOUT.controls.button_height,
                dialog.cancel:GetHeight() or PROFILES_LAYOUT.controls.button_height
            )
            local totalHeight = math.max(minHeight, (-y) + actionsGap + buttonRowH + bottomPad)
            dialog:SetHeight(totalHeight)

            dialog.cancel:ClearAllPoints()
            dialog.cancel:SetPoint("BOTTOMRIGHT", dialog, "BOTTOMRIGHT", -innerRight, bottomPad)
            dialog.confirm:ClearAllPoints()
            dialog.confirm:SetPoint("RIGHT", dialog.cancel, "LEFT", -PROFILES_LAYOUT.dialog.button_gap, 0)
        end

        local function wireDialogControls()
            dialog.confirm:SetScript("OnClick", function()
                local rawEditValue = dialog._hasEdit and dialog.edit:GetText() or nil
                local selectedValue = dialog._hasChoice and dialog._selectedChoiceValue or nil
                local ok, err = true, nil
                if dialog._hasChoice and (selectedValue == nil or tostring(selectedValue) == "") then
                    ok, err = false, "Select a profile first."
                elseif dialog._onConfirm then
                    ok, err = dialog._onConfirm(rawEditValue, selectedValue)
                end
                if ok == false then
                    dialog.feedback:SetText(tostring(err or "Profile operation failed."))
                    dialog.feedback:SetTextColor(1.0, 0.36, 0.36, 1)
                    dialog.feedback:Show()
                    if dialog._layout then
                        dialog._layout()
                    end
                    refreshModeControlDeferred()
                    return
                end
                dialog:Close()
                if refreshAndLayoutProfiles then
                    refreshAndLayoutProfiles()
                end
            end)
            dialog.cancel:SetScript("OnClick", function()
                dialog:Close()
                refreshModeControlDeferred()
            end)
            dialog.edit:SetScript("OnEscapePressed", function() dialog.cancel:Click() end)
            dialog.edit:SetScript("OnEnterPressed", function() dialog.confirm:Click() end)
        end

        wireDialogControls()

        local function wireActionButtons()
            widgets.createSharedButton:SetScript("OnClick", function()
                dialog:Open({
                    title = "Create Shared Profile",
                    message = "Save the current runtime settings as a new shared profile. Portal Authority will reload the UI.",
                    confirmText = "Create & Reload",
                    editLabel = "Shared Profile Name",
                    editValue = "",
                    editMaxLetters = 80,
                    onConfirm = function(rawName)
                        return PortalAuthority:Profiles_CreateSharedAndSwitch(rawName)
                    end,
                })
            end)

            widgets.copyFromButton:SetScript("OnClick", function()
                local copyChoices = PortalAuthority:Profiles_GetCopySourceChoices()
                if not copyChoices or #copyChoices == 0 then
                    setStatus("No other profile is available to copy from.", 1.0, 0.36, 0.36, 1)
                    return
                end
                local pickerOptions = {}
                local defaultValue = nil
                for index, choice in ipairs(copyChoices) do
                    local encoded = string.format("%s:%s", tostring(choice.kind or ""), tostring(choice.id or ""))
                    pickerOptions[#pickerOptions + 1] = {
                        value = encoded,
                        label = choice.label,
                    }
                    if index == 1 then
                        defaultValue = encoded
                    end
                end
                dialog:Open({
                    title = "Copy From Another Profile",
                    message = "Copy another profile into the current active profile. Portal Authority will reload the UI.",
                    confirmText = "Copy & Reload",
                    choiceLabel = "Source Profile",
                    choiceOptions = pickerOptions,
                    choiceValue = defaultValue,
                    onConfirm = function(_, encodedValue)
                        local kind, id = tostring(encodedValue or ""):match("^(.-):(.*)$")
                        if kind ~= "shared" and kind ~= "character" then
                            return false, "Source profile is unavailable."
                        end
                        if kind == "character" then
                            id = nil
                        end
                        return PortalAuthority:Profiles_CopyIntoActiveAndReload(kind, id)
                    end,
                })
            end)

            widgets.resetProfileButton:SetScript("OnClick", function()
                local activeInfo = PortalAuthority:Profiles_GetActiveInfo()
                local message = "Reset the current profile to defaults? Portal Authority will reload the UI."
                if activeInfo and activeInfo.isShared then
                    message = "Reset this shared profile to defaults? This affects every character using it, and Portal Authority will reload the UI."
                end
                dialog:Open({
                    title = "Reset Current Profile",
                    message = message,
                    confirmText = "Reset & Reload",
                    onConfirm = function()
                        return PortalAuthority:Profiles_ResetActiveAndReload()
                    end,
                })
            end)

            widgets.renameSharedButton:SetScript("OnClick", function()
                local activeInfo = PortalAuthority:Profiles_GetActiveInfo()
                if not activeInfo or not activeInfo.canRenameShared then
                    return
                end
                dialog:Open({
                    title = "Rename Shared Profile",
                    message = "Update the display name for this shared profile.",
                    confirmText = "Rename",
                    editLabel = "Shared Profile Name",
                    editValue = activeInfo.displayName or "",
                    editMaxLetters = 80,
                    onConfirm = function(rawName)
                        local ok, err = PortalAuthority:Profiles_RenameShared(activeInfo.sharedID, rawName)
                        if ok == false then
                            return false, err
                        end
                        setStatus("Shared profile renamed.", 0.66, 0.86, 0.70, 1)
                        return true
                    end,
                })
            end)

            widgets.deleteSharedButton:SetScript("OnClick", function()
                local activeInfo = PortalAuthority:Profiles_GetActiveInfo()
                if not activeInfo or not activeInfo.canDeleteShared then
                    return
                end
                dialog:Open({
                    title = "Delete Shared Profile",
                    message = string.format("Delete \"%s\"? This character will fall back to Default and Portal Authority will reload the UI.", tostring(activeInfo.displayName or "Shared Profile")),
                    confirmText = "Delete & Reload",
                    onConfirm = function()
                        return PortalAuthority:Profiles_DeleteShared(activeInfo.sharedID)
                    end,
                })
            end)
        end

        wireActionButtons()

        local function refreshSharedPicker(activeInfo)
            if activeInfo.isShared then
                widgets.sharedPickerLabel:Show()
                widgets.sharedPicker:Show()
                widgets.sharedPicker:SetButtonLabel(tostring(activeInfo.displayName or "Default"))
                if widgets.sharedPickerPicker and widgets.sharedPickerPicker.SetSelectedValue then
                    widgets.sharedPickerPicker:SetSelectedValue(activeInfo.sharedID)
                end
            else
                widgets.sharedPickerLabel:Hide()
                widgets.sharedPicker:Hide()
                if ACTIVE_PORTAL_PICKER == widgets.sharedPickerPicker and widgets.sharedPickerPicker and widgets.sharedPickerPicker.Close then
                    widgets.sharedPickerPicker:Close()
                end
            end
        end

        local function refreshProfileSelection(activeInfo)
            updateActiveMetadataRow(activeInfo)
            if activeInfo.isShared then
                widgets.currentCardHelper:SetText("Used by any character assigned to this shared profile.")
            else
                widgets.currentCardHelper:SetText("Stored only for this character.")
            end
            widgets.currentCardHelper:Show()
            refreshSharedPicker(activeInfo)
        end

        local function refreshActionsModule()
            if widgets.actionsCardHelper then
                widgets.actionsCardHelper:SetText("All changes require a UI reload to take effect.")
                widgets.actionsCardHelper:Show()
            end
            if widgets.status then
                widgets.status:SetText(self._profilesStatusText)
                widgets.status:SetTextColor(unpack(self._profilesStatusColor))
                if self._profilesStatusText == "" then
                    widgets.status:Hide()
                else
                    widgets.status:Show()
                end
            end
        end

        local function refreshDangerModule(activeInfo)
            if activeInfo.canDeleteShared then
                widgets.dangerCard:Show()
            else
                widgets.dangerCard:Hide()
            end
            if widgets.dangerCardHelper then
                widgets.dangerCardHelper:SetText("")
                widgets.dangerCardHelper:Hide()
            end
        end

        refreshProfilesBindings = function(activeInfo)
            activeInfo = activeInfo or (PortalAuthority and PortalAuthority.Profiles_GetActiveInfo and PortalAuthority:Profiles_GetActiveInfo() or nil)
            if not activeInfo then
                return nil
            end
            refreshProfileSelection(activeInfo)
            if widgets.modeControl and widgets.modeControl.Refresh then
                widgets.modeControl:Refresh()
            end
            refreshDangerModule(activeInfo)
            refreshActionsModule()
            return activeInfo
        end

        local function ensureProfilesHeader()
            local header = widgets.header
            if not header then
                header = createStyledFontString(scrollChild, "ARTWORK", "GameFontNormalLarge", 14)
                header:SetText("|cffffd100Profiles|r")
                header:SetJustifyH("LEFT")
                widgets.header = header
            end
            return header
        end

        local function computeHelperWidth(innerWidth, controlW)
            return math.max(1, math.min(innerWidth, math.max(controlW, PROFILES_LAYOUT.module.helper_pref_width)))
        end

        local function layoutSharedPickerSection(cardFrame, innerLeft, innerY, controlW, currentInfo)
            if currentInfo and currentInfo.isShared then
                widgets.sharedPickerLabel:ClearAllPoints()
                widgets.sharedPickerLabel:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
                widgets.sharedPickerLabel:SetWidth(controlW)
                innerY = innerY - PROFILES_LAYOUT.profile_selection.shared_label_gap
                widgets.sharedPicker:ClearAllPoints()
                widgets.sharedPicker:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
                widgets.sharedPicker:SetWidth(controlW)
                widgets.sharedPicker:SetButtonLabel(tostring(currentInfo.displayName or "Default"))
                innerY = innerY - PROFILES_LAYOUT.controls.picker_height - PROFILES_LAYOUT.controls.field_gap
            end
            return innerY
        end

        local function layoutProfileSelectionModule(cardX, cardY, cardW, currentInfo)
            local cardFrame = widgets.currentCard
            local title = widgets.currentCardTitle
            local helper = widgets.currentCardHelper
            local controlW = math.min(
                PROFILES_LAYOUT.controls.segment_width,
                math.max(PROFILES_LAYOUT.controls.min_width, cardW - (PROFILES_LAYOUT.module.padding_x * 2))
            )
            local innerLeft = PROFILES_LAYOUT.module.padding_x
            local innerWidth = cardW - (PROFILES_LAYOUT.module.padding_x * 2)
            local innerY = -PROFILES_LAYOUT.module.padding_top

            cardFrame:ClearAllPoints()
            cardFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", cardX, cardY)
            cardFrame:SetWidth(cardW)

            title:ClearAllPoints()
            title:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            innerY = innerY - PROFILES_LAYOUT.module.title_content_gap

            local metaH = layoutActiveMetadataRow(cardFrame, innerLeft, innerY, math.min(innerWidth, controlW))
            innerY = innerY - metaH - PROFILES_LAYOUT.meta.row_bottom_gap

            widgets.modeControl.control:ClearAllPoints()
            widgets.modeControl.control:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            widgets.modeControl:Layout(controlW)
            innerY = innerY - PROFILES_LAYOUT.controls.segment_control_height - PROFILES_LAYOUT.controls.field_gap

            innerY = layoutSharedPickerSection(cardFrame, innerLeft, innerY, controlW, currentInfo)

            local helperText = trim(helper:GetText() or "")
            if helperText ~= "" then
                local helperW = computeHelperWidth(innerWidth, controlW)
                helper:Show()
                helper:ClearAllPoints()
                helper:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
                helper:SetWidth(helperW)
                innerY = innerY - math.max(PROFILES_LAYOUT.module.helper_min_height, helper:GetStringHeight())
            else
                helper:Hide()
            end

            local cardH = (-innerY) + PROFILES_LAYOUT.module.padding_bottom
            cardFrame:SetHeight(cardH)
            return cardH
        end

        local function layoutActionsModule(cardX, cardY, cardW)
            local cardFrame = widgets.actionsCard
            local title = widgets.actionsCardTitle
            local helper = widgets.actionsCardHelper
            local controlW = math.min(
                PROFILES_LAYOUT.controls.action_button_width,
                math.max(PROFILES_LAYOUT.controls.min_width, cardW - (PROFILES_LAYOUT.module.padding_x * 2))
            )
            local innerLeft = PROFILES_LAYOUT.module.padding_x
            local innerY = -PROFILES_LAYOUT.module.padding_top

            cardFrame:ClearAllPoints()
            cardFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", cardX, cardY)
            cardFrame:SetWidth(cardW)

            title:ClearAllPoints()
            title:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            innerY = innerY - PROFILES_LAYOUT.module.title_content_gap

            helper:Show()
            helper:ClearAllPoints()
            helper:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            helper:SetWidth(computeHelperWidth(cardW - (PROFILES_LAYOUT.module.padding_x * 2), controlW))
            innerY = innerY - math.max(PROFILES_LAYOUT.module.helper_min_height, helper:GetStringHeight()) - PROFILES_LAYOUT.module.actions_helper_gap

            widgets.createSharedButton:ClearAllPoints()
            widgets.createSharedButton:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            widgets.createSharedButton:SetWidth(controlW)
            innerY = innerY - PROFILES_LAYOUT.controls.button_height - PROFILES_LAYOUT.controls.button_gap

            widgets.copyFromButton:ClearAllPoints()
            widgets.copyFromButton:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            widgets.copyFromButton:SetWidth(controlW)
            innerY = innerY - PROFILES_LAYOUT.controls.button_height - PROFILES_LAYOUT.controls.button_gap

            widgets.resetProfileButton:ClearAllPoints()
            widgets.resetProfileButton:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            widgets.resetProfileButton:SetWidth(controlW)
            innerY = innerY - PROFILES_LAYOUT.controls.button_height - PROFILES_LAYOUT.actions.status_gap

            widgets.status:ClearAllPoints()
            widgets.status:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            widgets.status:SetWidth(controlW)
            if widgets.status:IsShown() then
                innerY = innerY - math.max(PROFILES_LAYOUT.actions.status_min_height, widgets.status:GetStringHeight())
            end

            local cardH = (-innerY) + PROFILES_LAYOUT.module.padding_bottom
            cardFrame:SetHeight(cardH)
            return cardH
        end

        local function layoutDangerModule(cardX, cardY, cardW, controlX)
            local cardFrame = widgets.dangerCard
            local title = widgets.dangerCardTitle
            local controlW = PROFILES_LAYOUT.controls.danger_button_width
            local innerLeft = PROFILES_LAYOUT.module.padding_x
            local innerY = -PROFILES_LAYOUT.module.padding_top

            cardFrame:ClearAllPoints()
            cardFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", cardX, cardY)
            cardFrame:SetWidth(cardW)

            title:ClearAllPoints()
            title:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", innerLeft, innerY)
            innerY = innerY - PROFILES_LAYOUT.danger.title_gap

            widgets.renameSharedButton:ClearAllPoints()
            widgets.renameSharedButton:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", controlX, innerY)
            widgets.renameSharedButton:SetWidth(controlW)
            innerY = innerY - PROFILES_LAYOUT.controls.button_height - PROFILES_LAYOUT.controls.button_gap

            widgets.deleteSharedButton:ClearAllPoints()
            widgets.deleteSharedButton:SetPoint("TOPLEFT", cardFrame, "TOPLEFT", controlX, innerY)
            widgets.deleteSharedButton:SetWidth(controlW)
            innerY = innerY - PROFILES_LAYOUT.controls.button_height - PROFILES_LAYOUT.danger.trailing_gap

            local cardH = (-innerY) + PROFILES_LAYOUT.module.padding_bottom
            cardFrame:SetHeight(cardH)
            return cardH
        end

        layoutProfiles = function(currentInfo)
            currentInfo = currentInfo or (PortalAuthority and PortalAuthority.Profiles_GetActiveInfo and PortalAuthority:Profiles_GetActiveInfo() or nil)
            local scrollW = (scrollFrame:GetWidth() or 0)
            local contentW = math.max(PROFILES_LAYOUT.page.min_content_width, scrollW - PROFILES_LAYOUT.page.scroll_width_adjust)
            local useHostedChrome = isPanelUsingCustomSettingsWindowHost(self)
            scrollChild:SetWidth(contentW)

            local headerWidth = math.max(1, contentW - PROFILES_LAYOUT.page.header_left - PROFILES_LAYOUT.page.content_right)
            local left = PROFILES_LAYOUT.page.content_left
            local right = PROFILES_LAYOUT.page.content_right
            local sectionSpan = math.max(PROFILES_LAYOUT.page.module_lane_min_width, contentW - left - right)
            local y = -PROFILES_LAYOUT.page.top_padding
            if useHostedChrome then
                y = y - SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE
            end

            local header = ensureProfilesHeader()
            if useHostedChrome then
                setSettingsWindowChromeVisible(header, false, scrollChild)
                setSettingsWindowChromeVisible(widgets.sectionDescriptor, false, scrollChild)
            else
                setSettingsWindowChromeVisible(header, true)
                setSettingsWindowChromeVisible(widgets.sectionDescriptor, true, scrollChild)
                header:ClearAllPoints()
                header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", PROFILES_LAYOUT.page.header_left, y)
                header:SetWidth(headerWidth)
                y = y - math.min(PROFILES_LAYOUT.page.header_bottom_gap, 14)
                y = layoutSettingsSectionDescriptor(
                    widgets.sectionDescriptor,
                    scrollChild,
                    PROFILES_LAYOUT.page.header_left,
                    y,
                    headerWidth
                )
            end

            local cardW = math.min(sectionSpan, PROFILES_LAYOUT.page.max_module_width)
            local currentHeight = layoutProfileSelectionModule(left, y, cardW, currentInfo)
            y = y - currentHeight - PROFILES_LAYOUT.page.module_gap

            local actionsHeight = layoutActionsModule(left, y, cardW)
            y = y - actionsHeight - PROFILES_LAYOUT.page.module_gap

            if widgets.dangerCard:IsShown() then
                layoutDangerModule(left, y, cardW, PROFILES_LAYOUT.module.padding_x)
                y = y - widgets.dangerCard:GetHeight() - PROFILES_LAYOUT.page.module_gap
            end

            scrollChild:SetHeight(math.max(1, -y + PROFILES_LAYOUT.page.bottom_padding))
            updateScrollBehavior(scrollFrame, scrollChild)
        end

        refreshAndLayoutProfiles = function()
            local activeInfo = refreshProfilesBindings()
            if not activeInfo then
                return
            end
            layoutProfiles(activeInfo)
        end

        self._refresh = function()
            local perfStart, perfState = PA_PerfBegin("profiles_refresh")
            local activeInfo = refreshProfilesBindings()
            PA_PerfEnd("profiles_refresh", perfStart, perfState)
            return activeInfo
        end

        self._layout = function(activeInfo)
            local perfStart, perfState = PA_PerfBegin("profiles_layout")
            local result = layoutProfiles(activeInfo)
            PA_PerfEnd("profiles_layout", perfStart, perfState)
            return result
        end

        registerRefreshCallback(function()
            if shouldSuppressSettingsFirstOpenExternalRefresh(self) then
                return
            end
            if not self then
                return
            end
            if self.IsShown and self:IsShown() then
                if refreshAndLayoutProfiles then
                    refreshAndLayoutProfiles()
                end
            elseif self._refresh then
                self._refresh()
            end
        end, self)
        scrollFrame:SetScript("OnSizeChanged", function()
            if handleSettingsFirstOpenSizeReady(self, "size_changed") then
                return
            end
            if shouldSuppressSettingsFirstOpenExternalRefresh(self) then
                return
            end
            if self._layout then self._layout() end
        end)
        self._settingsFirstOpenKey = "profiles"
        self._settingsFirstOpenSizeTarget = scrollFrame
        self._settingsFirstOpenRender = function(panel)
            if panel._refresh and panel._layout then
                local activeInfo = panel._refresh()
                panel._layout(activeInfo)
            elseif panel._layout then
                panel._layout()
            elseif panel._refresh then
                panel._refresh()
            end
        end
        self._settingsFirstOpenIsReady = function(panel)
            return panelHasSizedViewport(scrollFrame)
                and widgets.currentCard ~= nil and widgets.currentCard:IsShown()
                and widgets.actionsCard ~= nil and widgets.actionsCard:IsShown()
                and widgets.modeControl ~= nil and widgets.modeControl.control ~= nil and widgets.modeControl.control:IsShown()
                and (tonumber(scrollChild:GetHeight()) or 0) >= 1
        end
        settingsSearchRuntime.endDescriptorCapture(self)
    end

    panel:SetScript("OnShow", function(self)
        if not self._paAnchored then
            local p = self:GetParent()
            if p then
                self:ClearAllPoints()
                self:SetAllPoints(p)
                self._paAnchored = true
            end
        end

        self:EnsureBuilt()
        if not handleSettingsFirstOpenPanelShow(self) then
            withPanelHydration(self, function()
                if self._refresh and self._layout then
                    local activeInfo = self._refresh()
                    self._layout(activeInfo)
                elseif self._layout then
                    self._layout()
                elseif self._refresh then
                    self._refresh()
                end
            end)
        end
    end)

    panel:HookScript("OnHide", function(self)
        handleSettingsFirstOpenPanelHide(self)
        if self and self._profilesWidgets and self._profilesWidgets.sharedPickerPicker and self._profilesWidgets.sharedPickerPicker.Close then
            self._profilesWidgets.sharedPickerPicker:Close()
        end
        if self and self._profilesDialog and self._profilesDialog.Close then
            self._profilesDialog:Close()
        end
    end)

    return panel
end

local function getPortalAuthorityLandingVersionText()
    local version = nil
    if PortalAuthority and type(PortalAuthority.GetAnnouncementReleaseVersionString) == "function" then
        version = PortalAuthority:GetAnnouncementReleaseVersionString()
    end
    if (type(version) ~= "string" or trim(version) == "") and C_AddOns and C_AddOns.GetAddOnMetadata then
        version = C_AddOns.GetAddOnMetadata("PortalAuthority", "Version")
    end
    if (type(version) ~= "string" or trim(version) == "") and GetAddOnMetadata then
        version = GetAddOnMetadata("PortalAuthority", "Version")
    end

    version = trim(tostring(version or ""))
    if version == "" then
        version = "1.0.0"
    end
    if not version:match("^[vV]") then
        version = "v" .. version
    end
    return version
end

local function createPortalAuthorityLandingDivider(parent, width)
    local divider = parent:CreateTexture(nil, "ARTWORK")
    divider:SetTexture("Interface\\Buttons\\WHITE8x8")
    divider:SetVertexColor(0.27, 0.27, 0.27, 0.60)
    divider:SetSize(width or 40, 1)
    return divider
end

local function configurePortalAuthorityLandingFontString(fontString, size, flags, justifyH)
    if not fontString then
        return nil
    end
    fontString._paLandingFontSize = size
    fontString._paLandingFontFlags = flags
    applyGlobalFontToObject(fontString, size, flags)
    fontString:SetJustifyH(justifyH or "CENTER")
    fontString:SetJustifyV("MIDDLE")
    if fontString.SetWordWrap then
        fontString:SetWordWrap(false)
    end
    if fontString.SetNonSpaceWrap then
        fontString:SetNonSpaceWrap(false)
    end
    if fontString.SetMaxLines then
        fontString:SetMaxLines(1)
    end
    return fontString
end

local function createPortalAuthorityLandingStyledFontString(parent, layer, template, size, justifyH)
    local fontString = createStyledFontString(parent, layer, template, size)
    return configurePortalAuthorityLandingFontString(fontString, size, nil, justifyH)
end

local function createPortalAuthorityLandingRawFontString(parent, layer, template, size, flags, justifyH)
    local fontString = parent:CreateFontString(nil, layer, template)
    return configurePortalAuthorityLandingFontString(fontString, size, flags, justifyH)
end

local function refreshPortalAuthorityLandingFontString(fontString)
    if not fontString or not fontString._paLandingFontSize then
        return
    end
    applyGlobalFontToObject(fontString, fontString._paLandingFontSize, fontString._paLandingFontFlags)
end

local function isOnboardingD3GateEnabled()
    return PortalAuthority
        and PortalAuthority.IsOnboardingD3DevGateEnabled
        and PortalAuthority:IsOnboardingD3DevGateEnabled()
end

local function applyPremiumAuthoredFontToObject(object, size, flags)
    if PortalAuthority and PortalAuthority.ApplyPremiumAuthoredFont then
        PortalAuthority:ApplyPremiumAuthoredFont(object, size, flags)
        return
    end
    if object and object.SetFont then
        object:SetFont("Fonts\\FRIZQT__.TTF", size or select(2, object:GetFont()) or 12, flags or "")
    end
end

local function configurePortalAuthorityPremiumFontString(fontString, size, flags, justifyH)
    if not fontString then
        return nil
    end
    fontString._paPremiumLandingFontSize = size
    fontString._paPremiumLandingFontFlags = flags
    applyPremiumAuthoredFontToObject(fontString, size, flags)
    fontString:SetJustifyH(justifyH or "CENTER")
    fontString:SetJustifyV("MIDDLE")
    if fontString.SetWordWrap then
        fontString:SetWordWrap(false)
    end
    if fontString.SetNonSpaceWrap then
        fontString:SetNonSpaceWrap(false)
    end
    if fontString.SetMaxLines then
        fontString:SetMaxLines(1)
    end
    return fontString
end

local function createPortalAuthorityPremiumStyledFontString(parent, layer, template, size, justifyH)
    local fontString = createStyledFontString(parent, layer, template, size)
    return configurePortalAuthorityPremiumFontString(fontString, size, nil, justifyH)
end

local function createPortalAuthorityPremiumRawFontString(parent, layer, template, size, flags, justifyH)
    local fontString = parent:CreateFontString(nil, layer, template)
    return configurePortalAuthorityPremiumFontString(fontString, size, flags, justifyH)
end

local function refreshPortalAuthorityPremiumFontString(fontString)
    if not fontString or not fontString._paPremiumLandingFontSize then
        return
    end
    applyPremiumAuthoredFontToObject(fontString, fontString._paPremiumLandingFontSize, fontString._paPremiumLandingFontFlags)
end

local function printPortalAuthorityCompatMessage(message)
    message = trim(tostring(message or ""))
    if message == "" then
        return
    end
    print("|cffE88BC7Portal Authority:|r " .. message)
end

local function createPortalAuthorityCompatStubButton(parent, label)
    local button = CreateFrame("Button", nil, parent, "BackdropTemplate")
    button:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = 1,
        insets = { left = 0, right = 0, top = 0, bottom = 0 },
    })

    local text = button:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    applyPremiumAuthoredFontToObject(text, 12, "")
    text:SetPoint("CENTER")
    text:SetText(label or "Open Settings")
    text:SetTextColor(0.98, 0.96, 0.88, 1.0)
    text:SetShadowOffset(0, -1)
    text:SetShadowColor(0, 0, 0, 0.35)

    button._text = text

    local function setVisual(state)
        local bgR, bgG, bgB, bgA = 0.11, 0.09, 0.06, 0.97
        local borderR, borderG, borderB, borderA = 0.74, 0.60, 0.24, 0.92
        local textR, textG, textB = 0.99, 0.97, 0.90

        if state == "hover" then
            bgR, bgG, bgB = 0.16, 0.12, 0.07
            borderR, borderG, borderB = 0.90, 0.74, 0.32
            textR, textG, textB = 1.0, 0.98, 0.94
        elseif state == "down" then
            bgR, bgG, bgB = 0.09, 0.07, 0.05
            borderR, borderG, borderB = 0.68, 0.52, 0.18
            textR, textG, textB = 0.96, 0.94, 0.86
        end

        button:SetBackdropColor(bgR, bgG, bgB, bgA)
        button:SetBackdropBorderColor(borderR, borderG, borderB, borderA)
        text:SetTextColor(textR, textG, textB, 1.0)
    end

    button:SetSize(164, 36)
    setVisual("idle")

    button:SetScript("OnEnter", function()
        setVisual("hover")
    end)
    button:SetScript("OnLeave", function()
        setVisual("idle")
    end)
    button:SetScript("OnMouseDown", function()
        setVisual("down")
    end)
    button:SetScript("OnMouseUp", function(selfBtn)
        if selfBtn:IsMouseOver() then
            setVisual("hover")
        else
            setVisual("idle")
        end
    end)

    return button
end

local function createBlizzardCompatibilityStubPanel(sectionKey, name)
    local panel = CreateFrame("Frame")
    panel.name = name
    panel._compatStubSectionKey = sectionKey

    panel.EnsureBuilt = function(self)
        if self._initialized then
            return
        end
        self._initialized = true

        local widgets = {}
        self._compatStubWidgets = widgets

        widgets.group = CreateFrame("Frame", nil, self)

        widgets.banner = widgets.group:CreateTexture(nil, "ARTWORK")
        widgets.banner:SetTexture("Interface\\AddOns\\PortalAuthority\\Media\\Images\\01.PA_banner_wow_1024x256_centered.png")
        widgets.banner:SetTexCoord(0, 1, 0, 1)

        widgets.button = createPortalAuthorityCompatStubButton(widgets.group, "Open Settings")
        widgets.button:SetScript("OnClick", function()
            if not PortalAuthority or type(PortalAuthority.OpenSettingsWindowFromBlizzardStub) ~= "function" then
                printPortalAuthorityCompatMessage("Settings window is unavailable.")
                return
            end

            local ok, err = PortalAuthority:OpenSettingsWindowFromBlizzardStub(self._compatStubSectionKey)
            if not ok and err then
                printPortalAuthorityCompatMessage(err)
            end
        end)

        self._layout = function(frame)
            local stub = frame and frame._compatStubWidgets or nil
            if not stub then
                return
            end

            local panelWidth = tonumber(frame:GetWidth()) or 0
            if panelWidth <= 1 and frame.GetParent then
                local parent = frame:GetParent()
                panelWidth = parent and tonumber(parent:GetWidth()) or 0
            end

            local bannerWidth = math.min(480, math.max(1, panelWidth - 64))
            local bannerHeight = math.max(1, math.floor((bannerWidth / 4) + 0.5))
            local buttonWidth = math.max(156, math.ceil((stub.button._text:GetStringWidth() or 0) + 28))
            local buttonHeight = 36
            local groupWidth = math.max(bannerWidth, buttonWidth)
            local groupHeight = bannerHeight + 18 + buttonHeight

            stub.group:SetSize(groupWidth, groupHeight)
            stub.group:ClearAllPoints()
            stub.group:SetPoint("CENTER", frame, "CENTER", 0, 0)

            stub.banner:SetSize(bannerWidth, bannerHeight)
            stub.banner:ClearAllPoints()
            stub.banner:SetPoint("TOP", stub.group, "TOP", 0, 0)

            stub.button:SetSize(buttonWidth, buttonHeight)
            stub.button:ClearAllPoints()
            stub.button:SetPoint("TOP", stub.banner, "BOTTOM", 0, -18)
        end

        self._refresh = function(frame)
            if frame and frame._layout then
                frame._layout(frame)
            end
        end
    end

    panel:SetScript("OnShow", function(self)
        self:EnsureBuilt()
        if self._refresh then
            self._refresh(self)
        end
    end)

    panel:SetScript("OnSizeChanged", function(self)
        if self._initialized and self._layout then
            self._layout(self)
        end
    end)

    return panel
end

local root = CreateFrame("Frame")
root.name = "Portal Authority"
debugSettingsLog("create frame:", root.name)
root.EnsureBuilt = function(self)
    debugSettingsLog("EnsureBuilt:", self.name, "initialized=", self._initialized and "true" or "false")
    if self._initialized then return end
    self._initialized = true
    resetSettingsFirstOpenPanelState(self)
    ensureDatabase()
    self._sizingFrame = self

    local widgets = {}
    self._landingWidgets = widgets

    local PORTAL_AUTHORITY_LANDING_PERCEPTUAL_CENTER_RATIO = 0.45
    local PORTAL_AUTHORITY_LANDING_MIN_TOP_INSET = 20

    local function getPortalAuthorityLandingElementHeight(element, fallback)
        fallback = math.max(0, tonumber(fallback) or 0)
        if not element then
            return fallback
        end

        local objectType = element.GetObjectType and element:GetObjectType() or nil
        if objectType == "FontString" and element.GetStringHeight then
            local stringHeight = tonumber(element:GetStringHeight()) or 0
            if stringHeight > 0 then
                return math.max(fallback, math.ceil(stringHeight))
            end
        end

        local height = tonumber(element.GetHeight and element:GetHeight()) or 0
        if height > 0 then
            return math.max(fallback, math.ceil(height))
        end

        return fallback
    end

    local function getPortalAuthorityLandingGroupTopOffset(panel, items)
        if type(items) ~= "table" or #items <= 0 then
            return -PORTAL_AUTHORITY_LANDING_MIN_TOP_INSET
        end

        local groupHeight = 0
        for i = 1, #items do
            local item = items[i]
            if type(item) == "table" then
                groupHeight = groupHeight + getPortalAuthorityLandingElementHeight(item.ref, item.fallback)
                groupHeight = groupHeight + math.max(0, tonumber(item.gapAfter) or 0)
            end
        end

        if groupHeight <= 0 then
            return -PORTAL_AUTHORITY_LANDING_MIN_TOP_INSET
        end

        local panelHeight = tonumber(panel and panel.GetHeight and panel:GetHeight()) or 0
        if panelHeight <= 1 then
            return -PORTAL_AUTHORITY_LANDING_MIN_TOP_INSET
        end

        local topInset = (panelHeight * PORTAL_AUTHORITY_LANDING_PERCEPTUAL_CENTER_RATIO) - (groupHeight * 0.5)
        topInset = math.max(PORTAL_AUTHORITY_LANDING_MIN_TOP_INSET, topInset)
        return -math.floor(topInset + 0.5)
    end

    if isOnboardingD3GateEnabled() then
        widgets.banner = self:CreateTexture(nil, "ARTWORK")
        widgets.banner:SetTexture("Interface\\AddOns\\PortalAuthority\\Media\\Images\\01.PA_banner_wow_1024x256_centered.png")
        widgets.banner:SetTexCoord(0, 1, 0, 1)
        widgets.banner:SetSize(460, 115)

        widgets.separator1 = createPortalAuthorityLandingDivider(self, 80)

        widgets.dedicatedLabel = createPortalAuthorityPremiumStyledFontString(self, "ARTWORK", "GameFontNormalSmall", 12)
        widgets.dedicatedLabel:SetText("DEDICATED TO")
        widgets.dedicatedLabel:SetTextColor(1.0, 0.82, 0.0, 1.0)

        widgets.characterName = createPortalAuthorityPremiumRawFontString(self, "ARTWORK", "GameFontHighlight", 15)
        widgets.characterName:SetText("|cFF33937FImbabyuwu|r|cFF555555-Illidan|r")

        widgets.alias = createPortalAuthorityPremiumStyledFontString(self, "ARTWORK", "GameFontHighlightSmall", 12)
        widgets.alias:SetText("Navarone")
        widgets.alias:SetTextColor(0.54, 0.54, 0.56, 1.0)

        widgets.separator2 = createPortalAuthorityLandingDivider(self, 40)

        widgets.inspiredLabel = createPortalAuthorityPremiumStyledFontString(self, "ARTWORK", "GameFontNormalSmall", 12)
        widgets.inspiredLabel:SetText("INSPIRED BY")
        widgets.inspiredLabel:SetTextColor(1.0, 0.82, 0.0, 1.0)

        widgets.guildRow = CreateFrame("Button", nil, self)
        widgets.guildRow:SetSize(1, 28)
        widgets.guildRow:SetHitRectInsets(-8, -8, -4, -4)

        widgets.guildLogo = widgets.guildRow:CreateTexture(nil, "ARTWORK")
        widgets.guildLogo:SetTexture("Interface\\AddOns\\PortalAuthority\\Media\\Images\\overclock_logo_wow_64x64.png")
        widgets.guildLogo:SetTexCoord(0, 1, 0, 1)
        widgets.guildLogo:SetSize(28, 28)

        widgets.guildName = createPortalAuthorityPremiumStyledFontString(widgets.guildRow, "ARTWORK", "GameFontHighlight", 15, "LEFT")
        widgets.guildName:SetText("Overclock")
        widgets.guildName:SetTextColor(1.0, 1.0, 1.0, 1.0)

        widgets.separator3 = createPortalAuthorityLandingDivider(self, 40)

        widgets.author = createPortalAuthorityPremiumRawFontString(self, "ARTWORK", "GameFontNormal", 12)
        widgets.author:SetText("|cFF999999by |r|cFF3FC7EBStormyeyes|r|cFF555555-Mal'Ganis|r")

        widgets.version = createPortalAuthorityPremiumStyledFontString(self, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.version:SetTextColor(0.34, 0.34, 0.36, 1.0)

        widgets.showMeAround = CreateFrame("Button", nil, self)
        widgets.showMeAround:SetSize(1, 18)
        widgets.showMeAround:SetHitRectInsets(-8, -8, -4, -4)
        widgets.showMeAroundText = createPortalAuthorityPremiumStyledFontString(widgets.showMeAround, "ARTWORK", "GameFontHighlightSmall", 11)
        widgets.showMeAroundText:SetPoint("CENTER")
        widgets.showMeAroundText:SetText("Show Me Around")
        widgets.showMeAroundText:SetTextColor(0.78, 0.78, 0.82, 1.0)

        widgets.fontStrings = {
            widgets.dedicatedLabel,
            widgets.characterName,
            widgets.alias,
            widgets.inspiredLabel,
            widgets.guildName,
            widgets.author,
            widgets.version,
            widgets.showMeAroundText,
        }

        local function setGuildRowHoverState(isHover)
            if isHover then
                widgets.guildName:SetTextColor(0.96, 0.96, 0.98, 1.0)
            else
                widgets.guildName:SetTextColor(1.0, 1.0, 1.0, 1.0)
            end
        end

        widgets.guildRow:SetScript("OnEnter", function()
            setGuildRowHoverState(true)
        end)
        widgets.guildRow:SetScript("OnLeave", function()
            setGuildRowHoverState(false)
        end)
        widgets.guildRow:SetScript("OnClick", function()
            if PortalAuthority and PortalAuthority.ShowOverclockLinkPopup then
                PortalAuthority:ShowOverclockLinkPopup()
            end
        end)

        widgets.showMeAround:SetScript("OnEnter", function()
            widgets.showMeAroundText:SetTextColor(0.92, 0.92, 0.95, 1.0)
        end)
        widgets.showMeAround:SetScript("OnLeave", function()
            widgets.showMeAroundText:SetTextColor(0.78, 0.78, 0.82, 1.0)
        end)
        widgets.showMeAround:SetScript("OnMouseDown", function()
            widgets.showMeAroundText:SetTextColor(0.98, 0.98, 1.0, 1.0)
        end)
        widgets.showMeAround:SetScript("OnMouseUp", function()
            if widgets.showMeAround:IsMouseOver() then
                widgets.showMeAroundText:SetTextColor(0.92, 0.92, 0.95, 1.0)
            else
                widgets.showMeAroundText:SetTextColor(0.78, 0.78, 0.82, 1.0)
            end
        end)
        widgets.showMeAround:SetScript("OnClick", function()
            if PortalAuthority and PortalAuthority.StartPremiumOnboardingExperience then
                PortalAuthority:StartPremiumOnboardingExperience("root-show-me-around")
            end
        end)

        self._layout = function()
            local landing = self._landingWidgets
            if not landing then
                return
            end

            local guildRowWidth = tonumber(self._landingGuildRowWidth) or 1
            landing.guildRow:SetSize(guildRowWidth, 28)

            local showMeAroundWidth = tonumber(self._landingShowMeAroundWidth) or 1
            landing.showMeAround:SetSize(showMeAroundWidth, 18)

            local groupTopOffset = getPortalAuthorityLandingGroupTopOffset(self, {
                { ref = landing.banner, fallback = 115, gapAfter = 20 },
                { ref = landing.separator1, fallback = 1, gapAfter = 20 },
                { ref = landing.dedicatedLabel, fallback = 12, gapAfter = 8 },
                { ref = landing.characterName, fallback = 15, gapAfter = 2 },
                { ref = landing.alias, fallback = 12, gapAfter = 18 },
                { ref = landing.separator2, fallback = 1, gapAfter = 18 },
                { ref = landing.inspiredLabel, fallback = 12, gapAfter = 8 },
                { ref = landing.guildRow, fallback = 28, gapAfter = 18 },
                { ref = landing.separator3, fallback = 1, gapAfter = 18 },
                { ref = landing.author, fallback = 12, gapAfter = 16 },
                { ref = landing.version, fallback = 11, gapAfter = 22 },
                { ref = landing.showMeAround, fallback = 18, gapAfter = 0 },
            })

            landing.guildLogo:ClearAllPoints()
            landing.guildLogo:SetPoint("LEFT", landing.guildRow, "LEFT", 0, 0)

            landing.guildName:ClearAllPoints()
            landing.guildName:SetPoint("LEFT", landing.guildLogo, "RIGHT", 8, 0)

            landing.banner:ClearAllPoints()
            landing.banner:SetPoint("TOP", self, "TOP", 0, groupTopOffset)

            landing.separator1:ClearAllPoints()
            landing.separator1:SetPoint("TOP", landing.banner, "BOTTOM", 0, -20)

            landing.dedicatedLabel:ClearAllPoints()
            landing.dedicatedLabel:SetPoint("TOP", landing.separator1, "BOTTOM", 0, -20)

            landing.characterName:ClearAllPoints()
            landing.characterName:SetPoint("TOP", landing.dedicatedLabel, "BOTTOM", 0, -8)

            landing.alias:ClearAllPoints()
            landing.alias:SetPoint("TOP", landing.characterName, "BOTTOM", 0, -2)

            landing.separator2:ClearAllPoints()
            landing.separator2:SetPoint("TOP", landing.alias, "BOTTOM", 0, -18)

            landing.inspiredLabel:ClearAllPoints()
            landing.inspiredLabel:SetPoint("TOP", landing.separator2, "BOTTOM", 0, -18)

            landing.guildRow:ClearAllPoints()
            landing.guildRow:SetPoint("TOP", landing.inspiredLabel, "BOTTOM", 0, -8)

            landing.separator3:ClearAllPoints()
            landing.separator3:SetPoint("TOP", landing.guildRow, "BOTTOM", 0, -18)

            landing.author:ClearAllPoints()
            landing.author:SetPoint("TOP", landing.separator3, "BOTTOM", 0, -18)

            landing.version:ClearAllPoints()
            landing.version:SetPoint("TOP", landing.author, "BOTTOM", 0, -16)

            landing.showMeAround:ClearAllPoints()
            landing.showMeAround:SetPoint("TOP", landing.version, "BOTTOM", 0, -22)
        end

        self._refresh = function()
            local landing = self._landingWidgets
            if not landing then
                return
            end

            for _, fontString in ipairs(landing.fontStrings or {}) do
                refreshPortalAuthorityPremiumFontString(fontString)
            end

            local versionText = getPortalAuthorityLandingVersionText()
            if landing.version:GetText() ~= versionText then
                landing.version:SetText(versionText)
            end

            local guildNameWidth = math.max(1, math.ceil(tonumber((landing.guildName.GetStringWidth and landing.guildName:GetStringWidth()) or 0) or 0))
            self._landingGuildRowWidth = 28 + 8 + guildNameWidth
            self._landingShowMeAroundWidth = math.max(1, math.ceil(tonumber((landing.showMeAroundText.GetStringWidth and landing.showMeAroundText:GetStringWidth()) or 0) or 0))

            if self._layout then
                self._layout()
            end
        end

        registerRefreshCallback(function()
            if shouldSuppressSettingsFirstOpenExternalRefresh(self) then
                return
            end
            if self and self._refresh then
                self._refresh()
            end
        end, self)

        self:SetScript("OnSizeChanged", function(panel)
            if handleSettingsFirstOpenSizeReady(panel, "size_changed") then
                return
            end
            if shouldSuppressSettingsFirstOpenExternalRefresh(panel) then
                return
            end
            if panel and panel._initialized and panel._layout and panel:IsShown() then
                panel._layout()
            end
        end)

        self._settingsFirstOpenKey = "root"
        self._settingsFirstOpenSizeTarget = self
        self._settingsFirstOpenRender = function(panel)
            if panel._refresh then
                panel._refresh()
            elseif panel._layout then
                panel._layout()
            end
        end
        self._settingsFirstOpenIsReady = function(panel)
            local landing = panel and panel._landingWidgets or nil
            return panelHasSizedViewport(panel)
                and landing ~= nil
                and landing.banner ~= nil and landing.banner:IsShown()
                and landing.version ~= nil and landing.version:IsShown()
                and landing.author ~= nil and landing.author:IsShown()
        end

        self._refresh()
        return
    end

    widgets.banner = self:CreateTexture(nil, "ARTWORK")
    widgets.banner:SetTexture("Interface\\AddOns\\PortalAuthority\\Media\\Images\\01.PA_banner_wow_1024x256_centered.png")
    widgets.banner:SetTexCoord(0, 1, 0, 1)
    widgets.banner:SetSize(460, 115)

    widgets.separator1 = createPortalAuthorityLandingDivider(self, 80)

    widgets.dedicatedLabel = createPortalAuthorityLandingStyledFontString(self, "ARTWORK", "GameFontNormalSmall", 11)
    widgets.dedicatedLabel:SetText("DEDICATED TO")
    widgets.dedicatedLabel:SetTextColor(1.0, 0.82, 0.0, 1.0)

    -- Use raw font strings for inline color escapes so their embedded colors remain untouched.
    widgets.characterName = createPortalAuthorityLandingRawFontString(self, "ARTWORK", "GameFontHighlight", 14)
    widgets.characterName:SetText("|cFF33937FImbabyuwu|r|cFF555555-Illidan|r")

    widgets.alias = createPortalAuthorityLandingStyledFontString(self, "ARTWORK", "GameFontHighlightSmall", 11)
    widgets.alias:SetText("Navarone")
    widgets.alias:SetTextColor(0.40, 0.40, 0.40, 1.0)

    widgets.separator2 = createPortalAuthorityLandingDivider(self, 40)

    widgets.inspiredLabel = createPortalAuthorityLandingStyledFontString(self, "ARTWORK", "GameFontNormalSmall", 11)
    widgets.inspiredLabel:SetText("INSPIRED BY")
    widgets.inspiredLabel:SetTextColor(1.0, 0.82, 0.0, 1.0)

    widgets.guildRow = CreateFrame("Frame", nil, self)
    widgets.guildRow:SetSize(1, 28)

    widgets.guildLogo = widgets.guildRow:CreateTexture(nil, "ARTWORK")
    widgets.guildLogo:SetTexture("Interface\\AddOns\\PortalAuthority\\Media\\Images\\overclock_logo_wow_64x64.png")
    widgets.guildLogo:SetTexCoord(0, 1, 0, 1)
    widgets.guildLogo:SetSize(28, 28)

    widgets.guildName = createPortalAuthorityLandingStyledFontString(widgets.guildRow, "ARTWORK", "GameFontHighlight", 13, "LEFT")
    widgets.guildName:SetText("Overclock")
    widgets.guildName:SetTextColor(0.80, 0.80, 0.80, 1.0)

    widgets.separator3 = createPortalAuthorityLandingDivider(self, 40)

    widgets.author = createPortalAuthorityLandingRawFontString(self, "ARTWORK", "GameFontNormal", 11)
    widgets.author:SetText("|cFF999999by |r|cFF3FC7EBStormyeyes|r|cFF555555-Mal'Ganis|r")

    widgets.version = createPortalAuthorityLandingStyledFontString(self, "ARTWORK", "GameFontHighlightSmall", 10)
    widgets.version:SetTextColor(0.22, 0.22, 0.22, 1.0)

    widgets.fontStrings = {
        widgets.dedicatedLabel,
        widgets.characterName,
        widgets.alias,
        widgets.inspiredLabel,
        widgets.guildName,
        widgets.author,
        widgets.version,
    }

    self._layout = function()
        local landing = self._landingWidgets
        if not landing then
            return
        end

        local guildRowWidth = tonumber(self._landingGuildRowWidth) or 1
        landing.guildRow:SetSize(guildRowWidth, 28)

        local groupTopOffset = getPortalAuthorityLandingGroupTopOffset(self, {
            { ref = landing.banner, fallback = 115, gapAfter = 20 },
            { ref = landing.separator1, fallback = 1, gapAfter = 20 },
            { ref = landing.dedicatedLabel, fallback = 11, gapAfter = 6 },
            { ref = landing.characterName, fallback = 14, gapAfter = 2 },
            { ref = landing.alias, fallback = 11, gapAfter = 18 },
            { ref = landing.separator2, fallback = 1, gapAfter = 18 },
            { ref = landing.inspiredLabel, fallback = 11, gapAfter = 8 },
            { ref = landing.guildRow, fallback = 28, gapAfter = 18 },
            { ref = landing.separator3, fallback = 1, gapAfter = 18 },
            { ref = landing.author, fallback = 11, gapAfter = 16 },
            { ref = landing.version, fallback = 10, gapAfter = 0 },
        })

        landing.guildLogo:ClearAllPoints()
        landing.guildLogo:SetPoint("LEFT", landing.guildRow, "LEFT", 0, 0)

        landing.guildName:ClearAllPoints()
        landing.guildName:SetPoint("LEFT", landing.guildLogo, "RIGHT", 8, 0)

        landing.banner:ClearAllPoints()
        landing.banner:SetPoint("TOP", self, "TOP", 0, groupTopOffset)

        landing.separator1:ClearAllPoints()
        landing.separator1:SetPoint("TOP", landing.banner, "BOTTOM", 0, -20)

        landing.dedicatedLabel:ClearAllPoints()
        landing.dedicatedLabel:SetPoint("TOP", landing.separator1, "BOTTOM", 0, -20)

        landing.characterName:ClearAllPoints()
        landing.characterName:SetPoint("TOP", landing.dedicatedLabel, "BOTTOM", 0, -6)

        landing.alias:ClearAllPoints()
        landing.alias:SetPoint("TOP", landing.characterName, "BOTTOM", 0, -2)

        landing.separator2:ClearAllPoints()
        landing.separator2:SetPoint("TOP", landing.alias, "BOTTOM", 0, -18)

        landing.inspiredLabel:ClearAllPoints()
        landing.inspiredLabel:SetPoint("TOP", landing.separator2, "BOTTOM", 0, -18)

        landing.guildRow:ClearAllPoints()
        landing.guildRow:SetPoint("TOP", landing.inspiredLabel, "BOTTOM", 0, -8)

        landing.separator3:ClearAllPoints()
        landing.separator3:SetPoint("TOP", landing.guildRow, "BOTTOM", 0, -18)

        landing.author:ClearAllPoints()
        landing.author:SetPoint("TOP", landing.separator3, "BOTTOM", 0, -18)

        landing.version:ClearAllPoints()
        landing.version:SetPoint("TOP", landing.author, "BOTTOM", 0, -16)
    end

    self._refresh = function()
        local landing = self._landingWidgets
        if not landing then
            return
        end

        for _, fontString in ipairs(landing.fontStrings or {}) do
            refreshPortalAuthorityLandingFontString(fontString)
        end

        local versionText = getPortalAuthorityLandingVersionText()
        if landing.version:GetText() ~= versionText then
            landing.version:SetText(versionText)
        end

        local guildNameWidth = math.max(1, math.ceil(tonumber((landing.guildName.GetStringWidth and landing.guildName:GetStringWidth()) or 0) or 0))
        self._landingGuildRowWidth = 28 + 8 + guildNameWidth

        if self._layout then
            self._layout()
        end
    end

    registerRefreshCallback(function()
        if shouldSuppressSettingsFirstOpenExternalRefresh(self) then
            return
        end
        if self and self._refresh then
            self._refresh()
        end
    end, self)

    self:SetScript("OnSizeChanged", function(panel)
        if handleSettingsFirstOpenSizeReady(panel, "size_changed") then
            return
        end
        if shouldSuppressSettingsFirstOpenExternalRefresh(panel) then
            return
        end
        if panel and panel._initialized and panel._layout and panel:IsShown() then
            panel._layout()
        end
    end)

    self._settingsFirstOpenKey = "root"
    self._settingsFirstOpenSizeTarget = self
    self._settingsFirstOpenRender = function(panel)
        if panel._refresh then
            panel._refresh()
        elseif panel._layout then
            panel._layout()
        end
    end
    self._settingsFirstOpenIsReady = function(panel)
        local landing = panel and panel._landingWidgets or nil
        return panelHasSizedViewport(panel)
            and landing ~= nil
            and landing.banner ~= nil and landing.banner:IsShown()
            and landing.version ~= nil and landing.version:IsShown()
            and landing.author ~= nil and landing.author:IsShown()
    end

    self._refresh()
end

local function ensureRootPanelAnchored(self)
    local parent = self and self:GetParent() or nil
    if not parent then
        return false
    end
    if self._paAnchorParent ~= parent or not self._paAnchored then
        self:ClearAllPoints()
        self:SetAllPoints(parent)
        self._paAnchorParent = parent
    end
    self._paAnchored = true
    return true
end

root:SetScript("OnShow", function(self)
    debugSettingsLog("OnShow:", self.name)
    ensureRootPanelAnchored(self)
    self:EnsureBuilt()
    if not handleSettingsFirstOpenPanelShow(self) then
        withPanelHydration(self, function()
            if self._refresh then
                self._refresh()
            elseif self._layout then
                self._layout()
            end
        end)
    end
end)

root:HookScript("OnHide", function(self)
    handleSettingsFirstOpenPanelHide(self)
end)

local announcementsPanel = createAnnouncementsPanel()
local dockPanel = createDockPanel()
local timersPanel = createTimersPanel()
local interruptTrackerPanel = createInterruptTrackerPanel()
local combatAlertsPanel = createCombatAlertsPanel()
local keystoneUtilityPanel = createKeystoneUtilityPanel()
local profilesPanel = createProfilesPanel()
local rootCategoryPanel = settingsWindowHostGateEnabled and createBlizzardCompatibilityStubPanel("root", root.name) or root

local function initializeDeferredSettingsPanelHidden(panel)
    if not panel or not panel.Hide or not panel.IsShown then
        return
    end
    if panel:IsShown() then
        panel:Hide()
    end
end

-- These panels were being created in the shown state, which means their first
-- real selection never produced an OnShow transition. Starting them hidden
-- makes first selection own the initial build/show path instead of relying on
-- later click-away/click-back or background priming.
local rootCategory = Settings.RegisterCanvasLayoutCategory(rootCategoryPanel, root.name, root.name)
Settings.RegisterAddOnCategory(rootCategory)
debugSettingsLog("register category:", root.name, "id=", rootCategory and rootCategory.GetID and rootCategory:GetID() or "nil")

initializeDeferredSettingsPanelHidden(root)
initializeDeferredSettingsPanelHidden(announcementsPanel)
initializeDeferredSettingsPanelHidden(dockPanel)
initializeDeferredSettingsPanelHidden(timersPanel)
initializeDeferredSettingsPanelHidden(interruptTrackerPanel)
initializeDeferredSettingsPanelHidden(combatAlertsPanel)
initializeDeferredSettingsPanelHidden(profilesPanel)

-- Direct settings panels now build on demand when opened for the first time.

local function bootstrapKeystoneUtilityPanelBuild(attempt)
    if not keystoneUtilityPanel then
        return
    end
    if keystoneUtilityPanel._initialized and keystoneUtilityPanel._layout and keystoneUtilityPanel._refresh and keystoneUtilityPanel._fullRefresh then
        return
    end

    ensureDatabase()
    if PortalAuthorityDB then
        keystoneUtilityPanel:EnsureBuilt()
        if keystoneUtilityPanel._fullRefresh then
            keystoneUtilityPanel._fullRefresh("bootstrap-eager")
        end
        return
    end

    local n = tonumber(attempt) or 0
    if n >= 180 then
        return
    end
    if C_Timer and C_Timer.After then
        C_Timer.After(0, function()
            bootstrapKeystoneUtilityPanelBuild(n + 1)
        end)
    end
end

if PortalAuthority and PortalAuthority.SetSettingsKeystoneBootstrapState then
    if settingsEagerBuildGateEnabled then
        PortalAuthority:SetSettingsKeystoneBootstrapState("suppressed")
    else
        PortalAuthority:SetSettingsKeystoneBootstrapState("unknown")
    end
end

if settingsEagerBuildGateEnabled then
    -- The eager-build gate suppresses the delayed bootstrap kickoff entirely.
elseif C_Timer and C_Timer.After then
    if PortalAuthority and PortalAuthority.SetSettingsKeystoneBootstrapState then
        PortalAuthority:SetSettingsKeystoneBootstrapState("scheduled")
    end
    C_Timer.After(0, function()
        if PortalAuthority and PortalAuthority.SetSettingsKeystoneBootstrapState then
            PortalAuthority:SetSettingsKeystoneBootstrapState("ran")
        end
        bootstrapKeystoneUtilityPanelBuild(0)
    end)
end

if PortalAuthority then
    PortalAuthority.settingsWindowSectionMeta = {
        root = {
            key = "root",
            title = "Home",
            descriptor = "",
            navLabel = nil,
            showInNav = false,
        },
        announcements = {
            key = "announcements",
            title = "Announcements",
            descriptor = "Customize your Utility alerts.",
            navLabel = "Announcements",
            showInNav = true,
        },
        dock = {
            key = "dock",
            title = "Mythic+ Dock",
            descriptor = "Configure your custom portal layout.",
            navLabel = "Mythic+ Dock",
            showInNav = true,
        },
        timers = {
            key = "timers",
            title = "Timers",
            descriptor = "Configure your M+ timers.",
            navLabel = "Timers",
            showInNav = true,
        },
        interrupt = {
            key = "interrupt",
            title = "Interrupt Tracker",
            descriptor = "Tune interrupt visibility and preview behavior.",
            navLabel = "Interrupt Tracker",
            showInNav = true,
        },
        combat = {
            key = "combat",
            title = "Combat Alerts",
            descriptor = "Control death alerts, audio, and on-screen messaging.",
            navLabel = "Combat Alerts",
            showInNav = true,
        },
        keystone = {
            key = "keystone",
            title = "Keystone Utility",
            descriptor = "Configure keystone assistant behavior and automation.",
            navLabel = "Keystone Utility",
            showInNav = true,
        },
        profiles = {
            key = "profiles",
            title = "Profiles",
            descriptor = "Manage your saved profiles.",
            navLabel = "Profiles",
            showInNav = true,
        },
    }
    PortalAuthority.settingsWindowNavOrder = {
        "announcements",
        "dock",
        "timers",
        "interrupt",
        "combat",
        "keystone",
        "profiles",
    }
    PortalAuthority.settingsCategory = rootCategory
    PortalAuthority.rootPanel = root
    local rootCategoryID = rootCategory and rootCategory.GetID and rootCategory:GetID() or nil
    PortalAuthority.rootCategoryID = rootCategoryID
    PortalAuthority.rootCategory = rootCategory
    PortalAuthority.defaultCategoryID = rootCategoryID
    PortalAuthority._settingsFirstOpenHostDebug = settingsFirstOpenHost
    PortalAuthority._settingsFirstOpenDebugPanels = {
        { key = "root", name = root.name, panel = root },
        { key = "announcements", name = announcementsPanel.name, panel = announcementsPanel },
        { key = "dock", name = dockPanel.name, panel = dockPanel },
        { key = "timers", name = timersPanel.name, panel = timersPanel },
        { key = "interrupt", name = interruptTrackerPanel.name, panel = interruptTrackerPanel },
        { key = "combat", name = combatAlertsPanel.name, panel = combatAlertsPanel },
        { key = "keystone", name = keystoneUtilityPanel.name, panel = keystoneUtilityPanel },
        { key = "profiles", name = profilesPanel.name, panel = profilesPanel },
    }
    PortalAuthority.settingsPanelWalkOrder = {
        "root",
        "announcements",
        "dock",
        "timers",
        "interrupt",
        "combat",
        "keystone",
        "profiles",
    }
    PortalAuthority.settingsPanelRegistry = {
        root = {
            key = "root",
            name = root.name,
            panel = root,
            category = rootCategory,
            categoryID = PortalAuthority.rootCategoryID,
            title = PortalAuthority.settingsWindowSectionMeta.root.title,
            descriptor = PortalAuthority.settingsWindowSectionMeta.root.descriptor,
            navLabel = PortalAuthority.settingsWindowSectionMeta.root.navLabel,
            showInNav = PortalAuthority.settingsWindowSectionMeta.root.showInNav,
        },
        announcements = {
            key = "announcements",
            name = announcementsPanel.name,
            panel = announcementsPanel,
            title = PortalAuthority.settingsWindowSectionMeta.announcements.title,
            descriptor = PortalAuthority.settingsWindowSectionMeta.announcements.descriptor,
            navLabel = PortalAuthority.settingsWindowSectionMeta.announcements.navLabel,
            showInNav = PortalAuthority.settingsWindowSectionMeta.announcements.showInNav,
        },
        dock = {
            key = "dock",
            name = dockPanel.name,
            panel = dockPanel,
            title = PortalAuthority.settingsWindowSectionMeta.dock.title,
            descriptor = PortalAuthority.settingsWindowSectionMeta.dock.descriptor,
            navLabel = PortalAuthority.settingsWindowSectionMeta.dock.navLabel,
            showInNav = PortalAuthority.settingsWindowSectionMeta.dock.showInNav,
        },
        timers = {
            key = "timers",
            name = timersPanel.name,
            panel = timersPanel,
            title = PortalAuthority.settingsWindowSectionMeta.timers.title,
            descriptor = PortalAuthority.settingsWindowSectionMeta.timers.descriptor,
            navLabel = PortalAuthority.settingsWindowSectionMeta.timers.navLabel,
            showInNav = PortalAuthority.settingsWindowSectionMeta.timers.showInNav,
        },
        interrupt = {
            key = "interrupt",
            name = interruptTrackerPanel.name,
            panel = interruptTrackerPanel,
            title = PortalAuthority.settingsWindowSectionMeta.interrupt.title,
            descriptor = PortalAuthority.settingsWindowSectionMeta.interrupt.descriptor,
            navLabel = PortalAuthority.settingsWindowSectionMeta.interrupt.navLabel,
            showInNav = PortalAuthority.settingsWindowSectionMeta.interrupt.showInNav,
        },
        combat = {
            key = "combat",
            name = combatAlertsPanel.name,
            panel = combatAlertsPanel,
            title = PortalAuthority.settingsWindowSectionMeta.combat.title,
            descriptor = PortalAuthority.settingsWindowSectionMeta.combat.descriptor,
            navLabel = PortalAuthority.settingsWindowSectionMeta.combat.navLabel,
            showInNav = PortalAuthority.settingsWindowSectionMeta.combat.showInNav,
        },
        keystone = {
            key = "keystone",
            name = keystoneUtilityPanel.name,
            panel = keystoneUtilityPanel,
            title = PortalAuthority.settingsWindowSectionMeta.keystone.title,
            descriptor = PortalAuthority.settingsWindowSectionMeta.keystone.descriptor,
            navLabel = PortalAuthority.settingsWindowSectionMeta.keystone.navLabel,
            showInNav = PortalAuthority.settingsWindowSectionMeta.keystone.showInNav,
        },
        profiles = {
            key = "profiles",
            name = profilesPanel.name,
            panel = profilesPanel,
            title = PortalAuthority.settingsWindowSectionMeta.profiles.title,
            descriptor = PortalAuthority.settingsWindowSectionMeta.profiles.descriptor,
            navLabel = PortalAuthority.settingsWindowSectionMeta.profiles.navLabel,
            showInNav = PortalAuthority.settingsWindowSectionMeta.profiles.showInNav,
        },
    }
end
