-- Portal Authority — options/panel_interrupt.lua
-- Interrupt Tracker settings panel and guided preview UI.
--
-- Depends on: PortalAuthority.OptionsInternal shared helpers; PortalAuthority.Modules; InterruptTracker
-- Exposes:    PortalAuthority.OptionsInternal.createInterruptTrackerPanel
-- DB keys:    PortalAuthorityDB.modules.interruptTracker*
-- Events:     none
-- Search key: interrupt

PortalAuthority = PortalAuthority or {}

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

if not Settings or not Settings.RegisterCanvasLayoutCategory then
    return
end

PortalAuthority.OptionsInternal = PortalAuthority.OptionsInternal or {}
local OptionsInternal = PortalAuthority.OptionsInternal
local L = PortalAuthority.L

local settingsSearchRuntime = OptionsInternal.SearchRuntime
local trim = OptionsInternal.trim
local rgba255 = OptionsInternal.rgba255
local unpackColor = OptionsInternal.unpackColor
local applyGlobalFontToObject = OptionsInternal.applyGlobalFontToObject
local getPortalMedia = OptionsInternal.getPortalMedia
local normalizeSoundChoiceValue = OptionsInternal.normalizeSoundChoiceValue
local compareChoiceLabels = OptionsInternal.compareChoiceLabels
local normalizeChoicePathKey = OptionsInternal.normalizeChoicePathKey
local resolveFontChoicePath = OptionsInternal.resolveFontChoicePath
local getSoundChoiceValueKey = OptionsInternal.getSoundChoiceValueKey
local buildFallbackSoundChoices = OptionsInternal.buildFallbackSoundChoices
local getSummonSoundChoices = OptionsInternal.getSummonSoundChoices
local getAvailableFontChoices = OptionsInternal.getAvailableFontChoices
local buildSharedFontPickerChoices = OptionsInternal.buildSharedFontPickerChoices
local SUMMON_SOUND_CHANNEL_CHOICES = OptionsInternal.SUMMON_SOUND_CHANNEL_CHOICES
local debugSettingsLog = OptionsInternal.debugSettingsLog or function() end
local FLAT_SETTINGS_BACKDROP = OptionsInternal.FLAT_SETTINGS_BACKDROP
local SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE = OptionsInternal.SETTINGS_WINDOW_HOSTED_TOP_RHYTHM_NUDGE
local SETTINGS_WINDOW_SCROLLBAR_WIDTH = OptionsInternal.SETTINGS_WINDOW_SCROLLBAR_WIDTH
local SETTINGS_WINDOW_SCROLLBAR_GAP = OptionsInternal.SETTINGS_WINDOW_SCROLLBAR_GAP
local SETTINGS_WINDOW_SCROLLBAR_MIN_THUMB_HEIGHT = OptionsInternal.SETTINGS_WINDOW_SCROLLBAR_MIN_THUMB_HEIGHT
local SETTINGS_WINDOW_HOST_COLORS = OptionsInternal.SETTINGS_WINDOW_HOST_COLORS
local SETTINGS_WINDOW_SCROLLBAR_TRACK = OptionsInternal.SETTINGS_WINDOW_SCROLLBAR_TRACK
local SETTINGS_WINDOW_SCROLLBAR_THUMB = OptionsInternal.SETTINGS_WINDOW_SCROLLBAR_THUMB
local SETTINGS_WINDOW_SCROLLBAR_THUMB_HOVER = OptionsInternal.SETTINGS_WINDOW_SCROLLBAR_THUMB_HOVER
local frameIsAlive = OptionsInternal.frameIsAlive
local isDescendedFromFrame = OptionsInternal.isDescendedFromFrame
local markSettingsWindowVisualOptIn = OptionsInternal.markSettingsWindowVisualOptIn
local isUsingCustomSettingsWindowVisualStyle = OptionsInternal.isUsingCustomSettingsWindowVisualStyle
local registerSettingsWindowVisualRefresh = OptionsInternal.registerSettingsWindowVisualRefresh
local setTextureSolidColor = OptionsInternal.setTextureSolidColor
local hideDefaultScrollBarPart = OptionsInternal.hideDefaultScrollBarPart
local getTemplateScrollBar = OptionsInternal.getTemplateScrollBar
local hideDefaultScrollBarChrome = OptionsInternal.hideDefaultScrollBarChrome
local refreshCustomSettingsScrollBarThumb = OptionsInternal.refreshCustomSettingsScrollBarThumb
local settingsScrollRuntime = PortalAuthority._settingsScrollRuntime or OptionsInternal.settingsScrollRuntime
local createStyledFontString = OptionsInternal.createStyledFontString
local createTopRightHeader = OptionsInternal.createTopRightHeader
local PA_SafeBool = OptionsInternal.PA_SafeBool
local getClassHex = OptionsInternal.getClassHex
local createCheckbox = OptionsInternal.createCheckbox
local createActionButton = OptionsInternal.createActionButton
local styleSecondaryActionButtonShared = OptionsInternal.styleSecondaryActionButtonShared
local createNumeric = OptionsInternal.createNumeric
local createDropdown = OptionsInternal.createDropdown
local createDynamicDropdown = OptionsInternal.createDynamicDropdown
local createPremiumSegmentedChoice = OptionsInternal.createPremiumSegmentedChoice
local CreatePicker = OptionsInternal.CreatePicker
local CreateStepperControl = OptionsInternal.CreateStepperControl
local createCanonicalDockFontSizeStepperControl = OptionsInternal.CreateStepperControl or OptionsInternal.createCanonicalDockFontSizeStepperControl
local createTextPlacement = OptionsInternal.createTextPlacement
local setSettingsControlEnabled = OptionsInternal.setSettingsControlEnabled
local setSettingsTextEnabled = OptionsInternal.setSettingsTextEnabled
local applySettingsWindowSelectButtonChrome = OptionsInternal.applySettingsWindowSelectButtonChrome
local createScrollableChild = OptionsInternal.createScrollableChild
local updateScrollBehavior = OptionsInternal.updateScrollBehavior
local withPanelHydration = OptionsInternal.withPanelHydration
local panelHasSizedViewport = OptionsInternal.panelHasSizedViewport
local isControlHydrating = OptionsInternal.isControlHydrating
local handleSettingsFirstOpenSizeReady = OptionsInternal.handleSettingsFirstOpenSizeReady
local handleSettingsFirstOpenPanelShow = OptionsInternal.handleSettingsFirstOpenPanelShow
local handleSettingsFirstOpenPanelHide = OptionsInternal.handleSettingsFirstOpenPanelHide
local shouldSuppressSettingsFirstOpenExternalRefresh = OptionsInternal.shouldSuppressSettingsFirstOpenExternalRefresh
local isPanelUsingCustomSettingsWindowHost = OptionsInternal.isPanelUsingCustomSettingsWindowHost
local setSettingsWindowChromeVisible = OptionsInternal.setSettingsWindowChromeVisible
local refreshSettingsWindowHeaderAccessoryIfHosted = OptionsInternal.refreshSettingsWindowHeaderAccessoryIfHosted
local refreshPanel = OptionsInternal.refreshPanel
local createScrollableTextArea = OptionsInternal.createScrollableTextArea
local createSettingsSectionDescriptor = OptionsInternal.createSettingsSectionDescriptor
local layoutSettingsSectionDescriptor = OptionsInternal.layoutSettingsSectionDescriptor
local registerRefreshCallback = OptionsInternal.registerRefreshCallback
local ensureDatabase = OptionsInternal.ensureDatabase
local IsPointerInsideActivePickerSafeZone = OptionsInternal.IsPointerInsideActivePickerSafeZone
local CloseActivePortalPicker = OptionsInternal.CloseActivePortalPicker
local restoreColorPickerPrevious = OptionsInternal.restoreColorPickerPrevious
local settingsFirstOpenHost = OptionsInternal.settingsFirstOpenHost
local resetSettingsFirstOpenPanelState = OptionsInternal.resetSettingsFirstOpenPanelState

local function createInterruptTrackerPanel()
    local panel = CreateFrame("Frame")
    panel.name = L["SETTINGS_IT_TITLE"]
    panel._paSearchSectionKey = "interrupt"
    panel._paSearchSectionName = panel.name
    settingsSearchRuntime.setPanelSearchTerms(panel, L["SETTINGS_SEARCH_SECTION_TERMS_INTERRUPT"])
    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 L["SETTINGS_SELECT_OPTION"]),
                searchHint = tostring(pickerOpts.searchHint or L["COMMON_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 = L["COMMON_NONE"], buttonLabel = L["COMMON_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 L["COMMON_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 = L["COMMON_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 = L["COMMON_OFF"], value = false, toggleState = "off" },
                { label = L["COMMON_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, L["COMMON_LOCK_POSITION"], nil, {
                { label = L["COMMON_UNLOCKED"], value = false },
                { label = L["COMMON_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("|cffffd100" .. L["SETTINGS_IT_TITLE"] .. "|r")
        widgets.sectionDescriptor = createSettingsSectionDescriptor(scrollChild, L["SETTINGS_IT_DESCRIPTOR"])

        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,
            L["COMMON_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, L["COMMON_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(L["SETTINGS_IT_APPEARANCE"])
        widgets.alertHeader = createStyledFontString(widgets.alertCard, "ARTWORK", "GameFontHighlight", 12)
        widgets.alertHeader:SetText(L["SETTINGS_IT_ALERTING"])
        widgets.guidedPreviewHeader = createStyledFontString(widgets.guidedPreviewCard, "ARTWORK", "GameFontHighlight", 12)
        widgets.guidedPreviewHeader:SetText(L["SETTINGS_IT_TRACKER_PREVIEW"])

        widgets.widthLabel = createStyledFontString(widgets.appearanceCard, "ARTWORK", "GameFontHighlight", 12)
        widgets.widthLabel:SetText(L["COMMON_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
        )
        settingsSearchRuntime.attachSearchTermsToTextRef(widgets.widthLabel, widgets.widthStepper and widgets.widthStepper.control or widgets.widthLabel, L["SETTINGS_SEARCH_TERMS_INTERRUPT_WIDTH"])

        widgets.rowHeightLabel = createStyledFontString(widgets.appearanceCard, "ARTWORK", "GameFontHighlight", 12)
        widgets.rowHeightLabel:SetText(L["COMMON_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,
            L["COMMON_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, L["SETTINGS_IT_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 = L["SETTINGS_SELECT_FONT_FACE"],
            searchHint = L["SETTINGS_SEARCH_FONTS_BY_NAME"],
            pickerWidth = 420,
            pickerHeight = 380,
            useOptionFontPreview = true,
            previewFontSize = 13,
            emptyLabel = L["COMMON_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, L["SETTINGS_IT_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 = L["SETTINGS_SELECT_BAR_TEXTURE"],
            searchHint = L["SETTINGS_SEARCH_TEXTURES"],
            pickerWidth = 420,
            pickerHeight = 360,
            useOptionTexturePreview = true,
        })

        widgets.useClassColors = createToggleRow(widgets.appearanceCard, L["SETTINGS_IT_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, L["SETTINGS_IT_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, L["SETTINGS_IT_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, L["SETTINGS_IT_ALERT_SOUND"], function()
            local media = PortalAuthority and PortalAuthority.Media
            return media and media.GetChoices and media.GetChoices("sound", {
                includeCurrent = getDB().alertSound,
                includeNone = true,
                noneLabel = L["COMMON_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 = L["SETTINGS_SELECT_ALERT_SOUND"],
            searchHint = L["SETTINGS_SEARCH_SOUNDS"],
            pickerWidth = 420,
            pickerHeight = 360,
            emptyLabel = L["COMMON_NONE"],
            onRightClick = function(value)
                previewInterruptTrackerAlertSoundValue(value)
            end,
            onOptionRightClick = function(value)
                previewInterruptTrackerAlertSoundValue(value)
            end,
            footerHint = L["SETTINGS_IT_RIGHT_CLICK_PREVIEWS_LEFT_CLICK_SELECTS"],
        })
        widgets.alertScope = createPremiumSegmentedChoice(widgets.alertCard, L["SETTINGS_IT_SCOPE"], nil, {
            { label = L["COMMON_ALL"], value = false },
            { label = L["COMMON_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,
        })
        settingsSearchRuntime.attachSearchTerms(widgets.alertSound, L["SETTINGS_SEARCH_TERMS_SOUND"])

        widgets.rightDisplay = createPremiumSegmentedChoice(widgets.appearanceCard, L["SETTINGS_IT_ROW_VALUE"], nil, {
            { label = L["SETTINGS_IT_INTERRUPT_COUNT"], value = "count" },
            { label = L["SETTINGS_IT_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(L["SETTINGS_IT_PREVIEW_BEST_TRACKING"])
            widgets.guidedPreviewGoldText:SetText(L["SETTINGS_IT_PREVIEW_FALLBACK_TRACKING"])
            widgets.guidedPreviewIconNote:SetText(L["SETTINGS_IT_PREVIEW_ICON_NOTE"])
            widgets.guidedPreviewValueNote:SetText(L["SETTINGS_IT_PREVIEW_VALUE_NOTE"])
            widgets.guidedPreviewSortNote:SetText(L["SETTINGS_IT_PREVIEW_SORT_NOTE"])
            widgets.guidedPreviewLimitNote:SetText(L["SETTINGS_IT_PREVIEW_LIMIT_NOTE"])
            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 L["SETTINGS_IT_LOCKED_HELP"] or L["SETTINGS_IT_UNLOCKED_HELP"])
            else
                widgets.lockHelper:SetText(L["SETTINGS_IT_DISABLED_HELP"])
            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 L["SETTINGS_IT_LOCKED_HELP"] or L["SETTINGS_IT_UNLOCKED_HELP"])
            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
OptionsInternal.createInterruptTrackerPanel = createInterruptTrackerPanel
