-------------------------
-- AiB Co-Tank | Options
-- Inline im AiB Settings Tab | 3 Sub-Tabs
-- Vollständig user-definierte Alerts, nach Boss gruppiert
-------------------------

local ns = AiB.CoTank.ns
local K  = ns.K

ns.activeInnerTab = ns.activeInnerTab or "general"

-- ── Farben ────────────────────────────────────────────────────────────────
local C = {
    accent = {1.00,0.35,0.35}, dim    = {0.52,0.38,0.38},
    text   = {0.90,0.90,0.90}, border = {0.28,0.12,0.12},
    btnBg  = {0.14,0.06,0.06}, btnHov = {0.45,0.08,0.08},
    danger = {0.44,0.10,0.12}, ok     = {0.30,0.80,0.48},
    warn   = {0.95,0.70,0.12}, rule   = {1.00,0.20,0.20},
    tabOn  = {0.22,0.08,0.08}, tabOff = {0.10,0.05,0.05},
    raidHdr= {1.00,0.55,0.15}, bossHdr= {0.80,0.80,0.80},
}
local TILE = "Interface\\Buttons\\WHITE8X8"

-- ── Widgets ───────────────────────────────────────────────────────────────
local function PxBorder(f)
    local t = f:CreateTexture(nil,"BORDER"); t:SetColorTexture(C.border[1],C.border[2],C.border[3],1)
    t:SetPoint("TOPLEFT",f,"TOPLEFT",-1,1); t:SetPoint("BOTTOMRIGHT",f,"BOTTOMRIGHT",1,-1); t:SetDrawLayer("BORDER",-1)
end
local function Btn(p,w,h,lbl,bgC)
    bgC=bgC or C.btnBg; local b=CreateFrame("Button",nil,p); b:SetSize(w,h)
    local bg=b:CreateTexture(nil,"BACKGROUND"); bg:SetAllPoints(); bg:SetColorTexture(bgC[1],bgC[2],bgC[3]); b.bg=bg
    PxBorder(b)
    local fs=b:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
    fs:SetAllPoints(); fs:SetJustifyH("CENTER"); fs:SetText(lbl or ""); b.label=fs
    b.SetText=function(_,t) if fs then fs:SetText(tostring(t or "")) end end
    b.GetText=function(_) return fs:GetText() end
    b:SetScript("OnEnter",function() bg:SetColorTexture(C.btnHov[1],C.btnHov[2],C.btnHov[3]) end)
    b:SetScript("OnLeave",function() bg:SetColorTexture(bgC[1],bgC[2],bgC[3]) end)
    return b
end
local function ABtn(p,w,h,l) local b=Btn(p,w,h,l); b.label:SetTextColor(C.accent[1],C.accent[2],C.accent[3]); return b end
local function DBtn(p,w,h,l)
    local b=Btn(p,w,h,l,C.danger); b.label:SetTextColor(1,0.48,0.48)
    b:SetScript("OnEnter",function() b.bg:SetColorTexture(0.62,0.14,0.14) end)
    b:SetScript("OnLeave",function() b.bg:SetColorTexture(C.danger[1],C.danger[2],C.danger[3]) end)
    return b
end
local function SecHdr(p,lbl,x,y)
    local bar=p:CreateTexture(nil,"ARTWORK"); bar:SetHeight(1)
    bar:SetPoint("TOPLEFT",p,"TOPLEFT",x,y); bar:SetPoint("TOPRIGHT",p,"TOPRIGHT",-20,y)
    bar:SetColorTexture(C.rule[1],C.rule[2],C.rule[3],0.7)
    local fs=p:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
    fs:SetPoint("TOPLEFT",bar,"BOTTOMLEFT",0,-4); fs:SetTextColor(C.accent[1],C.accent[2],C.accent[3]); fs:SetText(lbl)
end
local function Lbl(p,txt,x,y)
    local fs=p:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
    fs:SetPoint("TOPLEFT",p,"TOPLEFT",x,y); fs:SetTextColor(C.text[1],C.text[2],C.text[3]); fs:SetText(txt); return fs
end
local function MkSl(p,x,y,w,mn,mx,st)
    local sl=CreateFrame("Slider",nil,p,"BackdropTemplate"); sl:SetSize(w,12); sl:SetOrientation("HORIZONTAL")
    sl:SetMinMaxValues(mn,mx); sl:SetValueStep(st or 1); sl:SetObeyStepOnDrag(true)
    sl:SetPoint("TOPLEFT",p,"TOPLEFT",x,y)
    sl:SetBackdrop({bgFile=TILE,edgeFile=TILE,edgeSize=1})
    sl:SetBackdropColor(0.08,0.04,0.04,1); sl:SetBackdropBorderColor(0.32,0.14,0.14,1)
    local th=sl:CreateTexture(nil,"OVERLAY"); th:SetSize(8,18); th:SetColorTexture(C.accent[1],C.accent[2],C.accent[3],1); sl:SetThumbTexture(th); return sl
end
local function VT(p,sl)
    local vt=p:CreateFontString(nil,"OVERLAY","GameFontHighlight")
    vt:SetPoint("LEFT",sl,"RIGHT",8,0); vt:SetTextColor(C.accent[1],C.accent[2],C.accent[3]); return vt
end
local function EBx(p,w,h,num)
    local eb=CreateFrame("EditBox",nil,p,"BackdropTemplate"); eb:SetSize(w or 140,h or 26); eb:SetAutoFocus(false)
    eb:SetBackdrop({bgFile=TILE,edgeFile=TILE,edgeSize=1}); eb:SetBackdropColor(0.06,0.03,0.03,1)
    eb:SetBackdropBorderColor(C.border[1],C.border[2],C.border[3],1)
    eb:SetFont("Fonts\\ARIALN.TTF",11,""); eb:SetTextColor(C.text[1],C.text[2],C.text[3],1)
    eb:SetTextInsets(6,6,2,2); eb:SetMaxLetters(80)
    if num then eb:SetNumeric(true) end
    eb:SetScript("OnEscapePressed",function(s) s:ClearFocus() end)
    eb:SetScript("OnEditFocusGained",function(s) s:SetBackdropBorderColor(C.accent[1],C.accent[2],C.accent[3],0.8) end)
    eb:SetScript("OnEditFocusLost",function(s)   s:SetBackdropBorderColor(C.border[1],C.border[2],C.border[3],1) end)
    return eb
end

-- Dropdown
local activeDP=nil
local ddD=CreateFrame("Frame",nil,UIParent); ddD:SetAllPoints(); ddD:SetFrameStrata("FULLSCREEN"); ddD:EnableMouse(true); ddD:Hide()
ddD:SetScript("OnMouseDown",function() if activeDP then activeDP:Hide(); activeDP=nil end; ddD:Hide() end)

local MAX_DD_ROWS = 10  -- max sichtbare Zeilen vor Scroll
local DD_ROW_H    = 22

local function MkDD(p,x,y,w,opts,onSel,initLabel)
    local btn=Btn(p,w,24,initLabel or ""); btn:SetPoint("TOPLEFT",p,"TOPLEFT",x,y)
    btn.label:SetJustifyH("LEFT"); btn.label:ClearAllPoints()
    btn.label:SetPoint("LEFT",btn,"LEFT",6,0); btn.label:SetPoint("RIGHT",btn,"RIGHT",-14,0)
    local arr=btn:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
    arr:SetPoint("RIGHT",btn,"RIGHT",-4,0); arr:SetText("v"); arr:SetTextColor(C.dim[1],C.dim[2],C.dim[3])

    local visRows  = math.min(#opts, MAX_DD_ROWS)
    local popH     = visRows * DD_ROW_H + 4
    local needsSB  = #opts > MAX_DD_ROWS
    local innerW   = needsSB and (w - 18) or (w - 2)

    local pop = CreateFrame("Frame",nil,UIParent,"BackdropTemplate")
    pop:SetFrameStrata("TOOLTIP"); pop:SetSize(w, popH)
    pop:SetBackdrop({bgFile=TILE,edgeFile=TILE,edgeSize=1})
    pop:SetBackdropColor(0.06,0.02,0.02,0.98)
    pop:SetBackdropBorderColor(C.border[1],C.border[2],C.border[3],1)
    pop:Hide()

    -- ScrollFrame
    local sf = CreateFrame("ScrollFrame",nil,pop)
    sf:SetPoint("TOPLEFT",pop,"TOPLEFT",1,-2); sf:SetSize(innerW, popH-4)
    sf:EnableMouseWheel(true)
    local child = CreateFrame("Frame",nil,sf)
    child:SetSize(innerW, #opts*DD_ROW_H); sf:SetScrollChild(child)

    -- Scroll: nur per Mausrad (kein Template-Scrollbar wegen API-Inkompatibilitaet)
    local scrollPos = 0
    local maxScroll  = math.max(0, #opts*DD_ROW_H - (popH-4))
    if needsSB then
        -- Scroll-Indikator: einfache Up/Down Pfeile
        local upBtn = CreateFrame("Button",nil,pop)
        upBtn:SetSize(16,14); upBtn:SetPoint("TOPRIGHT",pop,"TOPRIGHT",-1,-2)
        local upTex = upBtn:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
        upTex:SetAllPoints(); upTex:SetText("^"); upTex:SetTextColor(C.dim[1],C.dim[2],C.dim[3])
        upBtn:SetScript("OnClick",function()
            scrollPos = math.max(0, scrollPos - DD_ROW_H*3)
            sf:SetVerticalScroll(scrollPos)
        end)

        local dnBtn = CreateFrame("Button",nil,pop)
        dnBtn:SetSize(16,14); dnBtn:SetPoint("BOTTOMRIGHT",pop,"BOTTOMRIGHT",-1,2)
        local dnTex = dnBtn:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
        dnTex:SetAllPoints(); dnTex:SetText("v"); dnTex:SetTextColor(C.dim[1],C.dim[2],C.dim[3])
        dnBtn:SetScript("OnClick",function()
            scrollPos = math.min(maxScroll, scrollPos + DD_ROW_H*3)
            sf:SetVerticalScroll(scrollPos)
        end)

        -- Duenner Scrollbalken (nur visuell)
        local track = pop:CreateTexture(nil,"ARTWORK")
        track:SetWidth(4)
        track:SetPoint("TOPRIGHT",pop,"TOPRIGHT",-1,-16)
        track:SetPoint("BOTTOMRIGHT",pop,"BOTTOMRIGHT",-1,16)
        track:SetColorTexture(C.border[1],C.border[2],C.border[3],0.5)
    end

    sf:SetScript("OnMouseWheel",function(self,delta)
        scrollPos = math.max(0, math.min(maxScroll, scrollPos - delta*DD_ROW_H*3))
        sf:SetVerticalScroll(scrollPos)
    end)

    -- Eintraege
    for i,opt in ipairs(opts) do
        local ob=CreateFrame("Button",nil,child); ob:SetSize(innerW,DD_ROW_H)
        ob:SetPoint("TOPLEFT",child,"TOPLEFT",0,-(i-1)*DD_ROW_H)
        local obg=ob:CreateTexture(nil,"BACKGROUND"); obg:SetAllPoints(); obg:SetColorTexture(0,0,0,0); ob.bg=obg
        local ol=ob:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
        ol:SetPoint("LEFT",ob,"LEFT",8,0); ol:SetText(opt.label); ol:SetTextColor(C.text[1],C.text[2],C.text[3])
        ob:SetScript("OnEnter",function() obg:SetColorTexture(C.btnHov[1],C.btnHov[2],C.btnHov[3],0.7) end)
        ob:SetScript("OnLeave",function() obg:SetColorTexture(0,0,0,0) end)
        ob:SetScript("OnClick",function()
            btn:SetText(opt.label); pop:Hide(); activeDP=nil; ddD:Hide(); onSel(opt)
        end)
    end

    btn:SetScript("OnClick",function()
        if activeDP==pop then pop:Hide(); activeDP=nil; ddD:Hide(); return end
        if activeDP then activeDP:Hide() end
        pop:ClearAllPoints()
        local btnAbsY = select(2,btn:GetCenter())
        if btnAbsY and btnAbsY < popH+30 then
            pop:SetPoint("BOTTOMLEFT",btn,"TOPLEFT",0,2)
        else
            pop:SetPoint("TOPLEFT",btn,"BOTTOMLEFT",0,-2)
        end
        pop:Show(); activeDP=pop; ddD:Show()
    end)
    btn.SetSelected=function(_,l) btn:SetText(l or "") end; btn._popup=pop; return btn
end

-- ── Hilfsdaten ────────────────────────────────────────────────────────────
local ACTION_TYPES = {
    {id="taunt",          label="Taunt"},
    {id="tank swap",      label="Tank Swap"},
    {id="tank debuff",    label="Tank Debuff"},
    {id="tank physical",  label="Tank Physical"},
    {id="tank dot",       label="Tank DoT"},
    {id="tank bleed",     label="Tank Bleed"},
    {id="tank tether",    label="Tank Tether"},
    {id="tank marker",    label="Tank Marker"},
    {id="custom",         label="Custom"},
}
local NOTE_CLR = {
    taunt={1,.50,.10}, ["tank swap"]={1,.60,.15}, ["tank debuff"]={1,.40,.40},
    ["tank physical"]={.85,.68,.40}, ["tank dot"]={1,.35,.35}, ["tank bleed"]={1,.40,.40},
    ["tank tether"]={.75,.50,1}, ["tank marker"]={.60,1,.60}, custom={.60,.60,.60},
}
local function NC(note) return NOTE_CLR[note] or {.60,.60,.60} end
local function ActionLabel(id)
    for _,a in ipairs(ACTION_TYPES) do if a.id==id then return a.label end end; return id or "?"
end
local function LookupSpellName(sid)
    if not sid or sid<=0 then return nil end
    if C_Spell and C_Spell.GetSpellInfo then local i=C_Spell.GetSpellInfo(sid); if i and i.name then return i.name end end
    local n=GetSpellInfo and GetSpellInfo(sid); return n or nil
end

-- ── Tab-Leiste ────────────────────────────────────────────────────────────
local INNER_TABS={{id="general",label="General"},{id="alerts",label="Alerts"},{id="tools",label="Tools"}}
local function BuildTabBar(parent,x,y)
    local TW=110
    for i,tab in ipairs(INNER_TABS) do
        local active=(tab.id==ns.activeInnerTab)
        local b=CreateFrame("Button",nil,parent); b:SetSize(TW,26); b:SetPoint("TOPLEFT",parent,"TOPLEFT",x+(i-1)*(TW+3),y)
        local bgC=active and C.tabOn or C.tabOff
        local bg=b:CreateTexture(nil,"BACKGROUND"); bg:SetAllPoints(); bg:SetColorTexture(bgC[1],bgC[2],bgC[3],1); b.bg=bg
        PxBorder(b)
        local fs=b:CreateFontString(nil,"OVERLAY","GameFontNormalSmall"); fs:SetAllPoints(); fs:SetJustifyH("CENTER"); fs:SetText(tab.label)
        if active then
            fs:SetTextColor(C.accent[1],C.accent[2],C.accent[3])
            local ul=b:CreateTexture(nil,"ARTWORK"); ul:SetHeight(2)
            ul:SetPoint("BOTTOMLEFT",b,"BOTTOMLEFT",2,1); ul:SetPoint("BOTTOMRIGHT",b,"BOTTOMRIGHT",-2,1)
            ul:SetColorTexture(C.accent[1],C.accent[2],C.accent[3],1)
        else
            fs:SetTextColor(C.dim[1],C.dim[2],C.dim[3])
            b:SetScript("OnEnter",function() bg:SetColorTexture(0.18,0.08,0.08,1) end)
            b:SetScript("OnLeave",function() bg:SetColorTexture(bgC[1],bgC[2],bgC[3],1) end)
        end
        local tid=tab.id
        b:SetScript("OnClick",function() if ns.activeInnerTab~=tid then ns.activeInnerTab=tid; AiB.Settings:ShowTab("cotank") end end)
    end
    local line=parent:CreateTexture(nil,"ARTWORK"); line:SetHeight(1)
    line:SetPoint("TOPLEFT",parent,"TOPLEFT",x,y-26); line:SetPoint("TOPRIGHT",parent,"TOPRIGHT",-20,y-26)
    line:SetColorTexture(C.border[1],C.border[2],C.border[3],0.8)
    return y-36
end

-- ─────────────────────────────────────────────────────────────────────────
-- TAB: GENERAL (unverändert)
-- ─────────────────────────────────────────────────────────────────────────
local function BuildGeneral(parent,y)
    local db=ns.DB(); local L=20; local R=290; local SW=222
    local function gF() return AiB.CoTank.frame end
    local function SL(x,init,mn,mx,st,cb,fmt)
        local sl=MkSl(parent,x,y,SW,mn,mx,st); sl:SetValue(init)
        local vt=VT(parent,sl); vt:SetText(fmt and fmt(init) or math.floor(init+0.5))
        sl:SetScript("OnValueChanged",function(_,v) v=math.floor(v+0.5); vt:SetText(fmt and fmt(v) or v); cb(v) end)
        return sl,vt
    end

    SecHdr(parent,"DISPLAY",L,y); y=y-24
    Lbl(parent,"Name font size",L,y); Lbl(parent,"HP font size",R,y); y=y-18
    SL(L,ns.SettingNumber("nameFontSize",K.DEFAULT_NAME_FONT_SIZE),K.MIN_FONT_SIZE,K.MAX_FONT_SIZE,1,function(v)
        db.nameFontSize=v; local f=gF(); if f and f.nameText then f.nameText:SetFont(db.fontFace or K.DEFAULT_FONT_FACE,v,"OUTLINE") end end)
    SL(R,ns.SettingNumber("hpFontSize",K.DEFAULT_HP_FONT_SIZE),K.MIN_FONT_SIZE,K.MAX_FONT_SIZE,1,function(v)
        db.hpFontSize=v; local f=gF(); if f and f.hpText then f.hpText:SetFont(db.fontFace or K.DEFAULT_FONT_FACE,v,"OUTLINE") end end)
    y=y-28

    SecHdr(parent,"FRAME SIZE",L,y); y=y-24
    Lbl(parent,"Width",L,y); Lbl(parent,"Height",R,y); y=y-18
    SL(L,ns.SettingNumber("frameWidth",K.DEFAULT_WIDTH),K.MIN_WIDTH,K.MAX_WIDTH,5,function(v)
        db.frameWidth=v; local f=gF(); if f and not InCombatLockdown() then f:SetWidth(v); f:FitNameToWidth() end end)
    SL(R,ns.SettingNumber("frameHeight",K.DEFAULT_HEIGHT),K.MIN_HEIGHT,K.MAX_HEIGHT,5,function(v)
        db.frameHeight=v; local f=gF(); if f and not InCombatLockdown() then f:SetHeight(v) end end)
    y=y-28

    SecHdr(parent,"ICONS",L,y); y=y-24
    Lbl(parent,"Debuff icons |cff555555(harmful only)|r",L,y); Lbl(parent,"Defensive icons |cff555555(0=hidden)|r",R,y); y=y-18
    SL(L,ns.SettingNumber("maxDebuffs",K.DEBUFF_DEFAULT_COUNT),K.DEBUFF_MIN_COUNT,K.DEBUFF_MAX_COUNT,1,function(v)
        db.maxDebuffs=v; local f=gF(); if f then f:UpdateAndRefreshDebuffLayout(v); if ns.isTestMode then f:ShowMockDebuffs() end end end)
    SL(R,ns.SettingNumber("maxDefensives",K.BIG_DEFENSIVES_DEFAULT_COUNT),K.BIG_DEFENSIVES_MIN_COUNT,K.BIG_DEFENSIVES_MAX_COUNT,1,function(v)
        db.maxDefensives=v; local f=gF(); if f then f:UpdateAndRefreshDefensiveLayout(v) end end)
    y=y-28
    Lbl(parent,"Private aura slots |cff555555(above frame)|r",L,y); Lbl(parent,"Private aura size",R,y); y=y-18
    SL(L,ns.SettingNumber("maxPrivateAuras",K.PRIVATE_AURAS_DEFAULT_COUNT),K.PRIVATE_AURAS_MIN_COUNT,K.PRIVATE_AURAS_MAX_COUNT,1,function(v)
        db.maxPrivateAuras=v; local f=gF(); if f then f:UpdateAndRefreshAuraLayout(v); if ns.isTestMode then f:ShowMockPrivateAuras() end end end)
    SL(R,ns.SettingNumber("privateAuraSize",K.PRIVATE_AURA_SIZE_DEFAULT),K.PRIVATE_AURA_SIZE_MIN,K.PRIVATE_AURA_SIZE_MAX,2,function(v)
        db.privateAuraSize=v; ns.RefreshPrivateAuraSize() end,
        function(v) return v.."px" end)
    y=y-28

    SecHdr(parent,"PRIVATE AURA STYLE",L,y); y=y-24
    Lbl(parent,"Grow direction",L,y); Lbl(parent,"Border scale (0=hidden)",R,y); y=y-20
    local gdd=MkDD(parent,L,y,200,K.PRIVATE_AURA_GROW_DIRECTIONS,function(o) db.privateAuraGrowDir=o.id; ns.RefreshPrivateAuraGrow() end)
    local gid=db.privateAuraGrowDir or "LEFT"
    for _,d in ipairs(K.PRIVATE_AURA_GROW_DIRECTIONS) do if d.id==gid then gdd:SetSelected(d.label); break end end
    SL(R,ns.SettingNumber("privateAuraBorderScale",K.PRIVATE_AURA_BORDER_SCALE_DEFAULT),K.PRIVATE_AURA_BORDER_SCALE_MIN,K.PRIVATE_AURA_BORDER_SCALE_MAX,1,function(v)
        db.privateAuraBorderScale=v; ns.RefreshPrivateAuraGrow() end)
    y=y-30; Lbl(parent,"Stack & Timer Textgroesse  |cff555555(x1 = normal, x2 empfohlen bei 48px, x6 = max)|r",L,y); y=y-18
    SL(L,ns.SettingNumber("privateAuraStackScale",K.PRIVATE_AURA_STACK_SCALE_DEFAULT),K.PRIVATE_AURA_STACK_SCALE_MIN,K.PRIVATE_AURA_STACK_SCALE_MAX,1,function(v)
        db.privateAuraStackScale=v; ns.RefreshPrivateAuraGrow() end,
        function(v) return "x"..v end)
    y=y-28

    SecHdr(parent,"ICON LABELS",L,y); y=y-24
    Lbl(parent,"Stack count size (0=hidden)",L,y); Lbl(parent,"On-icon timer scale (0=hidden)",R,y); y=y-18
    SL(L,ns.SettingNumber("stackCountSize",K.STACK_COUNT_DEFAULT_SIZE),K.STACK_COUNT_MIN_SIZE,K.STACK_COUNT_MAX_SIZE,1,function(v)
        db.stackCountSize=v; ns.RefreshAllIconSettings() end)
    SL(R,ns.SettingNumber("cdFontScale",K.CD_FONT_SCALE_DEFAULT),K.CD_FONT_SCALE_MIN,K.CD_FONT_SCALE_MAX,1,function(v)
        db.cdFontScale=v; ns.RefreshAllIconSettings() end, function(v) return string.format("%.1f",v/10.0) end)
    y=y-28
    Lbl(parent,"Above-icon timer size",L,y); Lbl(parent,"Debuff icon gap",R,y); y=y-18
    SL(L,ns.SettingNumber("timerTextSize",K.TIMER_TEXT_DEFAULT_SIZE),K.TIMER_TEXT_MIN_SIZE,K.TIMER_TEXT_MAX_SIZE,1,function(v)
        db.timerTextSize=v; ns.RefreshAllIconSettings() end)
    SL(R,ns.SettingNumber("debuffSpacing",K.DEBUFF_SPACING),K.ICON_SPACING_MIN,K.ICON_SPACING_MAX,1,function(v)
        db.debuffSpacing=v; ns.RefreshDebuffSpacing() end)
    y=y-28
    Lbl(parent,"Stack count position",L,y); Lbl(parent,"Timer position",R,y); y=y-20
    local spdd=MkDD(parent,L,y,222,K.STACK_COUNT_POSITIONS,function(o) db.stackCountPos=o.id; ns.RefreshAllIconSettings() end)
    local pid=db.stackCountPos or "BR_IN"
    for _,pos in ipairs(K.STACK_COUNT_POSITIONS) do if pos.id==pid then spdd:SetSelected(pos.label); break end end
    local cpdd=MkDD(parent,R,y,200,{{id=false,label="On Icon"},{id=true,label="Above Icon"}},function(o) db.cdAbove=o.id; ns.RefreshAllIconSettings() end)
    cpdd:SetSelected(db.cdAbove and "Above Icon" or "On Icon")
    y=y-32
    Lbl(parent,"Private aura gap",L,y); y=y-18
    SL(L,ns.SettingNumber("privateAuraSpacing",K.DEBUFF_SPACING),K.ICON_SPACING_MIN,K.ICON_SPACING_MAX,1,function(v)
        db.privateAuraSpacing=v; ns.RefreshPrivateAuraSpacing() end)
    y=y-28

    -- ── MEINE PRIVATE AURAS ───────────────────────────────────────────────
    y=y-10
    SecHdr(parent,"MEINE PRIVATE AURAS",L,y); y=y-24

    local function maGet(key, def)
        local d=ns.DB(); d.myPrivateAuras=d.myPrivateAuras or {}
        local v=d.myPrivateAuras[key]; return v~=nil and v or def
    end

    -- Zeile 1: Enable / Preview / Lock
    local maEnBtn = Btn(parent,150,26,
        ns.MyAuras:GetEnabled() and "|cff44ff88Anzeigen: ON|r" or "|cffff6666Anzeigen: OFF|r")
    maEnBtn:SetPoint("TOPLEFT",parent,"TOPLEFT",L,y)
    maEnBtn:SetScript("OnClick",function()
        local v = not ns.MyAuras:GetEnabled()
        ns.MyAuras:SetEnabled(v)
        maEnBtn:SetText(v and "|cff44ff88Anzeigen: ON|r" or "|cffff6666Anzeigen: OFF|r")
    end)

    local pvBtn = Btn(parent,120,26,
        ns.MyAuras:IsPreview() and "|cff44ff88Preview: ON|r" or "|cffff6666Preview: OFF|r")
    pvBtn:SetPoint("LEFT",maEnBtn,"RIGHT",6,0)
    pvBtn:SetScript("OnClick",function()
        ns.MyAuras:TogglePreview()
        pvBtn:SetText(ns.MyAuras:IsPreview() and "|cff44ff88Preview: ON|r" or "|cffff6666Preview: OFF|r")
    end)

    local maLkBtn = Btn(parent,120,26,
        maGet("locked",false) and "|cffff6666Locked|r" or "|cff44ff88Unlocked|r")
    maLkBtn:SetPoint("LEFT",pvBtn,"RIGHT",6,0)
    maLkBtn:SetScript("OnClick",function()
        local d=ns.DB(); d.myPrivateAuras=d.myPrivateAuras or {}
        d.myPrivateAuras.locked = not maGet("locked",false)
        maLkBtn:SetText(maGet("locked",false) and "|cffff6666Locked|r" or "|cff44ff88Unlocked|r")
    end)
    y=y-34

    Lbl(parent,"Icon Groesse",L,y); y=y-18
    SL(L,maGet("size",48),16,56,2,function(v)
        local d=ns.DB(); d.myPrivateAuras=d.myPrivateAuras or {}
        d.myPrivateAuras.size=v; ns.MyAuras:SetSize(v) end,
        function(v) return v.."px" end)
    y=y-28

    Lbl(parent,"Anzahl Slots",L,y); y=y-18
    SL(L,maGet("count",6),1,10,1,function(v)
        local d=ns.DB(); d.myPrivateAuras=d.myPrivateAuras or {}
        d.myPrivateAuras.count=v; ns.MyAuras:SetCount(v) end)
    y=y-28

    Lbl(parent,"Abstand",L,y); y=y-18
    SL(L,maGet("spacing",4),0,16,1,function(v)
        local d=ns.DB(); d.myPrivateAuras=d.myPrivateAuras or {}
        d.myPrivateAuras.spacing=v; ns.MyAuras:SetSpacing(v) end,
        function(v) return v.."px" end)
    y=y-28

    local growDirs={{id="RIGHT",label="Rechts"},{id="LEFT",label="Links"},
                    {id="UP",label="Oben"},{id="DOWN",label="Unten"}}
    local curGrow = maGet("growDir","RIGHT")
    local curGrowLabel = "Rechts"
    for _,g in ipairs(growDirs) do if g.id==curGrow then curGrowLabel=g.label end end
    Lbl(parent,"Wachstumsrichtung",L,y); y=y-20
    MkDD(parent,L,y,140,growDirs,function(o)
        local d=ns.DB(); d.myPrivateAuras=d.myPrivateAuras or {}
        d.myPrivateAuras.growDir=o.id; ns.MyAuras:SetGrowDir(o.id) end,
        curGrowLabel)
    y=y-34

    return y
end

-- ─────────────────────────────────────────────────────────────────────────
-- TAB: ALERTS  (boss-gruppiert, vollständig user-definiert)
-- ─────────────────────────────────────────────────────────────────────────
local function BuildAlerts(parent, y)
    local db  = ns.DB()
    local L   = 20
    local W   = 540

    -- Migration: alte Presets entfernen
    ns.SpellData.CleanupPresets(db)
    db.spellAlerts = db.spellAlerts or {}

    -- Spells nach Boss-Name gruppieren
    local byBoss = {}
    local totalSpells = 0
    for sid, sa in pairs(db.spellAlerts) do
        local boss = sa.boss or "general"
        if not byBoss[boss] then byBoss[boss] = {} end
        table.insert(byBoss[boss], {id = tonumber(sid) or sid, data = sa})
        totalSpells = totalSpells + 1
    end
    for _, entries in pairs(byBoss) do
        table.sort(entries, function(a,b) return (a.data.name or "") < (b.data.name or "") end)
    end

    -- ── ALERT UEBERSICHT (direkt in parent – kein nested Scroll) ────────────
    SecHdr(parent, "ALERT UEBERSICHT  |cff555555("..totalSpells.." gespeichert)|r", L, y); y = y - 24

    -- ── Spell-Card: Name + ActionType prominent, Alert-Controls kompakt ──────
    local function SpellRow(sid, sa)
        local capSid = sid
        -- Karte: 70px hoch
        -- Zeile 1 Mitte: -17px  → Button-TOP (22px): -6  → FontString-TOP (14px): -10
        -- Separator: -35px
        -- Zeile 2 Mitte: -52px  → Button-TOP (22px): -41 → FontString-TOP (10px): -47
        local CARD_H = 70
        local BTN_H  = 22
        local R1_TOP = -6    -- TOPLEFT y fuer 22px-Buttons in Zeile 1
        local R1_FS  = -10   -- TOPLEFT y fuer 14px-FontString in Zeile 1
        local R1_SFS = -12   -- TOPLEFT y fuer Small-FontString in Zeile 1
        local SEP_Y  = -35
        local R2_TOP = -41   -- TOPLEFT y fuer 22px-Buttons in Zeile 2
        local R2_SFS = -47   -- TOPLEFT y fuer Small-FontString in Zeile 2

        local card = CreateFrame("Frame", nil, parent, "BackdropTemplate")
        card:SetSize(W, CARD_H)
        card:SetPoint("TOPLEFT", parent, "TOPLEFT", L, y)
        card:SetBackdrop({bgFile="Interface\Buttons\WHITE8X8", edgeFile="Interface\Buttons\WHITE8X8", edgeSize=1})
        card:SetBackdropColor(0.08, 0.04, 0.04, 0.6)
        card:SetBackdropBorderColor(C.border[1], C.border[2], C.border[3], 0.5)

        local capSid2 = capSid

        -- ── SPELL ICON (links, ueber beide Zeilen) ─────────────────────────
        local ICON_SZ  = 45            -- 45x45px
        local ICON_SHF = ICON_SZ + 10 -- Offset fuer alle rechten Elemente
        local iconTex  = nil
        if C_Spell and C_Spell.GetSpellInfo then
            local info = C_Spell.GetSpellInfo(sid)
            if info then iconTex = info.iconID end
        end
        if not iconTex and GetSpellTexture then iconTex = GetSpellTexture(sid) end

        local iconBg = card:CreateTexture(nil, "BACKGROUND")
        iconBg:SetSize(ICON_SZ, ICON_SZ)
        iconBg:SetPoint("TOPLEFT", card, "TOPLEFT", 4, -12)
        iconBg:SetColorTexture(0.06, 0.03, 0.03, 1)  -- Fallback-Farbe

        local icon = card:CreateTexture(nil, "ARTWORK")
        icon:SetSize(ICON_SZ, ICON_SZ)
        icon:SetPoint("TOPLEFT", card, "TOPLEFT", 4, -12)
        icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)   -- Blizzard-Border wegschneiden
        if iconTex then icon:SetTexture(iconTex) end

        -- Duenne Border ums Icon
        local iconBorder = card:CreateTexture(nil, "BORDER")
        iconBorder:SetPoint("TOPLEFT",     card, "TOPLEFT",     3,     -11)
        iconBorder:SetPoint("BOTTOMRIGHT", card, "TOPLEFT",     4+ICON_SZ+1, -(12+ICON_SZ+1))
        iconBorder:SetColorTexture(C.border[1], C.border[2], C.border[3], 0.8)

        -- ── ZEILE 1: Toggle | Name | ActionType | >= Thr | X ──────────────
        -- Reihenfolge: zuerst rechte Elemente definieren, dann linke die sie referenzieren

        local en = sa.enabled ~= false
        local tBtn = Btn(card, 38, BTN_H, en and "|cff44ff88ON|r" or "|cffff6666OFF|r")
        tBtn:SetPoint("TOPLEFT", card, "TOPLEFT", ICON_SHF, R1_TOP)
        tBtn:SetScript("OnClick", function()
            local d = ns.DB(); d.spellAlerts[capSid2] = d.spellAlerts[capSid2] or {}
            d.spellAlerts[capSid2].enabled = not (d.spellAlerts[capSid2].enabled or false)
            tBtn:SetText(d.spellAlerts[capSid2].enabled and "|cff44ff88ON|r" or "|cffff6666OFF|r")
        end)

        -- Delete + Threshold ZUERST definieren (werden von anderen referenziert)
        local delB = DBtn(card, 14, BTN_H, "X")
        delB:SetPoint("TOPRIGHT", card, "TOPRIGHT", -2, R1_TOP)
        delB:SetScript("OnClick", function()
            local d = ns.DB(); d.spellAlerts[capSid2] = nil
            AiB.Settings:ShowTab("cotank")
        end)

        local thrEB = EBx(card, 32, BTN_H, true)
        thrEB:SetPoint("TOPRIGHT", card, "TOPRIGHT", -18, R1_TOP)
        thrEB:SetText(sa.threshold or 1)
        thrEB:SetScript("OnEditFocusLost", function(s)
            local v = s:GetNumber()
            if v and v >= 1 then
                local d = ns.DB(); d.spellAlerts[capSid2] = d.spellAlerts[capSid2] or {}
                d.spellAlerts[capSid2].threshold = v
            end
        end)
        thrEB:SetScript("OnEnterPressed", function(s) s:ClearFocus() end)

        -- >= Label: direkt an card TOPRIGHT
        local thrL = card:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        thrL:SetPoint("TOPRIGHT", card, "TOPRIGHT", -54, R1_SFS)
        thrL:SetText(">="); thrL:SetTextColor(C.dim[1], C.dim[2], C.dim[3])

        -- Action-Type: direkt an card TOPRIGHT, 90px Breite, rechtsbuendig
        -- Platz: X(14) + gap(2) + Thr(32) + gap(2) + >=(12) + gap(6) + Action(max ~90px)
        local nc = NC(sa.note)
        local afs = card:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        afs:SetPoint("TOPRIGHT", card, "TOPRIGHT", -72, R1_SFS)
        afs:SetJustifyH("RIGHT")
        afs:SetText(ActionLabel(sa.note)); afs:SetTextColor(nc[1], nc[2], nc[3])

        -- Spell-Name: GameFontHighlight, single TOPLEFT Anchor + SetWidth
        -- (zwei Anchors oder custom SetFont schlagen auf Cards still fehl)
        local nfs = card:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        nfs:SetPoint("TOPLEFT", card, "TOPLEFT", ICON_SHF + 44, R1_SFS)
        nfs:SetWidth(190)
        nfs:SetJustifyH("LEFT")
        nfs:SetText(sa.name or ("Spell "..sid))
        nfs:SetTextColor(0.95, 0.92, 0.88)

        -- Trennlinie: beginnt nach dem Icon
        local sep = card:CreateTexture(nil, "ARTWORK"); sep:SetHeight(1)
        sep:SetPoint("TOPLEFT",  card, "TOPLEFT",  ICON_SHF, SEP_Y)
        sep:SetPoint("TOPRIGHT", card, "TOPRIGHT", -4, SEP_Y)
        sep:SetColorTexture(C.border[1], C.border[2], C.border[3], 0.5)

        -- ── ZEILE 2: Sound: [DD] | Flash | Text | Test ────────────────────
        -- "Sound:" Label links, Dropdown mit Abstand danach
        local sndL = card:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        sndL:SetPoint("TOPLEFT", card, "TOPLEFT", ICON_SHF, R2_SFS)
        sndL:SetText("Sound:"); sndL:SetTextColor(0.75, 0.55, 0.55)

        -- Dropdown mit 58px Abstand vom linken Rand
        local curSound = sa.sound or ns.Alert.DEFAULTS.sound
        local sndDD = MkDD(card, ICON_SHF + 54, R2_TOP, 120, ns.Alert.SOUNDS,
            function(o)
                local d = ns.DB(); d.spellAlerts[capSid2] = d.spellAlerts[capSid2] or {}
                d.spellAlerts[capSid2].sound = o.id
                ns.Alert:PreviewSound(o)
            end,
            ns.Alert:GetSoundLabel(curSound))

        -- Flash Toggle
        local flashVal = sa.flash ~= false
        local flashCB = Btn(card, 76, BTN_H,
            flashVal and "|cff44ff88Flash  ON|r" or "|cffff6666Flash OFF|r")
        flashCB:SetPoint("TOPLEFT", card, "TOPLEFT", ICON_SHF + 188, R2_TOP)
        flashCB:SetScript("OnClick", function()
            local d = ns.DB(); d.spellAlerts[capSid2] = d.spellAlerts[capSid2] or {}
            d.spellAlerts[capSid2].flash = not (d.spellAlerts[capSid2].flash ~= false)
            flashVal = d.spellAlerts[capSid2].flash
            flashCB:SetText(flashVal and "|cff44ff88Flash  ON|r" or "|cffff6666Flash OFF|r")
        end)

        -- Text Toggle
        local textVal = sa.showText ~= false
        local textCB = Btn(card, 70, BTN_H,
            textVal and "|cff44ff88Text  ON|r" or "|cffff6666Text OFF|r")
        textCB:SetPoint("TOPLEFT", card, "TOPLEFT", ICON_SHF + 268, R2_TOP)
        textCB:SetScript("OnClick", function()
            local d = ns.DB(); d.spellAlerts[capSid2] = d.spellAlerts[capSid2] or {}
            d.spellAlerts[capSid2].showText = not (d.spellAlerts[capSid2].showText ~= false)
            textVal = d.spellAlerts[capSid2].showText
            textCB:SetText(textVal and "|cff44ff88Text  ON|r" or "|cffff6666Text OFF|r")
        end)

        -- Test-Button
        local tstB = ABtn(card, 46, BTN_H, "Test")
        tstB:SetPoint("TOPRIGHT", card, "TOPRIGHT", -2, R2_TOP)
        tstB:SetScript("OnClick", function() ns.Alert:TestSpell(capSid2) end)

        y = y - CARD_H - 4
    end

    -- Alle Raids/Bosse aus SpellData (immer anzeigen, auch leere)
    for _, raid in ipairs(ns.SpellData.raids) do
        y = y - 4  -- Luft vor jedem Raid

        -- Raid-Header: GameFontNormal + Unterstreichung
        local rh = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        rh:SetPoint("TOPLEFT", parent, "TOPLEFT", L, y)
        rh:SetTextColor(C.accent[1], C.accent[2], C.accent[3])
        rh:SetText(raid.name:upper()); y = y - 18

        local ul = parent:CreateTexture(nil, "ARTWORK"); ul:SetHeight(1)
        ul:SetPoint("TOPLEFT",  parent, "TOPLEFT",  L,   y)
        ul:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -20, y)
        ul:SetColorTexture(C.accent[1], C.accent[2], C.accent[3], 0.5)
        y = y - 8

        for _, boss in ipairs(raid.bosses) do
            local entries = byBoss[boss.name] or {}

            -- Boss-Header: GameFontHighlight fuer mehr Praesenz
            local bh = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
            bh:SetPoint("TOPLEFT", parent, "TOPLEFT", L + 8, y)
            bh:SetTextColor(C.raidHdr[1], C.raidHdr[2], C.raidHdr[3])
            bh:SetText(boss.name); y = y - 20

            if #entries > 0 then
                for _, entry in ipairs(entries) do
                    SpellRow(entry.id, entry.data)
                end
            else
                local emptyLbl = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                emptyLbl:SetPoint("TOPLEFT", parent, "TOPLEFT", L + 14, y)
                emptyLbl:SetTextColor(C.dim[1], C.dim[2], C.dim[3])
                emptyLbl:SetText("keine Alerts"); y = y - 18
            end
        end
        y = y - 6  -- Abstand zwischen Raids
    end

    -- General / Other (nur wenn Eintraege vorhanden)
    local genEntries = byBoss["general"] or {}
    if #genEntries > 0 then
        local gh = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        gh:SetPoint("TOPLEFT", parent, "TOPLEFT", L, y)
        gh:SetTextColor(C.raidHdr[1], C.raidHdr[2], C.raidHdr[3])
        gh:SetText("General / Other"); y = y - 18
        for _, entry in ipairs(genEntries) do
            SpellRow(entry.id, entry.data)
        end
        y = y - 6
    end

    y = y - 8  -- Abstand vor naechster Sektion

    -- ── ALERT HINZUFUEGEN ─────────────────────────────────────────────────
    SecHdr(parent, "ALERT HINZUFUEGEN", L, y); y = y - 24

    -- Hinweis: Private Auras
    local infoBox = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    infoBox:EnableMouse(false)
    infoBox:SetSize(W, 36)
    infoBox:SetPoint("TOPLEFT", parent, "TOPLEFT", L, y)
    infoBox:SetBackdrop({bgFile="Interface\Buttons\WHITE8X8", edgeFile="Interface\Buttons\WHITE8X8", edgeSize=1})
    infoBox:SetBackdropColor(0.12, 0.08, 0.02, 0.8)
    infoBox:SetBackdropBorderColor(0.6, 0.45, 0.1, 0.8)
    local infoIcon = infoBox:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    infoIcon:SetPoint("LEFT", infoBox, "LEFT", 8, 0)
    infoIcon:SetText("!"); infoIcon:SetTextColor(0.9, 0.7, 0.1)
    local infoText = infoBox:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    infoText:SetPoint("LEFT", infoBox, "LEFT", 22, 0)
    infoText:SetPoint("RIGHT", infoBox, "RIGHT", -8, 0)
    infoText:SetJustifyH("LEFT")
    infoText:SetText("Hinweis: Private Auras (z.B. Blackening Wounds, Gloomtouched) koennen nicht getriggert werden. Nur normale HARMFUL-Debuffs funktionieren.")
    infoText:SetTextColor(0.85, 0.75, 0.5)
    y = y - 44

    Lbl(parent, "Spell ID", L, y)
    Lbl(parent, "Name  |cff555555(auto via Lookup, editierbar)|r", L+110, y); y = y - 18
    local ebId   = EBx(parent, 90, 26, true);  ebId:SetPoint("TOPLEFT", parent, "TOPLEFT", L, y)
    local lkB    = ABtn(parent, 58, 26, "Lookup"); lkB:SetPoint("LEFT", ebId, "RIGHT", 4, 0)
    local ebName = EBx(parent, 266, 26); ebName:SetPoint("LEFT", lkB, "RIGHT", 6, 0)
    ebName:SetMaxLetters(60)
    lkB:SetScript("OnClick", function()
        local sid = ebId:GetNumber()
        local name = LookupSpellName(sid)
        ebName:SetText(name or (sid > 0 and "Spell "..sid or ""))
    end)
    ebId:SetScript("OnEnterPressed", function() lkB:GetScript("OnClick")(); ebName:SetFocus() end)
    y = y - 32

    Lbl(parent, "Boss / Encounter", L, y)
    Lbl(parent, "Action Type", L+300, y)
    Lbl(parent, "Stacks >=", L+470, y); y = y - 20

    -- Zwischentabellen fuer Selektion (Fix fuer Lua Upvalue-Bug)
    local bossSelection  = {value = "general"}
    local actSelection   = {value = ACTION_TYPES[1].id}
    local soundSelection = {value = ns.Alert.DEFAULTS.sound}
    local flashSelection = {value = ns.Alert.DEFAULTS.flash}
    local textSelection  = {value = ns.Alert.DEFAULTS.showText}

    local allBosses = ns.SpellData.GetAllBosses()
    local bossDD = MkDD(parent, L, y, 280, allBosses,
        function(o) bossSelection.value = o.id end,
        "General / Other")

    local actDD = MkDD(parent, L+300, y, 150, ACTION_TYPES,
        function(o) actSelection.value = o.id end,
        ACTION_TYPES[1].label)

    local ebThr = EBx(parent, 50, 26, true)
    ebThr:SetPoint("TOPLEFT", parent, "TOPLEFT", L+470, y)
    ebThr:SetText("2")
    y = y - 32

    -- Zeile 3: Sound / Flash / Text
    Lbl(parent, "Sound", L, y)
    Lbl(parent, "Flash", L+210, y)
    Lbl(parent, "Text", L+280, y); y = y - 20

    local sndDD = MkDD(parent, L, y, 195, ns.Alert.SOUNDS,
        function(o)
            soundSelection.value = o.id
            ns.Alert:PreviewSound(o)
        end,
        ns.Alert:GetSoundLabel(ns.Alert.DEFAULTS.sound))

    local flashCB = Btn(parent, 60, 24,
        flashSelection.value and "|cff44ff88ON|r" or "|cffff6666OFF|r")
    flashCB:SetPoint("TOPLEFT", parent, "TOPLEFT", L+210, y)
    flashCB:SetScript("OnClick", function()
        flashSelection.value = not flashSelection.value
        flashCB:SetText(flashSelection.value and "|cff44ff88ON|r" or "|cffff6666OFF|r")
    end)

    local textCB = Btn(parent, 60, 24,
        textSelection.value and "|cff44ff88ON|r" or "|cffff6666OFF|r")
    textCB:SetPoint("TOPLEFT", parent, "TOPLEFT", L+280, y)
    textCB:SetScript("OnClick", function()
        textSelection.value = not textSelection.value
        textCB:SetText(textSelection.value and "|cff44ff88ON|r" or "|cffff6666OFF|r")
    end)
    y = y - 32

    local addBtn = ABtn(parent, 160, 28, "+ Alert hinzufuegen")
    addBtn:SetPoint("TOPLEFT", parent, "TOPLEFT", L, y)
    addBtn:SetScript("OnClick", function()
        local sid  = ebId:GetNumber()
        local name = ebName:GetText():match("^%s*(.-)%s*$")
        local thr  = ebThr:GetNumber()
        local boss = bossSelection.value  or "general"
        local note = actSelection.value   or "custom"
        local snd  = soundSelection.value or ns.Alert.DEFAULTS.sound
        if not sid or sid <= 0 then return end
        if name == "" then name = LookupSpellName(sid) or ("Spell "..sid) end
        if not thr or thr < 1 then thr = 1 end
        local d = ns.DB(); d.spellAlerts = d.spellAlerts or {}
        d.spellAlerts[sid] = {
            enabled   = true,
            threshold = thr,
            name      = name,
            note      = note,
            boss      = boss,
            custom    = true,
            sound     = snd,
            flash     = flashSelection.value,
            showText  = textSelection.value,
        }
        AiB.Settings:ShowTab("cotank")
    end)
    y = y - 40

    -- ── ALERT EINSTELLUNGEN ───────────────────────────────────────────────
    -- Text-Prefix: der Text der auf dem Bildschirm erscheint wenn ein Alert ausgeloest wird.
    -- Ausloesebedingung: ein aktivierter Spell erreicht den gesetzten Stack-Threshold.
    -- Action Type (Taunt, Tank Swap etc.) ist nur ein Label fuer die Uebersicht, kein Filter.

    SecHdr(parent, "ALERT EINSTELLUNGEN", L, y); y = y - 24
    local d1 = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    d1:SetPoint("TOPLEFT", parent, "TOPLEFT", L, y)
    d1:SetText("Feuert wenn ein aktivierter Spell den Stack-Threshold erreicht. Action Type ist nur ein Label.")
    d1:SetTextColor(C.dim[1], C.dim[2], C.dim[3])
    y = y - 18

    Lbl(parent, "Text-Prefix  |cff555555(erscheint auf dem Bildschirm)|r", L, y); y = y - 18
    local ebMsg = EBx(parent, 190, 26)
    ebMsg:SetPoint("TOPLEFT", parent, "TOPLEFT", L, y)
    ebMsg:SetText(db.alertText or "TAUNT")
    local saveB = ABtn(parent, 56, 26, "Save"); saveB:SetPoint("LEFT", ebMsg, "RIGHT", 6, 0)
    local testB = ABtn(parent, 96, 26, "Test Alert"); testB:SetPoint("LEFT", saveB, "RIGHT", 8, 0)
    y = y - 34

    Lbl(parent, "Alert font size", L, y); y = y - 18
    local alSl = MkSl(parent, L, y, 222, 12, 48, 1)
    alSl:SetValue(ns.SettingNumber("alertTextSize", 22))
    local alVt = VT(parent, alSl); alVt:SetText(ns.SettingNumber("alertTextSize", 22))
    alSl:SetScript("OnValueChanged", function(_, v)
        v = math.floor(v + 0.5); alVt:SetText(v); ns.Alert:SetTextSize(v)
    end)
    y = y - 28

    saveB:SetScript("OnClick", function() db.alertText = ebMsg:GetText(); ebMsg:ClearFocus() end)
    ebMsg:SetScript("OnEnterPressed", function(s) db.alertText = s:GetText(); s:ClearFocus() end)
    ebMsg:SetScript("OnEditFocusLost", function(s) db.alertText = s:GetText() end)
    testB:SetScript("OnClick", function() ns.Alert:Test() end)

    return y
end

local function BuildTools(parent,y)
    local db=ns.DB(); local L=20
    local function gF() return AiB.CoTank.frame end

    SecHdr(parent,"TEST MODE",L,y); y=y-24
    local tBtn=ABtn(parent,170,28,ns.isTestMode and "Test Mode: ON" or "Test Mode: OFF")
    tBtn:SetPoint("TOPLEFT",parent,"TOPLEFT",L,y)
    tBtn:SetScript("OnClick",function()
        ns.isTestMode=not ns.isTestMode; tBtn:SetText(ns.isTestMode and "Test Mode: ON" or "Test Mode: OFF")
        local f=gF(); if f then
            if ns.isTestMode then
                UnregisterUnitWatch(f)
                f:SetAttribute("unit","player")
                f:Show()
                -- C_Timer.After(0) wartet einen Frame bis Show() und SecureTemplate gesettled sind
                C_Timer.After(0, function()
                    if ns.isTestMode then
                        f:AttachPrivateAnchors()
                        f:UpdateVisuals()
                    end
                end)
            else
                f:SetAttribute("unit",ns.FindCoTank())
                RegisterUnitWatch(f)
                f:UpdateVisuals()
            end
        end
    end); y=y-36

    SecHdr(parent,"FRAME LOCK",L,y); y=y-24
    local lk=db.frameLocked or false
    local lkBtn=Btn(parent,170,28,lk and "Frame: LOCKED" or "Frame: UNLOCKED")
    lkBtn:SetPoint("TOPLEFT",parent,"TOPLEFT",L,y)
    lkBtn.label:SetTextColor(lk and C.warn[1] or C.ok[1],lk and C.warn[2] or C.ok[2],lk and C.warn[3] or C.ok[3])
    lkBtn:SetScript("OnClick",function()
        local d=ns.DB(); d.frameLocked=not(d.frameLocked or false); lk=d.frameLocked
        lkBtn:SetText(lk and "Frame: LOCKED" or "Frame: UNLOCKED")
        lkBtn.label:SetTextColor(lk and C.warn[1] or C.ok[1],lk and C.warn[2] or C.ok[2],lk and C.warn[3] or C.ok[3])
    end); y=y-36

    SecHdr(parent,"PIN CO-TANK",L,y); y=y-24
    local pnL=parent:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
    pnL:SetPoint("TOPLEFT",parent,"TOPLEFT",L,y); pnL:SetTextColor(C.text[1],C.text[2],C.text[3])
    local pn=db.pinnedTank
    if pn then pnL:SetText("Pinned: |cffff6644"..pn.."|r")
    else local ct=ns.FindCoTank(); pnL:SetText("Auto-detect: |cffff6644"..((ct and UnitName(ct)) or "none").."|r") end
    y=y-20
    local pB=ABtn(parent,110,26,"Pin Current"); pB:SetPoint("TOPLEFT",parent,"TOPLEFT",L,y); pB.label:SetTextColor(C.ok[1],C.ok[2],C.ok[3])
    local uB=DBtn(parent,80,26,"Unpin"); uB:SetPoint("LEFT",pB,"RIGHT",6,0)
    local pEB=EBx(parent,160,26); pEB:SetPoint("LEFT",uB,"RIGHT",10,0); pEB:SetMaxLetters(60)
    local pNB=ABtn(parent,72,26,"Pin Name"); pNB:SetPoint("LEFT",pEB,"RIGHT",6,0); pNB.label:SetTextColor(C.ok[1],C.ok[2],C.ok[3])
    local function AP(name)
        name=name and name:match("^%s*(.-)%s*$"); if not name or name=="" then return end
        ns.DB().pinnedTank=name; pnL:SetText("Pinned: |cffff6644"..name.."|r"); pEB:SetText(""); pEB:ClearFocus()
        -- Live-Update: Frame sofort auf neuen Co-Tank umschalten
        local f=AiB.CoTank.frame
        if f and not InCombatLockdown() then
            local newUnit=ns.FindCoTank()
            if newUnit then f:SetAttribute("unit",newUnit); RegisterUnitWatch(f) end
        end
    end
    pB:SetScript("OnClick",function() local ct=ns.FindCoTank(); local nm=ct and UnitName(ct); if nm then AP(nm) end end)
    uB:SetScript("OnClick",function()
        ns.DB().pinnedTank=nil; pEB:SetText("")
        local ct=ns.FindCoTank(); pnL:SetText("Auto-detect: |cffff6644"..((ct and UnitName(ct)) or "none").."|r")
        -- Live-Update: Frame sofort auf Auto-detect umschalten
        local f=AiB.CoTank.frame
        if f and not InCombatLockdown() then
            local newUnit=ns.FindCoTank()
            if newUnit then f:SetAttribute("unit",newUnit); RegisterUnitWatch(f)
            else UnregisterUnitWatch(f) end
        end
    end)
    pNB:SetScript("OnClick",function() AP(pEB:GetText()) end)
    pEB:SetScript("OnEnterPressed",function(s) AP(s:GetText()) end); y=y-36

    SecHdr(parent,"POSITION & INTERACTION",L,y); y=y-24
    local rB=DBtn(parent,150,28,"Reset Position"); rB:SetPoint("TOPLEFT",parent,"TOPLEFT",L,y)
    rB:SetScript("OnClick",function() if InCombatLockdown() then return end; local f=gF(); if f then ns.ResetPosition(f) end end)
    local ct3=db.clickThrough or false
    local ctB=Btn(parent,170,28,ct3 and "Click-Through: ON" or "Click-Through: OFF"); ctB:SetPoint("LEFT",rB,"RIGHT",10,0)
    ctB.label:SetTextColor(ct3 and C.warn[1] or C.ok[1],ct3 and C.warn[2] or C.ok[2],ct3 and C.warn[3] or C.ok[3])
    ctB:SetScript("OnClick",function()
        local d=ns.DB(); d.clickThrough=not(d.clickThrough or false); ct3=d.clickThrough
        ctB:SetText(ct3 and "Click-Through: ON" or "Click-Through: OFF")
        ctB.label:SetTextColor(ct3 and C.warn[1] or C.ok[1],ct3 and C.warn[2] or C.ok[2],ct3 and C.warn[3] or C.ok[3])
        local f=gF(); if f then f:EnableMouse(not ct3) end
    end); y=y-46
    return y
end

-- ── Public API ────────────────────────────────────────────────────────────
ns.Options={}
function ns.Options:Initialize() end
function ns.Options:AddToSettingsPanel(parent, yOffset)
    local L=20; local y=BuildTabBar(parent,L,yOffset or -10)
    if     ns.activeInnerTab=="general" then y=BuildGeneral(parent,y)
    elseif ns.activeInnerTab=="alerts"  then y=BuildAlerts(parent,y)
    elseif ns.activeInnerTab=="tools"   then y=BuildTools(parent,y)
    end
    return y
end
function ns.Options:Open()
    if AiB.Settings then AiB.Settings:Show(); AiB.Settings:ShowTab("cotank") end
end
AiB.CoTank.OpenOptions=function() ns.Options:Open() end
