-- rChat: GUI
-- Überarbeitet im Stil von ObeliskMinimap (Sidebar-Layout, rote Akzente, moderne Controls)

local A, L = ...

local configFrame
local activeTab = 0

-- ============================================================
-- Fallback Rot #af1917; live: rChatGuiTheme.ApplyPalette(C)
-- ============================================================
local C = {
    primary    = {0.686, 0.098, 0.090},   -- #af1917  rot
    primaryHi  = {1.00,  0.30,  0.28},    -- helles Rot
    primaryDim = {0.35,  0.05,  0.04},    -- gedimmtes Rot
    bg         = {0.045, 0.040, 0.040, 0.98},
    sidebar    = {0.038, 0.034, 0.034, 1.0},
    content    = {0.058, 0.052, 0.052, 0.97},
    panel      = {0.09,  0.080, 0.080, 0.95},
    border     = {0.25,  0.10,  0.10,  1.0},
    text       = {0.95,  0.90,  0.90},
    textDim    = {0.58,  0.50,  0.50},
    textBright = {1.00,  1.00,  1.00},
    separator  = {0.35,  0.10,  0.10,  0.45},
    toggleOff  = {0.10,  0.08,  0.08},
}

-- ============================================================
-- LAYOUT
-- ============================================================
local FRAME_W_DEFAULT = 820
local FRAME_H_DEFAULT = 600
local FRAME_W, FRAME_H = FRAME_W_DEFAULT, FRAME_H_DEFAULT
local TITLE_H   = 52
local SIDEBAR_W = 185
local BOT_H     = 42
local PAD       = 16
local function CW() return FRAME_W - SIDEBAR_W - 8 end

local LOGO_PATH = "Interface\\AddOns\\rChat\\core\\logo"

-- ============================================================
-- BASIS-HELPER
-- ============================================================
local function Tex(parent, layer)
    return parent:CreateTexture(nil, layer or "ARTWORK")
end

local function FS(parent, template)
    return parent:CreateFontString(nil, "OVERLAY", template or "GameFontNormal")
end

local function AddOnVersionFromToc(folder)
    local gm = C_AddOns and C_AddOns.GetAddOnMetadata or GetAddOnMetadata
    if type(gm) ~= "function" then return nil end
    local v = gm(folder, "Version")
    if type(v) == "string" and strtrim(v) ~= "" then return strtrim(v) end
    return nil
end

local function AttachGuiTitleVersion(parent, anchorTitle, folder, dr, dg, db)
    local ver = AddOnVersionFromToc(folder)
    if not ver then return end
    local fs = FS(parent, "GameFontDisableSmall")
    fs:SetPoint("LEFT", anchorTitle, "RIGHT", 8, -4)
    fs:SetTextColor(dr or 0.55, dg or 0.55, db or 0.58, 0.9)
    fs:SetText("v" .. ver)
end

local function FlatFrame(parent, r, g, b, a, br, bg_, bb, ba)
    local f = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    f:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
        tile=false, edgeSize=1, insets={left=0,right=0,top=0,bottom=0}})
    f:SetBackdropColor(r or 0, g or 0, b or 0, a or 1)
    f:SetBackdropBorderColor(br or r or 0, bg_ or g or 0, bb or b or 0, ba or a or 1)
    return f
end

local function SectionHeader(parent, text, anchor, xOfs, yOfs)
    local lbl = FS(parent, "GameFontNormal")
    lbl:SetPoint("TOPLEFT", anchor or parent, "TOPLEFT", xOfs or 0, yOfs or 0)
    lbl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 1)
    lbl:SetText(text)
    local line = Tex(parent, "BACKGROUND")
    line:SetHeight(1)
    line:SetPoint("TOPLEFT",  lbl,    "BOTTOMLEFT",  0, -3)
    line:SetPoint("TOPRIGHT", parent, "TOPRIGHT",    0, yOfs or 0)
    line:SetGradient("HORIZONTAL",
        CreateColor(C.primary[1], C.primary[2], C.primary[3], 0.7),
        CreateColor(C.primary[1]*0.18, C.primary[2]*0.18, C.primary[3]*0.18, 0))
    return lbl
end

local function HRule(parent, anchor, yOfs)
    local t = Tex(parent, "BACKGROUND")
    t:SetHeight(1)
    t:SetPoint("TOPLEFT",  anchor or parent, "TOPLEFT",  0, yOfs or 0)
    t:SetPoint("TOPRIGHT", parent,           "TOPRIGHT", 0, yOfs or 0)
    t:SetColorTexture(unpack(C.separator))
    return t
end

-- ============================================================
-- STYLED BUTTON
-- ============================================================
local function StyledButton(parent, text, w, h, onClick)
    local btn = CreateFrame("Button", nil, parent, "BackdropTemplate")
    btn:SetSize(w or 110, h or 26)
    btn:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
        tile=false, edgeSize=1, insets={left=0,right=0,top=0,bottom=0}})
    btn:SetBackdropColor(
        math.min(1, C.primary[1]*0.26+0.05), math.min(1, C.primary[2]*0.26+0.05), math.min(1, C.primary[3]*0.26+0.05), 1)
    btn:SetBackdropBorderColor(
        math.min(1, C.primary[1]*0.52+0.10), math.min(1, C.primary[2]*0.52+0.10), math.min(1, C.primary[3]*0.52+0.10), 1)
    local lbl = FS(btn)
    lbl:SetPoint("CENTER")
    lbl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 1)
    lbl:SetText(text)
    btn:SetScript("OnEnter", function(s)
        s:SetBackdropColor(
            math.min(1, C.primary[1]*0.40+0.06), math.min(1, C.primary[2]*0.40+0.06), math.min(1, C.primary[3]*0.40+0.06), 1)
        s:SetBackdropBorderColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
        lbl:SetTextColor(1, 1, 1, 1)
    end)
    btn:SetScript("OnLeave", function(s)
        s:SetBackdropColor(
            math.min(1, C.primary[1]*0.26+0.05), math.min(1, C.primary[2]*0.26+0.05), math.min(1, C.primary[3]*0.26+0.05), 1)
        s:SetBackdropBorderColor(
            math.min(1, C.primary[1]*0.52+0.10), math.min(1, C.primary[2]*0.52+0.10), math.min(1, C.primary[3]*0.52+0.10), 1)
        lbl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 1)
    end)
    btn:SetScript("OnClick", onClick)
    return btn, lbl
end

-- ============================================================
-- MODERNER TOGGLE-SWITCH
-- ============================================================
local allToggles = {}
local allSliders = {}
local widthMiscRows = {}
local rChatDdRows = {}
local TOGGLE_W = 40
local TOGGLE_H = 20
local KNOB_SZ  = 14

-- Forward declaration für Dialoge
local ShowReloadDialog

local function ModernToggle(parent, label, desc, anchor, yOfs, getter, setter, reloadOnChange)
    local rowH = desc and 52 or 34
    local con  = CreateFrame("Frame", nil, parent)
    con:SetSize(CW() - 20, rowH)
    con:SetPoint("TOPLEFT", anchor or parent, "TOPLEFT", 0, yOfs or 0)

    local track = CreateFrame("Button", nil, con, "BackdropTemplate")
    track:SetSize(TOGGLE_W, TOGGLE_H)
    track:SetPoint("LEFT", con, "LEFT", 0, desc and 9 or 0)
    track:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
        tile=false, edgeSize=1, insets={left=0,right=0,top=0,bottom=0}})

    local knob = CreateFrame("Frame", nil, track, "BackdropTemplate")
    knob:SetSize(KNOB_SZ, KNOB_SZ)
    knob:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
        tile=false, edgeSize=1, insets={left=0,right=0,top=0,bottom=0}})

    local lbl = FS(con)
    lbl:SetPoint("LEFT", track, "RIGHT", 10, desc and 9 or 0)
    lbl:SetPoint("RIGHT", con, "RIGHT", -4, 0)
    lbl:SetJustifyH("LEFT")
    lbl:SetTextColor(unpack(C.text))
    lbl:SetText(label)

    if desc then
        local d = FS(con, "GameFontHighlightSmall")
        d:SetPoint("TOPLEFT", lbl, "BOTTOMLEFT", 0, -3)
        d:SetPoint("RIGHT", con, "RIGHT", -4, 0)
        d:SetJustifyH("LEFT")
        d:SetTextColor(unpack(C.textDim))
        d:SetText(desc)
    end

    local function SetVisual(on)
        if on then
            track:SetBackdropColor(C.primary[1], C.primary[2], C.primary[3], 1)
            track:SetBackdropBorderColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
            knob:ClearAllPoints()
            knob:SetPoint("RIGHT", track, "RIGHT", -3, 0)
            knob:SetBackdropColor(1, 1, 1, 1)
            knob:SetBackdropBorderColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
            lbl:SetTextColor(unpack(C.textBright))
        else
            track:SetBackdropColor(C.toggleOff[1], C.toggleOff[2], C.toggleOff[3], 1)
            track:SetBackdropBorderColor(C.border[1], C.border[2], C.border[3], 1)
            knob:ClearAllPoints()
            knob:SetPoint("LEFT", track, "LEFT", 3, 0)
            knob:SetBackdropColor(0.48, 0.40, 0.40, 1)
            knob:SetBackdropBorderColor(0.28, 0.22, 0.22, 1)
            lbl:SetTextColor(unpack(C.text))
        end
    end

    local function Refresh()
        local v = getter()
        SetVisual(v == true or v == 1)
    end
    Refresh()

    track:SetScript("OnEnter", function()
        local on = (getter() == true or getter() == 1)
        if on then track:SetBackdropBorderColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
        else track:SetBackdropBorderColor(
            math.min(1, C.primary[1]*0.48+0.10), math.min(1, C.primary[2]*0.48+0.10), math.min(1, C.primary[3]*0.48+0.10), 1) end
    end)
    track:SetScript("OnLeave", function()
        local on = (getter() == true or getter() == 1)
        if on then track:SetBackdropBorderColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
        else track:SetBackdropBorderColor(C.border[1], C.border[2], C.border[3], 1) end
    end)
    track:SetScript("OnClick", function()
        local newVal = not (getter() == true or getter() == 1)
        SetVisual(newVal)
        setter(newVal)
        if reloadOnChange then
            ShowReloadDialog(
                L.Strings["RELOAD_REQUIRED_INFO"] or "This change requires a UI reload to take effect."
            )
        end
    end)

    con.Refresh = Refresh
    tinsert(allToggles, con)
    return con
end

-- ============================================================
-- MODERNER SLIDER
-- ============================================================
local function ModernSlider(parent, label, desc, minV, maxV, step, anchor, yOfs, getter, setter, fmt, reload)
    local rowH = desc and 68 or 58
    local con  = CreateFrame("Frame", nil, parent)
    con:SetSize(CW() - 20, rowH)
    con:SetPoint("TOPLEFT", anchor or parent, "TOPLEFT", 0, yOfs or 0)

    local lbl = FS(con); lbl:SetPoint("TOPLEFT", 0, 0)
    lbl:SetTextColor(unpack(C.text)); lbl:SetText(label)
    local valLbl = FS(con, "GameFontNormalSmall")
    valLbl:SetPoint("TOPRIGHT", 0, -1)
    valLbl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 1)

    if desc then
        local d = FS(con, "GameFontHighlightSmall")
        d:SetPoint("TOPLEFT", lbl, "BOTTOMLEFT", 0, -1)
        d:SetTextColor(unpack(C.textDim)); d:SetText(desc)
    end

    local track = Tex(con, "BACKGROUND"); track:SetHeight(3)
    track:SetPoint("BOTTOMLEFT",  con, "BOTTOMLEFT",   6, 14)
    track:SetPoint("BOTTOMRIGHT", con, "BOTTOMRIGHT", -6, 14)
    track:SetColorTexture(
        math.min(1, C.primary[1]*0.14+0.08), math.min(1, C.primary[2]*0.14+0.08), math.min(1, C.primary[3]*0.14+0.08), 1)
    local fill = Tex(con, "ARTWORK"); fill:SetHeight(3)
    fill:SetPoint("LEFT", track, "LEFT", 0, 0)
    fill:SetColorTexture(C.primary[1], C.primary[2], C.primary[3], 0.85)

    local sl = CreateFrame("Slider", nil, con)
    sl:SetHeight(18)
    sl:SetPoint("LEFT",  track, "LEFT",  0, 0)
    sl:SetPoint("RIGHT", track, "RIGHT", 0, 0)
    sl:SetMinMaxValues(minV, maxV); sl:SetValueStep(step)
    sl:SetObeyStepOnDrag(true); sl:SetValue(getter())
    sl:SetOrientation("HORIZONTAL")
    local thumb = Tex(sl, "OVERLAY"); thumb:SetSize(10, 14)
    thumb:SetTexture("Interface\\Buttons\\WHITE8X8")
    thumb:SetVertexColor(C.primary[1], C.primary[2], C.primary[3], 1)
    sl:SetThumbTexture(thumb)

    local userChanged = false
    local prog = false
    local function UpdateFill()
        local pct = math.max(0, (sl:GetValue()-minV)/math.max(maxV-minV, 0.001))
        local w = track:GetWidth(); if w and w > 0 then fill:SetWidth(w*pct) end
    end
    local function UpdateVal()
        local v = sl:GetValue()
        valLbl:SetText(fmt and fmt(v) or string.format("%.1f", v))
        UpdateFill()
        if not prog then setter(v) end
        if not prog and reload then userChanged = true end
    end
    sl:SetScript("OnValueChanged", UpdateVal)
    sl:SetScript("OnSizeChanged",  UpdateFill)
    sl:SetScript("OnMouseUp", function()
        if userChanged and reload then
            ShowReloadDialog(
                L.Strings["RELOAD_REQUIRED_INFO"] or "This change requires a UI reload to take effect."
            )
            userChanged = false
        end
    end)
    sl:SetScript("OnEnter", function() thumb:SetVertexColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1) end)
    sl:SetScript("OnLeave", function() thumb:SetVertexColor(C.primary[1],   C.primary[2],   C.primary[3],   1) end)
    prog = true; sl:SetValue(getter()); prog = false
    UpdateVal()
    con.slider  = sl
    con.Refresh = function() prog=true; sl:SetValue(getter()); prog=false; UpdateVal() end
    tinsert(allSliders, con)
    return con
end

-- ============================================================
-- MODERNER DROPDOWN
-- ============================================================
local MAX_VISIBLE_ITEMS = 8
local ITEM_H = 22

local function ModernDropdown(parent, w, anchor, yOfs, getOptions, getter, setter, onChange)
    local h = 26
    local con = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    con:SetSize(w or 200, h)
    con:SetPoint("TOPLEFT", anchor or parent, "TOPLEFT", 0, yOfs or 0)
    con:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
        tile=false, edgeSize=1, insets={left=0,right=0,top=0,bottom=0}})
    con:SetBackdropColor(C.toggleOff[1], C.toggleOff[2], C.toggleOff[3], 1)
    con:SetBackdropBorderColor(C.border[1], C.border[2], C.border[3], 1)

    local currLbl = FS(con, "GameFontNormalSmall")
    currLbl:SetPoint("LEFT", 8, 0)
    currLbl:SetPoint("RIGHT", con, "RIGHT", -20, 0)
    currLbl:SetJustifyH("LEFT")
    currLbl:SetTextColor(unpack(C.text))

    local arrow = FS(con, "GameFontNormalSmall")
    arrow:SetPoint("RIGHT", -6, 0)
    arrow:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
    arrow:SetText("v")

    local function Refresh()
        local cur = getter()
        local opts = getOptions()
        for _, o in ipairs(opts) do
            if o.key == cur then currLbl:SetText(o.label); return end
        end
        currLbl:SetText(cur or "")
    end
    Refresh()

    local btn = CreateFrame("Button", nil, con)
    btn:SetAllPoints()
    btn:SetScript("OnEnter", function()
        con:SetBackdropBorderColor(
            math.min(1, C.primary[1]*0.48+0.10), math.min(1, C.primary[2]*0.48+0.10), math.min(1, C.primary[3]*0.48+0.10), 1)
        currLbl:SetTextColor(unpack(C.textBright))
    end)
    btn:SetScript("OnLeave", function()
        con:SetBackdropBorderColor(C.border[1], C.border[2], C.border[3], 1)
        currLbl:SetTextColor(unpack(C.text))
    end)

    btn:SetScript("OnClick", function()
        local opts    = getOptions()
        local numOpts = #opts
        local visible = math.min(numOpts, MAX_VISIBLE_ITEMS)
        local popupW  = (w or 200)
        local popupH  = visible * ITEM_H + 4

        local popup = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
        popup:SetSize(popupW, popupH)
        popup:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
            tile=false, edgeSize=1, insets={left=0,right=0,top=0,bottom=0}})
        popup:SetBackdropColor(0.06, 0.050, 0.050, 1)
        popup:SetBackdropBorderColor(
            math.min(1, C.primary[1]*0.52+0.10), math.min(1, C.primary[2]*0.52+0.10), math.min(1, C.primary[3]*0.52+0.10), 1)
        popup:SetFrameStrata("TOOLTIP"); popup:SetFrameLevel(200)
        popup:SetClampedToScreen(true)
        popup:EnableMouseWheel(true)
        popup:SetScript("OnMouseWheel", function(self)
            self:Hide()
        end)

        local cx = con:GetLeft() or 0
        local cy = con:GetBottom() or 0
        popup:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", cx, cy)

        local sf = CreateFrame("ScrollFrame", nil, popup)
        sf:SetPoint("TOPLEFT",     popup, "TOPLEFT",     2, -2)
        sf:SetPoint("BOTTOMRIGHT", popup, "BOTTOMRIGHT", -2, 2)
        local child = CreateFrame("Frame", nil, sf)
        child:SetWidth(popupW - 4)
        child:SetHeight(numOpts * ITEM_H)
        sf:SetScrollChild(child)

        local curVal = getter()
        for i, opt in ipairs(opts) do
            local row = CreateFrame("Button", nil, child, "BackdropTemplate")
            row:SetSize(popupW - 4, ITEM_H)
            row:SetPoint("TOPLEFT", child, "TOPLEFT", 0, -(i-1)*ITEM_H)
            row:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeSize=0,
                insets={left=0,right=0,top=0,bottom=0}})
            row:SetBackdropColor(0, 0, 0, 0)
            local rl = FS(row, "GameFontNormalSmall")
            rl:SetPoint("LEFT", 8, 0)
            local isCur = (opt.key == curVal)
            rl:SetTextColor(isCur and C.primary[1] or C.text[1],
                            isCur and C.primary[2] or C.text[2],
                            isCur and C.primary[3] or C.text[3], 1)
            rl:SetText(opt.label)
            row:SetScript("OnEnter", function()
                row:SetBackdropColor(
                    math.min(1, C.primary[1]*0.28+0.06), math.min(1, C.primary[2]*0.28+0.06), math.min(1, C.primary[3]*0.28+0.06), 1)
                rl:SetTextColor(1, 1, 1, 1)
            end)
            row:SetScript("OnLeave", function()
                row:SetBackdropColor(0, 0, 0, 0)
                local isCurNow = (opt.key == getter())
                rl:SetTextColor(isCurNow and C.primary[1] or C.text[1],
                                isCurNow and C.primary[2] or C.text[2],
                                isCurNow and C.primary[3] or C.text[3], 1)
            end)
            row:SetScript("OnClick", function()
                setter(opt.key)
                if onChange then onChange(opt.key) end
                Refresh(); popup:Hide()
            end)
        end

        local closer = CreateFrame("Frame", nil, UIParent)
        closer:SetAllPoints(); closer:SetFrameStrata("DIALOG"); closer:SetFrameLevel(199)
        closer:EnableMouse(true)
        closer:EnableMouseWheel(true)
        closer:SetScript("OnMouseDown", function() popup:Hide(); closer:Hide() end)
        closer:SetScript("OnMouseWheel", function() popup:Hide(); closer:Hide() end)
        popup:SetScript("OnHide", function() closer:Hide() end)
        popup:Show()
    end)

    con.Refresh = Refresh
    local wCap = w or 200
    function con:ApplyRChatDdLayout()
        local Wn = math.max(100, math.min(wCap, CW() - 30))
        self:SetSize(Wn, h)
    end
    tinsert(rChatDdRows, con)
    return con
end

-- ============================================================
-- FRAME FADE
-- ============================================================
local CFG_IN  = 0.16
local CFG_OUT = 0.20

local function ConfigFadeIn(f)
    f:SetAlpha(0); f:Show()
    UIFrameFadeIn(f, CFG_IN, 0, 1)
end

local function ConfigFadeOut(f)
    UIFrameFadeOut(f, CFG_OUT, f:GetAlpha(), 0)
    local elapsed = 0
    local ticker
    ticker = C_Timer.NewTicker(0.05, function()
        elapsed = elapsed + 0.05
        if elapsed >= CFG_OUT then f:Hide(); f:SetAlpha(1); ticker:Cancel() end
    end)
end

-- ============================================================
-- MODERNER RELOAD-DIALOG (rChat-Stil, rot)
-- ============================================================
local reloadDialog
local currentCancelCallback = nil

-- Hilfsfunktion: alle Toggles im configFrame refreshen
local function RefreshAllToggles()
    for _, t in ipairs(allToggles) do
        if t.Refresh then t:Refresh() end
    end
end

ShowReloadDialog = function(infoText, cancelCallback)
    if rChatGuiTheme and rChatGuiTheme.ApplyPalette then
        rChatGuiTheme.ApplyPalette(C)
    end
    -- Dialog einmal erstellen und wiederverwenden
    if not reloadDialog then
        local dlg = CreateFrame("Frame", "rChatReloadDialog", UIParent, "BackdropTemplate")
        dlg:SetSize(400, 195)
        dlg:SetPoint("CENTER")
        dlg:SetFrameStrata("FULLSCREEN_DIALOG")
        dlg:SetFrameLevel(200)
        dlg:SetClampedToScreen(true)
        dlg:SetMovable(true)
        dlg:EnableMouse(true)
        dlg:RegisterForDrag("LeftButton")
        dlg:SetScript("OnDragStart", dlg.StartMoving)
        dlg:SetScript("OnDragStop",  dlg.StopMovingOrSizing)
        dlg:SetBackdrop({
            bgFile   = "Interface\\Buttons\\WHITE8X8",
            edgeFile = "Interface\\Buttons\\WHITE8X8",
            tile = false, edgeSize = 2,
            insets = {left=0, right=0, top=0, bottom=0}
        })
        dlg:SetBackdropColor(C.bg[1], C.bg[2], C.bg[3], C.bg[4])
        dlg:SetBackdropBorderColor(
            math.min(1, C.primary[1] * 0.52 + 0.06),
            math.min(1, C.primary[2] * 0.52 + 0.06),
            math.min(1, C.primary[3] * 0.52 + 0.06), 1)

        -- ── Titelleiste ──────────────────────────────────────────────────
        local titleBar = CreateFrame("Frame", nil, dlg, "BackdropTemplate")
        titleBar:SetPoint("TOPLEFT",  dlg, "TOPLEFT",   2, -2)
        titleBar:SetPoint("TOPRIGHT", dlg, "TOPRIGHT",  -2, -2)
        titleBar:SetHeight(42)
        titleBar:SetBackdrop({
            bgFile   = "Interface\\Buttons\\WHITE8X8",
            edgeFile = "Interface\\Buttons\\WHITE8X8",
            tile = false, edgeSize = 1,
            insets = {left=0, right=0, top=0, bottom=0}
        })
        titleBar:SetBackdropColor(
            math.min(1, C.primary[1]*0.26+0.05), math.min(1, C.primary[2]*0.26+0.05), math.min(1, C.primary[3]*0.26+0.05), 1)
        titleBar:SetBackdropBorderColor(
            math.min(1, C.primary[1]*0.52+0.10), math.min(1, C.primary[2]*0.52+0.10), math.min(1, C.primary[3]*0.52+0.10), 1)

        -- Linker Akzentstreifen
        local accent = titleBar:CreateTexture(nil, "OVERLAY")
        accent:SetWidth(3)
        accent:SetPoint("TOPLEFT",    titleBar, "TOPLEFT",    0, 0)
        accent:SetPoint("BOTTOMLEFT", titleBar, "BOTTOMLEFT", 0, 0)
        accent:SetColorTexture(C.primary[1], C.primary[2], C.primary[3], 1)

        -- Titel-Icon (Logo)
        local titleIcon = titleBar:CreateTexture(nil, "OVERLAY")
        titleIcon:SetSize(22, 22)
        titleIcon:SetPoint("LEFT", titleBar, "LEFT", 12, 0)
        titleIcon:SetTexture(LOGO_PATH)

        -- Titel-Text
        dlg.titleLbl = titleBar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        dlg.titleLbl:SetPoint("LEFT", titleIcon, "RIGHT", 8, 0)
        dlg.titleLbl:SetTextColor(1, 1, 1, 1)

        -- Unterer Gradient-Streifen der Titelleiste
        local tgl = titleBar:CreateTexture(nil, "OVERLAY")
        tgl:SetHeight(2)
        tgl:SetPoint("BOTTOMLEFT",  titleBar, "BOTTOMLEFT",  0, 0)
        tgl:SetPoint("BOTTOMRIGHT", titleBar, "BOTTOMRIGHT", 0, 0)
        tgl:SetGradient("HORIZONTAL",
            CreateColor(C.primary[1], C.primary[2], C.primary[3], 1),
            CreateColor(C.primary[1]*0.22, C.primary[2]*0.22, C.primary[3]*0.22, 0))

        -- ── Logo (unter Titelleiste, links) ──────────────────────────────
        local iconTex = dlg:CreateTexture(nil, "ARTWORK")
        iconTex:SetSize(38, 38)
        iconTex:SetPoint("TOPLEFT", titleBar, "BOTTOMLEFT", 14, -13)
        iconTex:SetTexture(LOGO_PATH)
        iconTex:SetVertexColor(C.primary[1], C.primary[2], C.primary[3], 0.75)

        -- ── Info-Text ────────────────────────────────────────────────────
        dlg.infoLbl = dlg:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        dlg.infoLbl:SetPoint("TOPLEFT",  iconTex, "TOPRIGHT",  10, -2)
        dlg.infoLbl:SetPoint("TOPRIGHT", dlg,     "TOPRIGHT",  -18, -58)
        dlg.infoLbl:SetJustifyH("LEFT")
        dlg.infoLbl:SetTextColor(C.text[1], C.text[2], C.text[3], 1)
        dlg.infoLbl:SetWordWrap(true)

        -- ── Trennlinie ───────────────────────────────────────────────────
        local sep = dlg:CreateTexture(nil, "BACKGROUND")
        sep:SetHeight(1)
        sep:SetPoint("TOPLEFT",  dlg, "TOPLEFT",  18, -112)
        sep:SetPoint("TOPRIGHT", dlg, "TOPRIGHT", -18, -112)
        sep:SetColorTexture(C.primary[1], C.primary[2], C.primary[3], 0.20)

        -- ── Button-Hilfsfunktion ─────────────────────────────────────────
        local function MakeBtn(parent, w, h, isPrimary, onClick)
            local b = CreateFrame("Button", nil, parent, "BackdropTemplate")
            b:SetSize(w, h)
            b:SetBackdrop({
                bgFile   = "Interface\\Buttons\\WHITE8X8",
                edgeFile = "Interface\\Buttons\\WHITE8X8",
                tile = false, edgeSize = 1,
                insets = {left=0, right=0, top=0, bottom=0}
            })
            if isPrimary then
                b:SetBackdropColor(
                    math.min(1, C.primary[1]*0.30+0.06), math.min(1, C.primary[2]*0.30+0.06), math.min(1, C.primary[3]*0.30+0.06), 1)
                b:SetBackdropBorderColor(
                    math.min(1, C.primary[1]*0.58+0.10), math.min(1, C.primary[2]*0.58+0.10), math.min(1, C.primary[3]*0.58+0.10), 1)
            else
                b:SetBackdropColor(0.08, 0.06, 0.06, 1)
                b:SetBackdropBorderColor(0.28, 0.16, 0.16, 1)
            end
            local bl = b:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            bl:SetPoint("CENTER")
            if isPrimary then
                bl:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
            else
                bl:SetTextColor(0.65, 0.55, 0.55, 1)
            end
            b:SetScript("OnEnter", function(s)
                if isPrimary then
                    s:SetBackdropColor(
                        math.min(1, C.primary[1]*0.44+0.08), math.min(1, C.primary[2]*0.44+0.08), math.min(1, C.primary[3]*0.44+0.08), 1)
                    s:SetBackdropBorderColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
                else
                    s:SetBackdropColor(0.14, 0.10, 0.10, 1)
                    s:SetBackdropBorderColor(0.50, 0.28, 0.28, 1)
                end
                bl:SetTextColor(1, 1, 1, 1)
            end)
            b:SetScript("OnLeave", function(s)
                if isPrimary then
                    s:SetBackdropColor(
                        math.min(1, C.primary[1]*0.30+0.06), math.min(1, C.primary[2]*0.30+0.06), math.min(1, C.primary[3]*0.30+0.06), 1)
                    s:SetBackdropBorderColor(
                        math.min(1, C.primary[1]*0.58+0.10), math.min(1, C.primary[2]*0.58+0.10), math.min(1, C.primary[3]*0.58+0.10), 1)
                    bl:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
                else
                    s:SetBackdropColor(0.08, 0.06, 0.06, 1)
                    s:SetBackdropBorderColor(0.28, 0.16, 0.16, 1)
                    bl:SetTextColor(0.65, 0.55, 0.55, 1)
                end
            end)
            b:SetScript("OnClick", onClick)
            b.label = bl
            return b
        end

        -- ── Reload-Button (primär, rechts) ───────────────────────────────
        dlg.reloadBtn = MakeBtn(dlg, 140, 30, true, function()
            ReloadUI()
        end)
        dlg.reloadBtn:SetPoint("BOTTOMRIGHT", dlg, "BOTTOMRIGHT", -16, 14)

        -- ── Cancel-Button (sekundär, links vom Reload) ────────────────────
        dlg.cancelBtn = MakeBtn(dlg, 120, 30, false, function()
            if currentCancelCallback then currentCancelCallback() end
            currentCancelCallback = nil
            dlg:Hide()
        end)
        dlg.cancelBtn:SetPoint("RIGHT", dlg.reloadBtn, "LEFT", -10, 0)

        reloadDialog = dlg
    end

    -- Texte setzen (bei jedem Aufruf, wegen Sprachunterstützung)
    reloadDialog.titleLbl:SetText(L.Strings["RELOAD_REQUIRED_TITLE"] or "Reload Required")
    reloadDialog.infoLbl:SetText(infoText or (L.Strings["RELOAD_REQUIRED_INFO"] or "This change requires a UI reload to take effect."))
    reloadDialog.reloadBtn.label:SetText(L.Strings["GUI_RELOAD_BUTTON"] or "Reload UI")
    reloadDialog.cancelBtn.label:SetText(L.Strings["GUI_NO"] or "Cancel")

    currentCancelCallback = cancelCallback

    -- Zentriert anzeigen (falls vorher verschoben)
    reloadDialog:ClearAllPoints()
    reloadDialog:SetPoint("CENTER")
    reloadDialog:Show()
    reloadDialog:Raise()
end

-- Minimap-spezifischer Wrapper mit Revert-Cancel
local function ShowMinimapReloadDialog(pendingHide)
    local function revert()
        -- Config zurückdrehen
        if rChatDB and rChatDB.minimap then
            rChatDB.minimap.hide = not pendingHide
        end
        -- Alle Toggles im GUI aktualisieren
        RefreshAllToggles()
        if configFrame and configFrame.RefreshAllControls then
            configFrame:RefreshAllControls()
        end
    end
    ShowReloadDialog(
        L.Strings["MINIMAP_RELOAD_INFO"] or "Changing the minimap icon visibility requires a UI reload.",
        revert
    )
end

-- Öffentliche Funktionen für core.lua zugänglich machen
L.ShowReloadDialog = ShowReloadDialog
L.ShowMinimapReloadDialog = ShowMinimapReloadDialog

-- ============================================================
-- SCROLL HELPER (modern: schlanke Spur, Thumb ziehbar + Track-Klick)
-- ============================================================
local function MakeScroll(parent)
    -- Container-Frame: koppelt ScrollFrame + Track als eine Einheit
    local container = CreateFrame("Frame", nil, parent)
    container:SetPoint("TOPLEFT",     parent, "TOPLEFT",      0, -40)
    container:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT",  0,  4)

    local sf = CreateFrame("ScrollFrame", nil, container)
    sf:SetPoint("TOPLEFT",     container, "TOPLEFT",      2,  0)
    sf:SetPoint("BOTTOMRIGHT", container, "BOTTOMRIGHT", -12, 0)

    local sc = CreateFrame("Frame", nil, sf)
    local function SyncScrollChildWidth()
        local w = sf:GetWidth()
        if w and w > 40 then sc:SetWidth(math.max(100, w - 4)) end
    end
    sc:SetWidth(math.max(100, CW() - 30))
    sf:SetScrollChild(sc)

    -- Schlanke Scrollspur (8 px) – Kind von container, nicht von parent!
    local TRACK_W = 8
    local track = CreateFrame("Frame", nil, container, "BackdropTemplate")
    track:SetWidth(TRACK_W)
    track:SetPoint("TOPRIGHT",    container, "TOPRIGHT",    -2,  0)
    track:SetPoint("BOTTOMRIGHT", container, "BOTTOMRIGHT", -2,  0)
    track:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeSize=0,
        insets={left=0,right=0,top=0,bottom=0}})
    track:SetBackdropColor(
        math.min(1, 0.08 + C.primary[1]*0.05), math.min(1, 0.08 + C.primary[2]*0.05), math.min(1, 0.08 + C.primary[3]*0.05), 1)

    local function ScrollThumbBase()
        local pr, pg, pb = C.primary[1], C.primary[2], C.primary[3]
        return math.min(1, pr*0.5+0.10), math.min(1, pg*0.5+0.10), math.min(1, pb*0.5+0.10)
    end
    local function ScrollThumbBorder()
        local pr, pg, pb = C.primary[1], C.primary[2], C.primary[3]
        return math.min(1, pr*0.62+0.06), math.min(1, pg*0.62+0.06), math.min(1, pb*0.62+0.06)
    end

    -- Thumb
    local thumb = CreateFrame("Button", nil, track, "BackdropTemplate")
    thumb:SetWidth(TRACK_W)
    thumb:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8",
        edgeFile="Interface\\Buttons\\WHITE8X8",
        edgeSize=1, insets={left=0,right=0,top=0,bottom=0}})
    do
        local tr, tg, tb = ScrollThumbBase()
        thumb:SetBackdropColor(tr, tg, tb, 1)
        local br, bg_, bb = ScrollThumbBorder()
        thumb:SetBackdropBorderColor(br, bg_, bb, 1)
    end
    thumb:SetPoint("TOPLEFT", track, "TOPLEFT", 0, 0)

    -- Thumb-Position berechnen und setzen
    local function UpdateThumb()
        local trackH  = track:GetHeight()
        if not trackH or trackH <= 0 then return end
        local viewH    = sf:GetHeight()
        local contentH = sc:GetHeight()
        if contentH <= viewH then thumb:Hide(); return end
        thumb:Show()
        local ratio   = viewH / contentH
        local thumbH  = math.max(20, trackH * ratio)
        thumb:SetHeight(thumbH)
        local maxScroll = contentH - viewH
        local cur     = sf:GetVerticalScroll()
        local pct     = maxScroll > 0 and (cur / maxScroll) or 0
        local maxY    = trackH - thumbH
        thumb:ClearAllPoints()
        thumb:SetPoint("TOPLEFT", track, "TOPLEFT", 0, -(pct * maxY))
    end

    -- ── Mausrad ──────────────────────────────────────────────────────────
    sf:EnableMouseWheel(true)
    sf:SetScript("OnMouseWheel", function(self, d)
        local viewH    = self:GetHeight()
        local contentH = sc:GetHeight()
        local maxScroll = math.max(0, contentH - viewH)
        local cur = self:GetVerticalScroll()
        self:SetVerticalScroll(math.max(0, math.min(maxScroll, cur - d * 30)))
        UpdateThumb()
    end)

    -- ── Thumb per Maus ziehen ─────────────────────────────────────────────
    local dragStartY, dragStartScroll
    thumb:EnableMouse(true)
    thumb:SetScript("OnMouseDown", function(self, btn)
        if btn ~= "LeftButton" then return end
        local _, my = GetCursorPosition()
        local scale = UIParent:GetEffectiveScale()
        dragStartY      = my / scale
        dragStartScroll = sf:GetVerticalScroll()
        self:SetScript("OnUpdate", function()
            local _, cy = GetCursorPosition()
            cy = cy / scale
            local delta     = dragStartY - cy
            local trackH    = track:GetHeight()
            local viewH     = sf:GetHeight()
            local contentH  = sc:GetHeight()
            local maxScroll = math.max(0, contentH - viewH)
            local thumbH    = self:GetHeight()
            local maxY      = trackH - thumbH
            if maxY <= 0 then return end
            local scrollDelta = (delta / maxY) * maxScroll
            sf:SetVerticalScroll(math.max(0, math.min(maxScroll, dragStartScroll + scrollDelta)))
            UpdateThumb()
        end)
    end)
    thumb:SetScript("OnMouseUp", function(self)
        self:SetScript("OnUpdate", nil)
    end)
    thumb:SetScript("OnEnter", function(self)
        self:SetBackdropColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
        self:SetBackdropBorderColor(1, 1, 1, 0.35)
    end)
    thumb:SetScript("OnLeave", function(self)
        local tr, tg, tb = ScrollThumbBase()
        self:SetBackdropColor(tr, tg, tb, 1)
        local br, bg_, bb = ScrollThumbBorder()
        self:SetBackdropBorderColor(br, bg_, bb, 1)
    end)

    -- ── Klick auf Spur (Sprung zur angeklickten Stelle) ───────────────────
    track:EnableMouse(true)
    track:SetScript("OnMouseDown", function(self, btn)
        if btn ~= "LeftButton" then return end
        local _, my = GetCursorPosition()
        my = my / UIParent:GetEffectiveScale()
        local trackH    = self:GetHeight()
        local viewH     = sf:GetHeight()
        local contentH  = sc:GetHeight()
        local maxScroll = math.max(0, contentH - viewH)
        local cx, cy    = self:GetCenter()
        local trackTop  = (cy or 0) + trackH / 2
        local relY      = trackTop - my
        local pct       = math.max(0, math.min(1, relY / trackH))
        sf:SetVerticalScroll(pct * maxScroll)
        UpdateThumb()
    end)

    sf:SetScript("OnScrollRangeChanged", function() UpdateThumb() end)
    sc:SetScript("OnSizeChanged",        function() UpdateThumb() end)
    sf:SetScript("OnSizeChanged",        function() SyncScrollChildWidth(); UpdateThumb() end)
    container:SetScript("OnSizeChanged", function() SyncScrollChildWidth(); UpdateThumb() end)

    container.sf = sf
    container.sc = sc
    container.UpdateThumb = UpdateThumb
    -- container zurückgeben; sf und sc wie bisher nutzbar
    return container, sf, sc
end

-- ============================================================
-- HAUPT-FRAME AUFBAUEN
-- ============================================================
local function BuildConfigFrame()
    if configFrame then return configFrame end

    if rChatGuiTheme and rChatGuiTheme.ApplyPalette then
        rChatGuiTheme.ApplyPalette(C)
    end

    if not rChatDB then rChatDB = {} end
    if rChatDB.guiFrameW and rChatDB.guiFrameH then
        FRAME_W = rChatDB.guiFrameW
        FRAME_H = rChatDB.guiFrameH
    else
        FRAME_W, FRAME_H = FRAME_W_DEFAULT, FRAME_H_DEFAULT
    end

    local frame = CreateFrame("Frame", "rChatConfigFrame", UIParent, "BackdropTemplate")
    frame:SetSize(FRAME_W, FRAME_H)
    frame:SetPoint("CENTER")
    frame:SetMovable(true); frame:EnableMouse(true)
    frame:SetFrameStrata("DIALOG"); frame:SetClampedToScreen(true); frame:Hide()
    tinsert(UISpecialFrames, "rChatConfigFrame")
    frame:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
        tile=false, edgeSize=2, insets={left=0,right=0,top=0,bottom=0}})
    frame:SetBackdropColor(unpack(C.bg))
    frame:SetBackdropBorderColor(
        math.min(1, C.primary[1] * 0.52 + 0.06),
        math.min(1, C.primary[2] * 0.52 + 0.06),
        math.min(1, C.primary[3] * 0.52 + 0.06), 1)

    frame:SetScript("OnShow", function(self)
        for _, t in ipairs(allToggles) do if t.Refresh then t:Refresh() end end
    end)

    -- RefreshAllControls: alle Toggles neu zeichnen
    function frame:RefreshAllControls()
        for _, t in ipairs(allToggles) do if t.Refresh then t:Refresh() end end
        if self.SyncScale then self:SyncScale() end
    end

    -- ── TITELLEISTE ────────────────────────────────────────
    local titleBg = FlatFrame(frame,
        C.primary[1]*0.22, C.primary[2]*0.18, C.primary[3]*0.18, 1,
        C.primary[1]*0.50, C.primary[2]*0.38, C.primary[3]*0.36, 1)
    titleBg:SetPoint("TOPLEFT",  frame, "TOPLEFT",   2, -2)
    titleBg:SetPoint("TOPRIGHT", frame, "TOPRIGHT",  -2, -2)
    titleBg:SetHeight(TITLE_H)

    local ta = Tex(titleBg); ta:SetWidth(3)
    ta:SetPoint("TOPLEFT",    titleBg, "TOPLEFT",    0, 0)
    ta:SetPoint("BOTTOMLEFT", titleBg, "BOTTOMLEFT", 0, 0)
    ta:SetColorTexture(C.primary[1], C.primary[2], C.primary[3], 1)

    local logoTex = Tex(titleBg, "ARTWORK")
    logoTex:SetTexture(LOGO_PATH)
    logoTex:SetSize(36, 36)
    logoTex:SetPoint("LEFT", titleBg, "LEFT", 12, 0)

    local titleLbl = FS(titleBg, "GameFontNormalHuge")
    titleLbl:SetPoint("LEFT", logoTex, "RIGHT", 8, 1)
    titleLbl:SetTextColor(1, 1, 1, 1)
    local titleHex = (rChatGuiTheme and rChatGuiTheme.RGBToWoWColorHex)
        and rChatGuiTheme.RGBToWoWColorHex(C.primary[1], C.primary[2], C.primary[3])
        or "af1917"
    titleLbl:SetText("|cff" .. titleHex .. "r|rChat")
    AttachGuiTitleVersion(titleBg, titleLbl, "rChat", C.textDim[1], C.textDim[2], C.textDim[3])

    local tgl = Tex(titleBg)
    tgl:SetHeight(2)
    tgl:SetPoint("BOTTOMLEFT",  titleBg, "BOTTOMLEFT",  0, 0)
    tgl:SetPoint("BOTTOMRIGHT", titleBg, "BOTTOMRIGHT", 0, 0)
    tgl:SetGradient("HORIZONTAL",
        CreateColor(C.primary[1], C.primary[2], C.primary[3], 1),
        CreateColor(C.primary[1]*0.22, C.primary[2]*0.22, C.primary[3]*0.22, 0))

    local closeBtn = CreateFrame("Button", nil, titleBg)
    closeBtn:SetSize(28, 28)
    closeBtn:SetPoint("RIGHT", titleBg, "RIGHT", -12, 0)
    closeBtn:SetFrameLevel(titleBg:GetFrameLevel() + 5)
    local closeBg = Tex(closeBtn, "BACKGROUND")
    closeBg:SetAllPoints()
    closeBg:SetColorTexture(0, 0, 0, 0)
    local closeLbl = closeBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    closeLbl:SetPoint("CENTER", 0, 1)
    closeLbl:SetText("\195\151")
    closeLbl:SetTextColor(1, 1, 1, 1)
    closeBtn:SetScript("OnEnter", function()
        closeBg:SetColorTexture(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
    end)
    closeBtn:SetScript("OnLeave", function()
        closeBg:SetColorTexture(0, 0, 0, 0)
    end)
    closeBtn:SetScript("OnClick", function() ConfigFadeOut(frame) end)

    -- ── SIDEBAR ────────────────────────────────────────────
    local sidebar = FlatFrame(frame, C.sidebar[1], C.sidebar[2], C.sidebar[3], C.sidebar[4])
    sidebar:SetPoint("TOPLEFT",    titleBg, "BOTTOMLEFT",   2,  0)
    sidebar:SetPoint("BOTTOMLEFT", frame,   "BOTTOMLEFT",   2,  BOT_H+2)
    sidebar:SetWidth(SIDEBAR_W)

    local sbl = Tex(sidebar); sbl:SetWidth(1)
    sbl:SetPoint("TOPRIGHT",    sidebar, "TOPRIGHT",    0,  0)
    sbl:SetPoint("BOTTOMRIGHT", sidebar, "BOTTOMRIGHT", 0,  0)
    sbl:SetColorTexture(
        math.min(1, C.primary[1]*0.38+0.08), math.min(1, C.primary[2]*0.38+0.08), math.min(1, C.primary[3]*0.38+0.08), 1)

    -- ── INHALTSBEREICH ────────────────────────────────────
    local contentBg = FlatFrame(frame, C.content[1], C.content[2], C.content[3], C.content[4],
        C.border[1]*0.5, C.border[2]*0.5, C.border[3]*0.5, C.border[4])
    contentBg:SetPoint("TOPLEFT",     sidebar,  "TOPRIGHT",    1,  0)
    contentBg:SetPoint("BOTTOMRIGHT", frame,    "BOTTOMRIGHT", -2, BOT_H+2)

    -- ── UNTERE LEISTE ─────────────────────────────────────
    local bot = FlatFrame(frame,
        (C.botFill and C.botFill[1]) or 0.038, (C.botFill and C.botFill[2]) or 0.032, (C.botFill and C.botFill[3]) or 0.032, (C.botFill and C.botFill[4]) or 1,
        (C.botEdge and C.botEdge[1]) or 0.12, (C.botEdge and C.botEdge[2]) or 0.06, (C.botEdge and C.botEdge[3]) or 0.06, (C.botEdge and C.botEdge[4]) or 1)
    bot:SetPoint("BOTTOMLEFT",  frame, "BOTTOMLEFT",   2, 2)
    bot:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -2, 2)
    bot:SetHeight(BOT_H)

    local botLine = Tex(bot); botLine:SetHeight(1)
    botLine:SetPoint("TOPLEFT",  bot, "TOPLEFT",  0, 0)
    botLine:SetPoint("TOPRIGHT", bot, "TOPRIGHT", 0, 0)
    botLine:SetColorTexture(C.primary[1], C.primary[2], C.primary[3], 0.28)

    -- Reload Button (rechts)
    StyledButton(bot, L.Strings["GUI_RELOAD_BUTTON"], 130, 28, function() ReloadUI() end)
        :SetPoint("RIGHT", bot, "RIGHT", -12, 0)

    -- GUI Scale (links)
    do
        local SCALE_STEP = 0.05
        local SCALE_MIN  = 0.5
        local SCALE_MAX  = 2.0

        local scaleLbl = FS(bot, "GameFontHighlightSmall")
        scaleLbl:SetPoint("LEFT", bot, "LEFT", 10, 0)
        scaleLbl:SetTextColor(unpack(C.textDim))
        scaleLbl:SetText("GUI Scale")

        local function GetScale() return (rChatDB and rChatDB.guiScale) or 1.0 end
        local function ApplyScale(v)
            v = math.max(SCALE_MIN, math.min(SCALE_MAX, v))
            v = math.floor(v / SCALE_STEP + 0.5) * SCALE_STEP
            v = math.floor(v * 100 + 0.5) / 100
            if rChatDB then rChatDB.guiScale = v end
            frame:SetScale(v)
        end

        local valBox = CreateFrame("EditBox", nil, bot, "BackdropTemplate")
        valBox:SetSize(46, 22)
        valBox:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8x8", edgeFile="Interface\\Buttons\\WHITE8x8",
            edgeSize=1, insets={left=0,right=0,top=0,bottom=0}})
        valBox:SetBackdropColor(0.04, 0.04, 0.05, 0.9)
        valBox:SetBackdropBorderColor(
            math.min(1, C.primary[1]*0.48+0.10), math.min(1, C.primary[2]*0.48+0.10), math.min(1, C.primary[3]*0.48+0.10), 1)
        valBox:SetFont("Fonts\\FRIZQT__.TTF", 11, "")
        valBox:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
        valBox:SetJustifyH("CENTER"); valBox:SetMaxLetters(5); valBox:SetAutoFocus(false)
        valBox:EnableMouseWheel(true)

        local function SyncScaleBox()
            valBox:SetText(string.format("%.2f", GetScale()))
            frame:SetScale(GetScale())
        end

        local function MakeArrowBtn(ltext, dir)
            local b = CreateFrame("Button", nil, bot, "BackdropTemplate")
            b:SetSize(20, 22)
            b:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8x8", edgeFile="Interface\\Buttons\\WHITE8x8",
                edgeSize=1, insets={left=1,right=1,top=1,bottom=1}})
            b:SetBackdropColor(
                (C.toggleOff and C.toggleOff[1]) or 0.08, (C.toggleOff and C.toggleOff[2]) or 0.08, (C.toggleOff and C.toggleOff[3]) or 0.09, 1)
            b:SetBackdropBorderColor(
                math.min(1, C.primary[1]*0.42+0.08), math.min(1, C.primary[2]*0.42+0.08), math.min(1, C.primary[3]*0.42+0.08), 1)
            local t = b:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            t:SetAllPoints(); t:SetText(ltext)
            t:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
            b:SetScript("OnEnter", function(s)
                s:SetBackdropColor(
                    math.min(1, C.primary[1]*0.22+0.08), math.min(1, C.primary[2]*0.22+0.08), math.min(1, C.primary[3]*0.22+0.08), 1)
                s:SetBackdropBorderColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
            end)
            b:SetScript("OnLeave", function(s)
                s:SetBackdropColor(
                    (C.toggleOff and C.toggleOff[1]) or 0.08, (C.toggleOff and C.toggleOff[2]) or 0.08, (C.toggleOff and C.toggleOff[3]) or 0.09, 1)
                s:SetBackdropBorderColor(
                    math.min(1, C.primary[1]*0.42+0.08), math.min(1, C.primary[2]*0.42+0.08), math.min(1, C.primary[3]*0.42+0.08), 1)
            end)
            local ticker
            b:SetScript("OnClick", function() ApplyScale(GetScale() + dir * SCALE_STEP); SyncScaleBox() end)
            b:SetScript("OnMouseDown", function()
                b.held = true
                C_Timer.After(0.4, function()
                    if b.held then
                        ticker = C_Timer.NewTicker(0.08, function()
                            if b.held then ApplyScale(GetScale() + dir * SCALE_STEP); SyncScaleBox()
                            else ticker:Cancel(); ticker = nil end
                        end)
                    end
                end)
            end)
            b:SetScript("OnMouseUp", function()
                b.held = false; if ticker then ticker:Cancel(); ticker = nil end
            end)
            return b
        end

        local btnMinus = MakeArrowBtn("<", -1)
        btnMinus:SetPoint("LEFT", scaleLbl, "RIGHT", 8, 0)
        valBox:SetPoint("LEFT", btnMinus, "RIGHT", 2, 0)
        local btnPlus = MakeArrowBtn(">", 1)
        btnPlus:SetPoint("LEFT", valBox, "RIGHT", 2, 0)

        valBox:SetScript("OnMouseWheel", function(_, d) ApplyScale(GetScale() + d * SCALE_STEP); SyncScaleBox() end)
        local function CommitTyped()
            local v = tonumber(valBox:GetText()); if v then ApplyScale(v) end
            SyncScaleBox(); valBox:ClearFocus()
        end
        valBox:SetScript("OnEnterPressed",  CommitTyped)
        valBox:SetScript("OnTabPressed",    CommitTyped)
        valBox:SetScript("OnEditFocusLost", function() C_Timer.After(0, CommitTyped) end)
        valBox:SetScript("OnEscapePressed", function() SyncScaleBox(); valBox:ClearFocus() end)
        frame:HookScript("OnShow", SyncScaleBox)
        frame:HookScript("OnHide", function() valBox:ClearFocus() end)
        frame.SyncScale = SyncScaleBox; SyncScaleBox()
    end

    -- ============================================================
    -- TAB-DEFINITIONEN
    -- ============================================================
    local TAB_DEFS = {
        { id="general",  label=L.Strings["TAB_GENERAL"],  icon="Interface\\Icons\\inv_misc_map_01" },
        { id="chicchai", label=L.Strings["TAB_CHICCHAI"], icon="Interface\\Icons\\ability_warrior_battleshout" },
        { id="chat",     label=L.Strings["TAB_CHAT"],     icon="Interface\\Icons\\inv_misc_note_06" },
    }

    local TAB_H = 44; local TAB_GAP = 2
    local tabs = {}; local tabPanels = {}

    local contentHeader = FS(contentBg, "GameFontNormalLarge")
    contentHeader:SetPoint("TOPLEFT", contentBg, "TOPLEFT", PAD, -14)
    contentHeader:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 0.70)

    local chLine = Tex(contentBg, "BACKGROUND"); chLine:SetHeight(1)
    chLine:SetPoint("TOPLEFT",  contentBg, "TOPLEFT",  PAD,  -34)
    chLine:SetPoint("TOPRIGHT", contentBg, "TOPRIGHT", -PAD, -34)
    chLine:SetColorTexture(C.primary[1], C.primary[2], C.primary[3], 0.18)

    local function SelectTab(idx)
        activeTab = idx
        for i, tab in ipairs(tabs) do
            local sel = (i == idx)
            if sel then
                tab.accent:Show()
                tab.bgTex:SetColorTexture(
                    math.min(1, C.primary[1]*0.18+0.06), math.min(1, C.primary[2]*0.18+0.06), math.min(1, C.primary[3]*0.18+0.06), 1)
                tab.icon:SetVertexColor(C.primary[1], C.primary[2], C.primary[3], 1)
                tab.lbl:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
            else
                tab.accent:Hide()
                tab.bgTex:SetColorTexture(C.sidebar[1], C.sidebar[2], C.sidebar[3], 1)
                tab.icon:SetVertexColor(
                    math.min(1, C.primaryDim[1]+0.28), math.min(1, C.primaryDim[2]+0.28), math.min(1, C.primaryDim[3]+0.28), 1)
                tab.lbl:SetTextColor(
                    math.min(1, C.primaryDim[1]+0.38), math.min(1, C.primaryDim[2]+0.38), math.min(1, C.primaryDim[3]+0.38), 1)
            end
            tabPanels[i]:SetShown(sel)
        end
        contentHeader:SetText(TAB_DEFS[idx].label)
    end

    for i, td in ipairs(TAB_DEFS) do
        local tab = CreateFrame("Button", nil, sidebar)
        tab:SetHeight(TAB_H)
        tab:SetPoint("TOPLEFT",  sidebar, "TOPLEFT",  0, -(i-1)*(TAB_H+TAB_GAP))
        tab:SetPoint("TOPRIGHT", sidebar, "TOPRIGHT", -1, -(i-1)*(TAB_H+TAB_GAP))

        tab.bgTex = Tex(tab, "BACKGROUND"); tab.bgTex:SetAllPoints()
        tab.bgTex:SetColorTexture(C.sidebar[1], C.sidebar[2], C.sidebar[3], 1)

        tab.accent = Tex(tab, "OVERLAY"); tab.accent:SetWidth(3)
        tab.accent:SetPoint("TOPLEFT",    tab, "TOPLEFT",    0, 0)
        tab.accent:SetPoint("BOTTOMLEFT", tab, "BOTTOMLEFT", 0, 0)
        tab.accent:SetColorTexture(C.primary[1], C.primary[2], C.primary[3], 1)
        tab.accent:Hide()

        local sep = Tex(tab, "BORDER"); sep:SetHeight(1)
        sep:SetPoint("BOTTOMLEFT",  tab, "BOTTOMLEFT",  0, 0)
        sep:SetPoint("BOTTOMRIGHT", tab, "BOTTOMRIGHT", 0, 0)
        sep:SetColorTexture(C.primary[1]*0.12+0.04, C.primary[2]*0.12+0.04, C.primary[3]*0.12+0.04, 1)

        tab.icon = Tex(tab, "OVERLAY"); tab.icon:SetSize(18, 18)
        tab.icon:SetPoint("LEFT", tab, "LEFT", 14, 0)
        tab.icon:SetTexture(td.icon)
        tab.icon:SetVertexColor(
            math.min(1, C.primaryDim[1]+0.28), math.min(1, C.primaryDim[2]+0.28), math.min(1, C.primaryDim[3]+0.28), 1)

        tab.lbl = FS(tab, "GameFontNormalSmall")
        tab.lbl:SetPoint("LEFT", tab.icon, "RIGHT", 8, 0)
        tab.lbl:SetPoint("RIGHT", tab, "RIGHT", -6, 0)
        tab.lbl:SetJustifyH("LEFT")
        tab.lbl:SetTextColor(
            math.min(1, C.primaryDim[1]+0.38), math.min(1, C.primaryDim[2]+0.38), math.min(1, C.primaryDim[3]+0.38), 1)
        tab.lbl:SetText(td.label)

        local ii = i
        tab:SetScript("OnEnter", function(s)
            if activeTab ~= ii then
                s.bgTex:SetColorTexture(
                    math.min(1, C.primary[1]*0.14+0.05), math.min(1, C.primary[2]*0.14+0.05), math.min(1, C.primary[3]*0.14+0.05), 1)
                s.lbl:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
                s.icon:SetVertexColor(C.primary[1], C.primary[2], C.primary[3], 1)
            end
        end)
        tab:SetScript("OnLeave", function(s)
            if activeTab ~= ii then
                s.bgTex:SetColorTexture(C.sidebar[1], C.sidebar[2], C.sidebar[3], 1)
                s.lbl:SetTextColor(
                    math.min(1, C.primaryDim[1]+0.38), math.min(1, C.primaryDim[2]+0.38), math.min(1, C.primaryDim[3]+0.38), 1)
                s.icon:SetVertexColor(
                    math.min(1, C.primaryDim[1]+0.28), math.min(1, C.primaryDim[2]+0.28), math.min(1, C.primaryDim[3]+0.28), 1)
            end
        end)
        tab:SetScript("OnClick", function() SelectTab(ii) end)
        tabs[i] = tab
    end

    do
        local ICON_SZ = 56
        local classIconHolder = CreateFrame("Frame", nil, sidebar)
        classIconHolder:SetSize(ICON_SZ, ICON_SZ)
        classIconHolder:SetPoint("BOTTOM", sidebar, "BOTTOM", 0, 10)
        local ciTex = classIconHolder:CreateTexture(nil, "ARTWORK", nil, 2)
        ciTex:SetAllPoints()
        ciTex:SetVertexColor(1, 1, 1, 1)
        if not (rChatGuiTheme and rChatGuiTheme.ApplyCustomClassIconToTexture and rChatGuiTheme.ApplyCustomClassIconToTexture(ciTex)) then
            classIconHolder:Hide()
        else
            classIconHolder:EnableMouse(true)
            classIconHolder:SetScript("OnEnter", function()
                GameTooltip:SetOwner(classIconHolder, "ANCHOR_RIGHT")
                local _, className = UnitClass("player")
                GameTooltip:SetText(className or "", C.primary[1], C.primary[2], C.primary[3], 1)
                GameTooltip:Show()
            end)
            classIconHolder:SetScript("OnLeave", function() GameTooltip:Hide() end)
        end
    end

    -- ============================================================
    -- TAB 1: GENERAL
    -- ============================================================
    local pfT1, sfT1, sT1 = MakeScroll(contentBg)
    do
        local y = -PAD

        local logo = sT1:CreateTexture(nil, "ARTWORK")
        logo:SetTexture("Interface\\AddOns\\rChat\\core\\logo_big")
        logo:SetSize(300, 200)
        logo:SetPoint("TOP", sT1, "TOP", 0, y)
        y = y - 212

        HRule(sT1, sT1, y); y = y - 20
        SectionHeader(sT1, L.Strings["GENERAL_SLASHCMDS"], sT1, 0, y); y = y - 32

        local slashRows = {
            {"/rchat",         L.Strings["GENERAL_OPEN_BTN"]},
            {"/rchat config",  L.Strings["GENERAL_OPEN_BTN"]},
            {"/rchat toggle",  L.Strings["TAB_CHICCHAI"] .. " on/off"},
            {"/rchat minimap", L.Strings["CMD_MINIMAP"] or "Toggle minimap icon"},
            {"/rchat reset",   L.Strings["GENERAL_RESET_BTN"]},
        }
        for _, row in ipairs(slashRows) do
            local cl = FS(sT1, "GameFontNormalSmall")
            cl:SetPoint("TOPLEFT", sT1, "TOPLEFT", 4, y)
            cl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 0.9)
            cl:SetText(row[1])
            local dl = FS(sT1, "GameFontHighlightSmall")
            dl:SetPoint("LEFT", cl, "RIGHT", 10, 0)
            dl:SetTextColor(unpack(C.textDim))
            dl:SetText("- " .. row[2])
            y = y - 24
        end

        y = y - 16
        HRule(sT1, sT1, y); y = y - 20
        SectionHeader(sT1, L.Strings["SECTION_MINIMAP"], sT1, 0, y); y = y - 32

        ModernToggle(sT1,
            L.Strings["MINIMAP_ICON_SHOW"],
            L.Strings["MINIMAP_ICON_SHOW_DESC"],
            sT1, y,
            function() return not L:GetConfig("minimap", "hide") end,
            function(v)
                if reloadDialog and reloadDialog:IsShown() then
                    RefreshAllToggles()
                    return
                end
                local newHide = not v
                L:SetConfig("minimap", "hide", newHide)
                RefreshAllToggles()
                ShowMinimapReloadDialog(newHide)
            end)
        y = y - 58

        HRule(sT1, sT1, y); y = y - 20

        local resetNote = FS(sT1, "GameFontHighlightSmall")
        resetNote:SetPoint("TOPLEFT", sT1, "TOPLEFT", 0, y)
        resetNote:SetTextColor(unpack(C.textDim))
        resetNote:SetText(L.Strings["GENERAL_RESET_NOTE"])
        y = y - 30

        local resetBtn, _ = StyledButton(sT1, L.Strings["GENERAL_RESET_BTN"], 220, 28, function()
            L:ResetConfig()
        end)
        resetBtn:SetPoint("TOPLEFT", sT1, "TOPLEFT", 0, y)
        y = y - 44

        sT1:SetHeight(math.abs(y) + 40)
    end
    tabPanels[1] = pfT1

    -- ============================================================
    -- TAB 2: CHICCHAI
    -- ============================================================
    local pfT2, sfT2, sT2 = MakeScroll(contentBg)
    do
        local y = -PAD

        SectionHeader(sT2, L.Strings["CHICCHAI_HEADER"], sT2, 0, y); y = y - 32

        ModernToggle(sT2,
            L.Strings["CHICCHAI_ENABLE"],
            L.Strings["CHICCHAI_ENABLE_DESC"],
            sT2, y,
            function() return L:GetConfig("chicchai", "enabled") end,
            function(v) L:SetConfig("chicchai", "enabled", v) end,
            true)
        y = y - 58

        -- Info-Box
        local infoBox = FlatFrame(sT2,
            math.min(1, C.primary[1]*0.12+0.06), math.min(1, C.primary[2]*0.12+0.06), math.min(1, C.primary[3]*0.12+0.06), 0.8,
            math.min(1, C.primary[1]*0.42+0.10), math.min(1, C.primary[2]*0.42+0.10), math.min(1, C.primary[3]*0.42+0.10), 1)
        infoBox:SetPoint("TOPLEFT", sT2, "TOPLEFT", 0, y)
        infoBox:SetSize(CW() - 20, 44)
        tinsert(widthMiscRows, { f = infoBox, minus = 20, fh = 44 })
        local infoLbl = FS(infoBox, "GameFontHighlightSmall")
        infoLbl:SetPoint("LEFT", infoBox, "LEFT", 12, 0)
        infoLbl:SetPoint("RIGHT", infoBox, "RIGHT", -8, 0)
        infoLbl:SetJustifyH("LEFT")
        infoLbl:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
        infoLbl:SetText(L.Strings["CHICCHAI_EDITMODE_NOTE"])
        y = y - 58

        HRule(sT2, sT2, y); y = y - 20
        SectionHeader(sT2, L.Strings["SECTION_TIMING_ANIM"], sT2, 0, y); y = y - 32

        ModernSlider(sT2,
            L.Strings["CHICCHAI_ANIM_TIME"],
            L.Strings["CHICCHAI_ANIM_TIME_DESC"],
            0.1, 2.0, 0.1, sT2, y,
            function() return L:GetConfig("chicchai", "animTime") end,
            function(v) L:SetConfig("chicchai", "animTime", v) end,
            function(v) return string.format("%.1fs", v) end)
        y = y - 78

        ModernSlider(sT2,
            L.Strings["CHICCHAI_MIN_TIME"],
            L.Strings["CHICCHAI_MIN_TIME_DESC"],
            1, 60, 1, sT2, y,
            function() return L:GetConfig("chicchai", "minimizeTime") end,
            function(v) L:SetConfig("chicchai", "minimizeTime", v) end,
            function(v) return math.floor(v) .. "s" end)
        y = y - 78

        ModernSlider(sT2,
            L.Strings["CHICCHAI_MIN_LINES"],
            L.Strings["CHICCHAI_MIN_LINES_DESC"],
            1, 5, 1, sT2, y,
            function() return L:GetConfig("chicchai", "minimizedLines") end,
            function(v) L:SetConfig("chicchai", "minimizedLines", v) end,
            function(v) return math.floor(v) end)
        y = y - 78

        HRule(sT2, sT2, y); y = y - 20
        SectionHeader(sT2, L.Strings["SECTION_BEHAVIOR"], sT2, 0, y); y = y - 32

        ModernToggle(sT2,
            L.Strings["CHICCHAI_MOUSE_OVER"],
            L.Strings["CHICCHAI_MOUSE_OVER_DESC"],
            sT2, y,
            function() return L:GetConfig("chicchai", "maximizeOnEnter") end,
            function(v) L:SetConfig("chicchai", "maximizeOnEnter", v) end)
        y = y - 58

        ModernToggle(sT2,
            L.Strings["CHICCHAI_COMBAT_LOCK"],
            L.Strings["CHICCHAI_COMBAT_LOCK_DESC"],
            sT2, y,
            function() return L:GetConfig("chicchai", "lockInCombat") end,
            function(v) L:SetConfig("chicchai", "lockInCombat", v) end)
        y = y - 58

        ModernToggle(sT2,
            L.Strings["CHICCHAI_COMBAT_LOG"],
            L.Strings["CHICCHAI_COMBAT_LOG_DESC"],
            sT2, y,
            function() return L:GetConfig("chicchai", "maximizeCombatLog") end,
            function(v) L:SetConfig("chicchai", "maximizeCombatLog", v) end,
            true)
        y = y - 58

        sT2:SetHeight(math.abs(y) + 40)
    end
    tabPanels[2] = pfT2

    -- ============================================================
    -- TAB 3: CHAT
    -- ============================================================
    local pfT3, sfT3, sT3 = MakeScroll(contentBg)
    do
        local y = -PAD

        SectionHeader(sT3, L.Strings["CHAT_HEADER"], sT3, 0, y); y = y - 32

        ModernToggle(sT3,
            L.Strings["CHAT_ALWAYS_SHOW_TABS"],
            L.Strings["CHAT_ALWAYS_SHOW_TABS_DESC"],
            sT3, y,
            function() return L:GetConfig("chat", "alwaysShowTabs") end,
            function(v) L:SetConfig("chat", "alwaysShowTabs", v) end,
            true)
        y = y - 58

        ModernToggle(sT3,
            L.Strings["CHAT_SHOW_TIMESTAMP"],
            L.Strings["CHAT_SHOW_TIMESTAMP_DESC"],
            sT3, y,
            function() return L:GetConfig("chat", "showTimestamp") end,
            function(v) L:SetConfig("chat", "showTimestamp", v) end,
            true)
        y = y - 58

        ModernToggle(sT3,
            L.Strings["CHAT_SHOW_PLAYER_LEVEL"],
            L.Strings["CHAT_SHOW_PLAYER_LEVEL_DESC"],
            sT3, y,
            function() return L:GetConfig("chat", "showPlayerLevel") end,
            function(v) L:SetConfig("chat", "showPlayerLevel", v) end,
            true)
        y = y - 58

        ModernToggle(sT3,
            L.Strings["CHAT_ENABLE_URL_COPY"],
            L.Strings["CHAT_ENABLE_URL_COPY_DESC"],
            sT3, y,
            function() return L:GetConfig("chat", "enableURLCopy") end,
            function(v) L:SetConfig("chat", "enableURLCopy", v) end)
        y = y - 58

        ModernToggle(sT3,
            L.Strings["CHAT_ENABLE_COPY_BUTTON"],
            L.Strings["CHAT_ENABLE_COPY_BUTTON_DESC"],
            sT3, y,
            function() return L:GetConfig("chat", "enableChatCopyButton") end,
            function(v) L:SetConfig("chat", "enableChatCopyButton", v) end,
            true)
        y = y - 58

        HRule(sT3, sT3, y); y = y - 20
        SectionHeader(sT3, L.Strings["SECTION_TIMING_POS"], sT3, 0, y); y = y - 32

        ModernSlider(sT3,
            L.Strings["CHAT_FADE_TIME"],
            L.Strings["CHAT_FADE_TIME_DESC"],
            5, 120, 5, sT3, y,
            function() return L:GetConfig("chat", "chatFadeTime") end,
            function(v) L:SetConfig("chat", "chatFadeTime", v) end,
            function(v) return math.floor(v) .. "s" end,
            true)
        y = y - 78

        local posLbl = FS(sT3); posLbl:SetPoint("TOPLEFT", sT3, "TOPLEFT", 0, y)
        posLbl:SetTextColor(unpack(C.text)); posLbl:SetText(L.Strings["CHAT_EDITBOX_POSITION"])
        local posHint = FS(sT3, "GameFontHighlightSmall")
        posHint:SetPoint("TOPLEFT", posLbl, "BOTTOMLEFT", 0, -3)
        posHint:SetTextColor(unpack(C.textDim)); posHint:SetText(L.Strings["CHAT_EDITBOX_POSITION_DESC"])
        y = y - 44

        ModernDropdown(sT3, 200, sT3, y,
            function()
                return {
                    {key = "top",    label = L.Strings["CHAT_EDITBOX_TOP"]},
                    {key = "bottom", label = L.Strings["CHAT_EDITBOX_BOTTOM"]},
                }
            end,
            function() return L:GetConfig("chat", "editboxPosition") end,
            function(v) L:SetConfig("chat", "editboxPosition", v); L:UpdateEditBoxPositions() end)
        y = y - 44

        sT3:SetHeight(math.abs(y) + 40)
    end
    tabPanels[3] = pfT3

    SelectTab(1)

    if RR_ConfigResizeGrip_Attach then
        RR_ConfigResizeGrip_Attach({
            frame = frame,
            titleBg = titleBg,
            dbTable = rChatDB,
            texturePath = "Interface\\AddOns\\rChat\\core\\resize.tga",
            gripName = "rChatConfigResizeGrip",
            defW = FRAME_W_DEFAULT,
            defH = FRAME_H_DEFAULT,
            primary = { C.primary[1], C.primary[2], C.primary[3] },
            primaryHi = { C.primaryHi[1], C.primaryHi[2], C.primaryHi[3] },
            tooltipText = (L.Strings and L.Strings["GUI_RESIZE_GRIP"]) or "Drag to resize. Size is saved.",
            syncScaleName = "SyncScale",
            onSaved = function()
                FRAME_W = rChatDB.guiFrameW or FRAME_W
                FRAME_H = rChatDB.guiFrameH or FRAME_H
            end,
            onLiveResize = function(w, h)
                FRAME_W, FRAME_H = w, h
                local cw = CW() - 20
                for _, c in ipairs(allToggles) do
                    if c and c.SetSize and not c:IsForbidden() then
                        c:SetSize(math.max(60, cw), c:GetHeight())
                        if c.Refresh then c:Refresh() end
                    end
                end
                for _, c in ipairs(allSliders) do
                    if c and c.SetSize and not c:IsForbidden() then
                        c:SetSize(math.max(60, cw), c:GetHeight())
                        if c.Refresh then c:Refresh() end
                    end
                end
                for _, e in ipairs(widthMiscRows) do
                    if e.f and e.f.SetSize and not e.f:IsForbidden() then
                        e.f:SetSize(math.max(60, CW() - e.minus), e.fh)
                    end
                end
                for _, d in ipairs(rChatDdRows) do
                    if d and d.ApplyRChatDdLayout then d:ApplyRChatDdLayout() end
                    if d and d.Refresh then d:Refresh() end
                end
                for _, panel in ipairs(tabPanels) do
                    if panel.sf and panel.sc then
                        local wf = panel.sf:GetWidth()
                        if wf and wf > 40 then panel.sc:SetWidth(math.max(100, wf - 4)) end
                    end
                    if panel.UpdateThumb then panel.UpdateThumb() end
                end
            end,
        })
    end

    configFrame = frame
    return frame
end

-- ============================================================
-- PUBLIC API
-- ============================================================
function L:ShowConfig()
    local frame = BuildConfigFrame()
    if frame:IsShown() then ConfigFadeOut(frame) else ConfigFadeIn(frame) end
end

function L:RegisterInterfaceOptions()
    if rChatGuiTheme and rChatGuiTheme.ApplyPalette then
        rChatGuiTheme.ApplyPalette(C)
    end

    local panel = CreateFrame("Frame", "rChatInterfacePanel")
    panel.name = "rChat"

    -- Big logo centered at top (nmainbar-style)
    local logo = panel:CreateTexture(nil, "ARTWORK")
    logo:SetTexture("Interface\\AddOns\\rChat\\core\\logo_big")
    logo:SetSize(400, 267)
    logo:SetPoint("TOP", panel, "TOP", 0, -28)

    local optsHex = (rChatGuiTheme and rChatGuiTheme.RGBToWoWColorHex)
        and rChatGuiTheme.RGBToWoWColorHex(C.primary[1], C.primary[2], C.primary[3])
        or "af1917"

    -- Addon title below logo
    local titleLbl = panel:CreateFontString(nil, "ARTWORK", "GameFontNormalHuge")
    titleLbl:SetPoint("TOP", logo, "BOTTOM", 0, -10)
    titleLbl:SetTextColor(1, 1, 1, 1)
    titleLbl:SetText("|cff" .. optsHex .. "r|rChat")
    AttachGuiTitleVersion(panel, titleLbl, "rChat", C.textDim[1], C.textDim[2], C.textDim[3])

    -- Author sub-line
    local subLbl = panel:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
    subLbl:SetPoint("TOP", titleLbl, "BOTTOM", 0, -4)
    subLbl:SetTextColor(
        math.min(1, C.primaryDim[1]+0.25), math.min(1, C.primaryDim[2]+0.25), math.min(1, C.primaryDim[3]+0.25), 1)
    subLbl:SetText("by zork")

    -- Description
    local descLbl = panel:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    descLbl:SetPoint("TOP", subLbl, "BOTTOM", 0, -8)
    descLbl:SetWidth(440)
    descLbl:SetJustifyH("CENTER")
    descLbl:SetTextColor(unpack(C.textDim))
    descLbl:SetText(L.Strings["GENERAL_ADDON_DESC"])

    -- Open Settings button
    local openBtn = CreateFrame("Button", nil, panel, "BackdropTemplate")
    openBtn:SetSize(240, 40)
    openBtn:SetPoint("TOP", descLbl, "BOTTOM", 0, -20)
    openBtn:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
        tile=false, edgeSize=1, insets={left=0,right=0,top=0,bottom=0}})
    openBtn:SetBackdropColor(
        math.min(1, C.primary[1]*0.26+0.05), math.min(1, C.primary[2]*0.26+0.05), math.min(1, C.primary[3]*0.26+0.05), 1)
    openBtn:SetBackdropBorderColor(
        math.min(1, C.primary[1]*0.52+0.10), math.min(1, C.primary[2]*0.52+0.10), math.min(1, C.primary[3]*0.52+0.10), 1)
    local openLbl = openBtn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    openLbl:SetPoint("CENTER")
    openLbl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 1)
    openLbl:SetText(L.Strings["GENERAL_OPEN_BTN"])
    openBtn:SetScript("OnEnter", function(s)
        s:SetBackdropColor(
            math.min(1, C.primary[1]*0.40+0.06), math.min(1, C.primary[2]*0.40+0.06), math.min(1, C.primary[3]*0.40+0.06), 1)
        s:SetBackdropBorderColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
        openLbl:SetTextColor(1, 1, 1, 1)
    end)
    openBtn:SetScript("OnLeave", function(s)
        s:SetBackdropColor(
            math.min(1, C.primary[1]*0.26+0.05), math.min(1, C.primary[2]*0.26+0.05), math.min(1, C.primary[3]*0.26+0.05), 1)
        s:SetBackdropBorderColor(
            math.min(1, C.primary[1]*0.52+0.10), math.min(1, C.primary[2]*0.52+0.10), math.min(1, C.primary[3]*0.52+0.10), 1)
        openLbl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 1)
    end)
    openBtn:SetScript("OnClick", function()
        C_Timer.After(0, function()
            if SettingsPanel and SettingsPanel:IsShown() then HideUIPanel(SettingsPanel) end
            L:ShowConfig()
        end)
    end)

    -- Thin gradient accent line under button
    local accentL = panel:CreateTexture(nil, "ARTWORK")
    accentL:SetHeight(1)
    accentL:SetWidth(240)
    accentL:SetPoint("TOP", openBtn, "BOTTOM", 0, -6)
    accentL:SetGradient("HORIZONTAL",
        CreateColor(0, 0, 0, 0),
        CreateColor(C.primary[1], C.primary[2], C.primary[3], 0.6))
    local accentR = panel:CreateTexture(nil, "ARTWORK")
    accentR:SetHeight(1)
    accentR:SetWidth(240)
    accentR:SetPoint("TOP", openBtn, "BOTTOM", 0, -6)
    accentR:SetGradient("HORIZONTAL",
        CreateColor(C.primary[1], C.primary[2], C.primary[3], 0.6),
        CreateColor(0, 0, 0, 0))

    local category = Settings.RegisterCanvasLayoutCategory(panel, panel.name)
    Settings.RegisterAddOnCategory(category)
    rChatSettingsCategoryID = category:GetID()
    L.settingsCategory = category
end

-- ============================================================
-- SLASH COMMANDS
-- ============================================================
SLASH_RCHAT1 = "/rchat"
SlashCmdList["RCHAT"] = function(msg)
    msg = msg:lower():trim()
    if msg == "config" or msg == "cfg" or msg == "" then
        L:ShowConfig()
    elseif msg == "toggle" then
        local enabled = L:GetConfig("chicchai", "enabled")
        L:SetConfig("chicchai", "enabled", not enabled)
        print("|cffaf1917rChat:|r Chicchai", not enabled and "|cff00ff00" .. L.Strings["CHICCHAI_ENABLED"] .. "|r" or "|cffff0000" .. L.Strings["CHICCHAI_DISABLED"] .. "|r")
        ReloadUI()
    elseif msg == "minimap" then
        -- Minimap-Symbol an/aus – mit modernem Reload-Dialog
        local newHide = not L:GetConfig("minimap", "hide")
        L:SetConfig("minimap", "hide", newHide)
        ShowMinimapReloadDialog(newHide)
    elseif msg == "reset" then
        L:ResetConfig()
    else
        print("|cffaf1917rChat:|r " .. (L.Strings and L.Strings["CMD_HELP"] or "Verfügbare Befehle:"))
        print("  " .. (L.Strings and L.Strings["CMD_CONFIG"]  or "/rchat config"))
        print("  " .. (L.Strings and L.Strings["CMD_TOGGLE"]  or "/rchat toggle"))
        print("  " .. (L.Strings and L.Strings["CMD_MINIMAP"] or "/rchat minimap"))
        print("  " .. (L.Strings and L.Strings["CMD_RESET"]   or "/rchat reset"))
    end
end
