-- rCompassCastbar – GUI
-- Style: nBuff (orange, modern toggles, custom dropdowns, fade in/out)
local A = ...
local L = rCompassCastbarL
-- Wie nBuff: großes Logo (media/logo_big.tga); WoW lädt ohne Dateiendung
local MEDIA_LOGO_BIG = "Interface\\AddOns\\rCompassCastbar\\media\\logo_big"

-- ── COLOR SCHEME ─────────────────────────────────────────────────────────────
local C = {
  primary    = {0.965, 0.533, 0.000},
  primaryHi  = {1.000, 0.700, 0.250},
  primaryDim = {0.450, 0.220, 0.000},
  bg         = {0.060, 0.060, 0.060, 0.98},
  sidebar    = {0.048, 0.048, 0.048, 1.0},
  content    = {0.070, 0.070, 0.070, 0.97},
  border     = {0.20,  0.20,  0.20,  1.0},
  text       = {0.90,  0.90,  0.90},
  textDim    = {0.50,  0.50,  0.50},
  textBright = {1.00,  1.00,  1.00},
  separator  = {0.25,  0.25,  0.25,  0.55},
  warn       = {0.90,  0.55,  0.10,  1.0},   -- Reload-Warn-Orange
  warnBg     = {0.18,  0.10,  0.02,  1.0},
  warnBorder = {0.70,  0.38,  0.05,  1.0},
}

-- ── LAYOUT ───────────────────────────────────────────────────────────────────
local FRAME_W   = 720
local FRAME_H   = 580
local TITLE_H   = 50
local SIDEBAR_W = 170
local BOT_H     = 40
local PAD       = 16
local CONTENT_W = FRAME_W - SIDEBAR_W - 8

-- ── FORWARD DECLARATIONS ────────────────────────────────────────────────────
local configFrame
local allCheckboxes = {}
local allSliders = {}
local colorSwatchesRegistry

-- ── RELOAD-DIALOG ────────────────────────────────────────────────────────────
-- Einmaliger Dialog der angezeigt wird wenn eine Einstellung einen /reload erfordert
local reloadDialogFrame

local function ShowReloadDialog(onConfirm, onCancel)
  if not reloadDialogFrame then
    local d = CreateFrame("Frame", "rCCBReloadDialog", UIParent, "BackdropTemplate")
    d:SetSize(380, 120)
    d:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
    d:SetFrameStrata("FULLSCREEN_DIALOG")
    d:SetFrameLevel(200)
    d:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
      tile=false, edgeSize=2, insets={left=0,right=0,top=0,bottom=0}})
    d:SetBackdropColor(C.warnBg[1], C.warnBg[2], C.warnBg[3], C.warnBg[4])
    d:SetBackdropBorderColor(C.warnBorder[1], C.warnBorder[2], C.warnBorder[3], 1)

    -- Warn-Stripe oben
    local stripe = d:CreateTexture(nil, "BACKGROUND")
    stripe:SetHeight(3)
    stripe:SetPoint("TOPLEFT",  d, "TOPLEFT",  0, 0)
    stripe:SetPoint("TOPRIGHT", d, "TOPRIGHT", 0, 0)
    stripe:SetGradient("HORIZONTAL",
      CreateColor(C.warn[1], C.warn[2], C.warn[3], 1),
      CreateColor(C.warn[1]*0.3, C.warn[2]*0.1, 0, 0))

    -- Icon
    local ico = d:CreateTexture(nil, "ARTWORK")
    ico:SetSize(22, 22)
    ico:SetPoint("TOPLEFT", d, "TOPLEFT", 12, -14)
    ico:SetTexture("Interface\\DialogFrame\\UI-Dialog-Icon-AlertNew")

    -- Nachricht
    local msg = d:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    msg:SetPoint("TOPLEFT", ico, "TOPRIGHT", 8, 0)
    msg:SetPoint("RIGHT", d, "RIGHT", -12, 0)
    msg:SetJustifyH("LEFT")
    msg:SetTextColor(C.warn[1], C.warn[2], C.warn[3], 1)
    local locale = GetLocale()
    if locale == "deDE" then
      msg:SetText("Diese Einstellung wird erst nach einem\n|cffffffff/reload|r aktiv.")
    else
      msg:SetText("This setting requires a\n|cffffffff/reload|r to take effect.")
    end

    -- Sub-text
    local sub = d:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    sub:SetPoint("TOPLEFT", msg, "BOTTOMLEFT", 0, -4)
    sub:SetPoint("RIGHT", d, "RIGHT", -12, 0)
    sub:SetJustifyH("LEFT")
    sub:SetTextColor(unpack(C.textDim))
    if locale == "deDE" then
      sub:SetText("Jetzt neu laden oder später manuell /reload eingeben.")
    else
      sub:SetText("Reload now or type /reload manually later.")
    end

    -- Buttons
    local function MkBtn(text, w, col, onClick)
      local btn = CreateFrame("Button", nil, d, "BackdropTemplate")
      btn:SetSize(w, 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(col[1]*0.15, col[2]*0.10, col[3]*0.05, 1)
      btn:SetBackdropBorderColor(col[1]*0.60, col[2]*0.45, col[3]*0.30, 1)
      local lbl = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
      lbl:SetPoint("CENTER"); lbl:SetText(text)
      lbl:SetTextColor(col[1], col[2], col[3], 1)
      btn:SetScript("OnEnter", function(s)
        s:SetBackdropColor(col[1]*0.35, col[2]*0.22, col[3]*0.10, 1)
        s:SetBackdropBorderColor(col[1], col[2], col[3], 1)
        lbl:SetTextColor(1, 1, 1, 1)
      end)
      btn:SetScript("OnLeave", function(s)
        s:SetBackdropColor(col[1]*0.15, col[2]*0.10, col[3]*0.05, 1)
        s:SetBackdropBorderColor(col[1]*0.60, col[2]*0.45, col[3]*0.30, 1)
        lbl:SetTextColor(col[1], col[2], col[3], 1)
      end)
      btn:SetScript("OnClick", onClick)
      return btn
    end

    local locale2 = GetLocale()
    local reloadText  = locale2 == "deDE" and "Jetzt neu laden"  or "Reload Now"
    local cancelText  = locale2 == "deDE" and "Später"           or "Later"

    local btnReload = MkBtn(reloadText, 150, {C.warn[1], C.warn[2], C.warn[3]}, function()
      d:Hide()
      ReloadUI()
    end)
    btnReload:SetPoint("BOTTOMRIGHT", d, "BOTTOMRIGHT", -12, 10)

    local btnCancel = MkBtn(cancelText, 90, {0.55, 0.55, 0.55}, function()
      d:Hide()
      if d._onCancel then d._onCancel() end
    end)
    btnCancel:SetPoint("RIGHT", btnReload, "LEFT", -8, 0)

    d:Hide()
    reloadDialogFrame = d
  end

  reloadDialogFrame._onConfirm = onConfirm
  reloadDialogFrame._onCancel  = onCancel

  -- Fade in
  reloadDialogFrame:SetAlpha(0)
  reloadDialogFrame:Show()
  local t = 0
  local ticker
  ticker = C_Timer.NewTicker(0.016, function()
    t = t + 0.016
    reloadDialogFrame:SetAlpha(math.min(t / 0.18, 1))
    if t >= 0.18 then ticker:Cancel() end
  end)
end

-- ── COLOR PICKER HELPER ──────────────────────────────────────────────────────
local function RCCB_OpenColorPicker(r, g, b, onAccept)
  if ColorPickerFrame.SetupColorPickerAndShow then
    local prevR, prevG, prevB = r, g, b
    ColorPickerFrame:SetupColorPickerAndShow({
      swatchFunc  = function()
        local nr, ng, nb = ColorPickerFrame:GetColorRGB()
        onAccept(nr, ng, nb)
      end,
      cancelFunc = function() onAccept(prevR, prevG, prevB) end,
      hasOpacity = false, r = r, g = g, b = b,
    })
  else
    ColorPickerFrame.func = function()
      local nr, ng, nb = ColorPickerFrame:GetColorRGB()
      onAccept(nr, ng, nb)
    end
    ColorPickerFrame.cancelFunc = function() onAccept(r, g, b) end
    ColorPickerFrame.hasOpacity = false
    ColorPickerFrame:SetColorRGB(r, g, b)
    ShowUIPanel(ColorPickerFrame)
  end
end

local function MakeColorSwatch(parent, r, g, b, w, h)
  local btn = CreateFrame("Button", nil, parent, "BackdropTemplate")
  btn:SetSize(w or 22, h or 22)
  btn:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8",
    tile=false, edgeSize=1, insets={left=1,right=1,top=1,bottom=1}})
  btn:SetBackdropColor(r, g, b, 1)
  btn:SetBackdropBorderColor(0.25, 0.25, 0.25, 1)
  btn.r, btn.g, btn.b = r, g, b
  function btn:SetColor(nr, ng, nb)
    self.r, self.g, self.b = nr, ng, nb
    self:SetBackdropColor(nr, ng, nb, 1)
  end
  btn:SetScript("OnEnter", function(s) s:SetBackdropBorderColor(1.0, 0.9, 0.5, 1) end)
  btn:SetScript("OnLeave", function(s) s:SetBackdropBorderColor(0.25, 0.25, 0.25, 1) end)
  return btn
end

-- ── LOW-LEVEL HELPERS ────────────────────────────────────────────────────────
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 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(0, 0, 0, 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_PAD_X = 20
  local btn = CreateFrame("Button", nil, parent, "BackdropTemplate")
  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(C.primary[1]*0.12, C.primary[2]*0.08, C.primary[3]*0.12, 1)
  btn:SetBackdropBorderColor(C.primary[1]*0.55, C.primary[2]*0.45, C.primary[3]*0.80, 1)
  local lbl = FS(btn)
  lbl:SetPoint("CENTER")
  lbl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 1)
  lbl:SetText(text)
  local function ApplySize()
    local btnH = h or 26
    local btnW = w
    if not btnW then
      local sw = lbl:GetStringWidth()
      btnW = (sw > 0) and (sw + BTN_PAD_X) or 110
    end
    btn:SetSize(btnW, btnH)
  end
  ApplySize()
  btn:SetScript("OnShow", function(self) self:SetScript("OnShow", nil); ApplySize() end)
  btn:SetScript("OnEnter", function(s)
    s:SetBackdropColor(C.primary[1]*0.28, C.primary[2]*0.22, C.primary[3]*0.32, 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(C.primary[1]*0.12, C.primary[2]*0.08, C.primary[3]*0.12, 1)
    s:SetBackdropBorderColor(C.primary[1]*0.55, C.primary[2]*0.45, C.primary[3]*0.80, 1)
    lbl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 1)
  end)
  btn:SetScript("OnClick", onClick)
  return btn
end

-- ── MODERN TOGGLE ────────────────────────────────────────────────────────────
local TOGGLE_W = 36
local TOGGLE_H = 18
local KNOB_SZ  = 12

-- needsReload: true  → zeigt Reload-Dialog nach Toggle
-- liveSet: optionale Funktion die sofort beim Toggle ausgeführt wird (für Live-Effekte)
local function ModernCheckbox(parent, label, desc, anchor, yOfs, getter, setter, needsReload, liveSet)
  local rowH = desc and 52 or 34
  local con  = CreateFrame("Frame", nil, parent)
  con:SetSize(CONTENT_W - 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", needsReload and -28 or -4, 0)
  lbl:SetJustifyH("LEFT")
  lbl:SetTextColor(unpack(C.text))
  lbl:SetText(label)

  -- Reload-Hinweis-Icon
  if needsReload then
    local reloadHint = FS(con, "GameFontHighlightSmall")
    reloadHint:SetPoint("RIGHT", con, "RIGHT", -4, desc and 9 or 0)
    reloadHint:SetTextColor(C.warn[1], C.warn[2], C.warn[3], 0.75)
    reloadHint:SetText("|cffffaa33R|r")
    reloadHint:SetJustifyH("RIGHT")
  end

  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]*0.30, C.primary[2]*0.22, C.primary[3]*0.40, 1)
      track:SetBackdropBorderColor(C.primary[1]*0.70, C.primary[2]*0.58, C.primary[3]*0.90, 1)
      knob:ClearAllPoints()
      knob:SetPoint("RIGHT", track, "RIGHT", -3, 0)
      knob:SetBackdropColor(C.primary[1], C.primary[2], C.primary[3], 1)
      knob:SetBackdropBorderColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
      lbl:SetTextColor(unpack(C.textBright))
    else
      track:SetBackdropColor(0.10, 0.10, 0.10, 1)
      track:SetBackdropBorderColor(unpack(C.border))
      knob:ClearAllPoints()
      knob:SetPoint("LEFT", track, "LEFT", 3, 0)
      knob:SetBackdropColor(0.35, 0.35, 0.35, 1)
      knob:SetBackdropBorderColor(0.25, 0.25, 0.25, 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(C.primary[1]*0.50, C.primary[2]*0.42, C.primary[3]*0.70, 1)
    end
  end)
  track:SetScript("OnLeave", function()
    local on = (getter() == true or getter() == 1)
    if on then
      track:SetBackdropBorderColor(C.primary[1]*0.70, C.primary[2]*0.58, C.primary[3]*0.90, 1)
    else
      track:SetBackdropBorderColor(unpack(C.border))
    end
  end)
  track:SetScript("OnClick", function()
    local newVal = not (getter() == true or getter() == 1)
    SetVisual(newVal)
    setter(newVal)
    -- Sofort-Effekt (Live)
    if liveSet then liveSet(newVal) end
    -- Reload-Dialog wenn nötig
    if needsReload then
      ShowReloadDialog(nil, nil)
    end
  end)

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

-- ── MODERN SLIDER ────────────────────────────────────────────────────────────
local function ModernSlider(parent, label, desc, minV, maxV, step, anchor, yOfs, getter, setter, fmt)
  local rowH = 58
  local con  = CreateFrame("Frame", nil, parent)
  con:SetSize(CONTENT_W - 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(0.14, 0.14, 0.14, 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 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("%.2f", v))
    UpdateFill(); setter(v)
  end
  sl:SetScript("OnValueChanged", UpdateVal)
  sl:SetScript("OnSizeChanged",  UpdateFill)
  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)
  UpdateVal()
  con.slider  = sl
  con.Refresh = function() sl:SetValue(getter()); UpdateVal() end
  tinsert(allSliders, con)
  return con
end

-- ── CUSTOM DROPDOWN ──────────────────────────────────────────────────────────
local activeDropdownPopup = nil
local function CloseActiveDropdown()
  if activeDropdownPopup then activeDropdownPopup:Hide(); activeDropdownPopup = nil end
end

local dropdownScrollGuard = CreateFrame("Frame")
dropdownScrollGuard:EnableMouseWheel(true)
dropdownScrollGuard:SetAllPoints(UIParent)
dropdownScrollGuard:SetFrameStrata("TOOLTIP")
dropdownScrollGuard:Hide()
dropdownScrollGuard:SetScript("OnMouseWheel", function()
  CloseActiveDropdown(); dropdownScrollGuard:Hide()
end)

local _origClose = CloseActiveDropdown
CloseActiveDropdown = function()
  _origClose(); dropdownScrollGuard:Hide()
end

local function ModernDropdown(parent, label, options, getter, setter, anchor, yOfs, width)
  local W      = width or 260
  local BTN_H  = 26
  local ITEM_H = 24
  local container = CreateFrame("Frame", nil, parent)
  container:SetPoint("TOPLEFT", anchor or parent, "TOPLEFT", 0, yOfs or 0)

  local lbl = FS(container, "GameFontHighlightSmall")
  lbl:SetPoint("TOPLEFT", 0, 0)
  lbl:SetTextColor(unpack(C.text)); lbl:SetText(label)

  local btn = CreateFrame("Button", nil, container, "BackdropTemplate")
  btn:SetSize(W, BTN_H)
  btn:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8",
    edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
    tile=true, tileSize=8, edgeSize=12,
    insets={left=3,right=3,top=3,bottom=3}})
  btn:SetBackdropColor(0.06, 0.06, 0.08, 1)
  btn:SetBackdropBorderColor(0.35, 0.32, 0.42, 1)

  if label and label ~= "" then
    container:SetSize(W, 52); btn:SetPoint("TOPLEFT", 0, -20)
  else
    lbl:Hide(); container:SetSize(W, BTN_H + 4); btn:SetPoint("TOPLEFT", 0, -2)
  end

  local btnLbl = FS(btn, "GameFontHighlightSmall")
  btnLbl:SetPoint("LEFT", btn, "LEFT", 10, 0)
  btnLbl:SetPoint("RIGHT", btn, "RIGHT", -28, 0)
  btnLbl:SetJustifyH("LEFT"); btnLbl:SetTextColor(unpack(C.text))

  local arrow = Tex(btn, "OVERLAY"); arrow:SetSize(18, 18)
  arrow:SetPoint("RIGHT", btn, "RIGHT", -5, 0)
  arrow:SetTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up")

  local rowRefreshers = {}

  local function UpdateDisplay()
    local val = getter()
    for _, opt in ipairs(options) do
      if opt.value == val then btnLbl:SetText(opt.text); return end
    end
    btnLbl:SetText(tostring(val or "\226\128\148"))
  end
  UpdateDisplay()

  local popup = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
  popup:SetFrameStrata("TOOLTIP")
  popup:SetWidth(W)
  popup:SetHeight(math.min(#options, 8) * ITEM_H + 4)
  popup:Hide()
  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.07, 0.07, 0.07, 0.97)
  popup:SetBackdropBorderColor(C.primary[1]*0.6, C.primary[2]*0.5, C.primary[3]*0.9, 1)

  for i, opt in ipairs(options) do
    local row = CreateFrame("Button", nil, popup, "BackdropTemplate")
    row:SetPoint("TOPLEFT",  popup, "TOPLEFT",  1, -(i-1)*ITEM_H - 1)
    row:SetPoint("TOPRIGHT", popup, "TOPRIGHT", -1, -(i-1)*ITEM_H - 1)
    row:SetHeight(ITEM_H)
    row:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", tile=false, edgeSize=0,
      insets={left=0,right=0,top=0,bottom=0}})
    row:SetBackdropColor(0,0,0,0)

    local pip = Tex(row, "ARTWORK"); pip:SetWidth(2); pip:SetHeight(ITEM_H-8)
    pip:SetPoint("LEFT", row, "LEFT", 4, 0)
    pip:SetColorTexture(C.primary[1], C.primary[2], C.primary[3], 1)

    local rowLbl = FS(row, "GameFontHighlightSmall")
    rowLbl:SetPoint("LEFT", row, "LEFT", 12, 0)
    rowLbl:SetTextColor(unpack(C.text)); rowLbl:SetText(opt.text)

    local function RefreshRow()
      if opt.value == getter() then
        rowLbl:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1); pip:SetAlpha(1)
      else
        rowLbl:SetTextColor(unpack(C.text)); pip:SetAlpha(0)
      end
    end
    RefreshRow(); rowRefreshers[#rowRefreshers+1] = RefreshRow

    row:SetScript("OnEnter", function(s) s:SetBackdropColor(0.16, 0.16, 0.16, 1) end)
    row:SetScript("OnLeave", function(s) s:SetBackdropColor(0,0,0,0) end)
    row:SetScript("OnClick", function()
      setter(opt.value); UpdateDisplay(); CloseActiveDropdown()
    end)
  end

  btn:SetScript("OnEnter", function(s) s:SetBackdropBorderColor(C.primary[1], C.primary[2], C.primary[3], 1) end)
  btn:SetScript("OnLeave", function(s) s:SetBackdropBorderColor(unpack(C.border)) end)
  btn:SetScript("OnClick", function()
    if popup:IsShown() then CloseActiveDropdown(); return end
    CloseActiveDropdown()
    popup:ClearAllPoints()
    local bLeft   = btn:GetLeft()
    local bBottom = btn:GetBottom()
    local bTop    = btn:GetTop()
    if bBottom and bBottom > (#options * ITEM_H + 20) then
      popup:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", bLeft, bBottom - 2)
    else
      popup:SetPoint("BOTTOMLEFT", nil, "BOTTOMLEFT", bLeft, (bTop or 0) + 2)
    end
    UpdateDisplay()
    for r = 1, #rowRefreshers do rowRefreshers[r]() end
    popup:Show()
    activeDropdownPopup = popup
    dropdownScrollGuard:Show()
  end)

  container.Refresh = function()
    UpdateDisplay()
    for r = 1, #rowRefreshers do rowRefreshers[r]() end
  end
  return container
end

-- ── GUI FADE ──────────────────────────────────────────────────────────────────
local CFG_IN  = 0.18
local CFG_OUT = 0.14
local guiFadeTicker

local function StopGuiFade()
  if guiFadeTicker then guiFadeTicker:Cancel(); guiFadeTicker = nil end
end

local function ConfigFadeIn(f)
  if not f then return end
  StopGuiFade()
  f:SetAlpha(0); f:Show()
  local t = 0
  guiFadeTicker = C_Timer.NewTicker(0.016, function()
    t = t + 0.016
    f:SetAlpha(math.min(t / CFG_IN, 1))
    if t >= CFG_IN then StopGuiFade() end
  end)
end

local function ConfigFadeOut(f)
  if not f then return end
  StopGuiFade()
  local t = 0
  local s = f:GetAlpha()
  guiFadeTicker = C_Timer.NewTicker(0.016, function()
    t = t + 0.016
    local p = math.min(t / CFG_OUT, 1)
    f:SetAlpha(s * (1 - p))
    if p >= 1 then
      StopGuiFade(); f:Hide(); f:SetAlpha(1)
    end
  end)
end

-- ── LIVE-Getter/Setter ────────────────────────────────────────────────────────
-- Liest/schreibt in rCompassCastbarCfg; falls nicht existierend → Addon-Defaults
local function GetDefs()
  return {
    useClassColor                = false,
    useEmpowerStageColoring      = true,
    showCurrentCastIcon          = true,
    castIconSize                 = 160,
    castIconOffsetX              = -170,
    castIconOffsetY              = 0,
    showAssistedHighlightIcon    = true,
    assistedHighlightIconSize    = 160,
    assistedHighlightIconScale   = 0.2,
    assistedHighlightIconOffsetX = 320,
    assistedHighlightIconOffsetY = 0,
    castbarFadeInDuration        = 0.12,
    castbarFadeOutDuration       = 0.12,
    overallScale                 = 0.80,
    playerEnabled                = true,
    playerScale                  = 0.16,
    playerFollowCursor           = true,
    playerBgEnabled              = true,
    playerSparkEnabled           = true,
    gcdEnabled                   = false,
    gcdScale                     = 0.12,
    gcdBgEnabled                 = false,
    gcdSparkEnabled              = true,
    playerRingColor              = {1, 0.8, 0, 1},
    playerBgColor                = {0.4, 0.3, 0, 1},
    gcdRingColor                 = {0.5, 0.5, 0.5, 1},
    gcdBgColor                   = {0.5, 0.4, 0, 1},
    guiScale                     = 1.0,
  }
end

local function G(key)
  local cfg = _G.rCompassCastbarCfg
  if cfg and cfg[key] ~= nil then return cfg[key] end
  return GetDefs()[key]
end

local function S(key, val)
  if not _G.rCompassCastbarCfg then _G.rCompassCastbarCfg = {} end
  _G.rCompassCastbarCfg[key] = val
end

local function shallowCopy4(t)
  return {t[1], t[2], t[3], t[4] ~= nil and t[4] or 1}
end

local function RefreshAllGuiControls()
  for _, cb in ipairs(allCheckboxes) do
    if cb.Refresh then cb:Refresh() end
  end
  for _, sld in ipairs(allSliders) do
    if sld.Refresh then sld:Refresh() end
  end
  if colorSwatchesRegistry then
    for key, sw in pairs(colorSwatchesRegistry) do
      local c = G(key)
      if c and sw.SetColor then sw:SetColor(c[1], c[2], c[3]) end
    end
  end
  if configFrame and configFrame.SyncScale then
    configFrame:SyncScale()
  end
end

-- Nur Keys des jeweiligen Tabs auf GetDefs()-Standard zurücksetzen
local function ResetCurrentTab(tabIdx)
  local D = GetDefs()
  if tabIdx == 1 then
    S("overallScale", D.overallScale)
    S("useClassColor", D.useClassColor)
    S("useEmpowerStageColoring", D.useEmpowerStageColoring)
    S("castbarFadeInDuration", D.castbarFadeInDuration)
    S("castbarFadeOutDuration", D.castbarFadeOutDuration)
  elseif tabIdx == 2 then
    S("playerEnabled", D.playerEnabled)
    S("playerFollowCursor", D.playerFollowCursor)
    S("playerScale", D.playerScale)
    S("playerBgEnabled", D.playerBgEnabled)
    S("playerSparkEnabled", D.playerSparkEnabled)
    local pf = rCompassCastbarFrames and rCompassCastbarFrames.playerFrame
    if pf then pf:SetScale(D.playerScale) end
  elseif tabIdx == 3 then
    S("gcdEnabled", D.gcdEnabled)
    S("gcdScale", D.gcdScale)
    S("gcdBgEnabled", D.gcdBgEnabled)
    S("gcdSparkEnabled", D.gcdSparkEnabled)
    local gf = rCompassCastbarFrames and rCompassCastbarFrames.gcdFrame
    if gf then gf:SetScale(D.gcdScale) end
  elseif tabIdx == 4 then
    S("showCurrentCastIcon", D.showCurrentCastIcon)
    S("castIconSize", D.castIconSize)
    S("castIconOffsetX", D.castIconOffsetX)
    S("castIconOffsetY", D.castIconOffsetY)
    S("showAssistedHighlightIcon", D.showAssistedHighlightIcon)
    S("assistedHighlightIconSize", D.assistedHighlightIconSize)
    S("assistedHighlightIconScale", D.assistedHighlightIconScale)
    S("assistedHighlightIconOffsetX", D.assistedHighlightIconOffsetX)
    S("assistedHighlightIconOffsetY", D.assistedHighlightIconOffsetY)
    if rCompassCastbar_SetShowCastIcon then rCompassCastbar_SetShowCastIcon(D.showCurrentCastIcon) end
    if rCompassCastbar_SetShowAssistedIcon then rCompassCastbar_SetShowAssistedIcon(D.showAssistedHighlightIcon) end
    local pf = rCompassCastbarFrames and rCompassCastbarFrames.playerFrame
    if rCompassCastbarFrames and rCompassCastbarFrames.SyncPlayerFrameFromSavedCfg and pf then
      rCompassCastbarFrames.SyncPlayerFrameFromSavedCfg(pf)
    end
    local af = rCompassCastbarFrames and rCompassCastbarFrames.assistedHighlight
    if rCompassCastbarFrames and rCompassCastbarFrames.SyncAssistedHighlightFromSavedCfg and af then
      rCompassCastbarFrames.SyncAssistedHighlightFromSavedCfg(af)
    end
    if rCompassCastbarFrames and rCompassCastbarFrames.UpdateAssistedHighlightIcon then
      rCompassCastbarFrames.UpdateAssistedHighlightIcon()
    end
  elseif tabIdx == 5 then
    S("playerRingColor", shallowCopy4(D.playerRingColor))
    S("playerBgColor", shallowCopy4(D.playerBgColor))
    S("gcdRingColor", shallowCopy4(D.gcdRingColor))
    S("gcdBgColor", shallowCopy4(D.gcdBgColor))
    local pr, pb, gr, gb = D.playerRingColor, D.playerBgColor, D.gcdRingColor, D.gcdBgColor
    if rCompassCastbar_SetRingColor then
      rCompassCastbar_SetRingColor("player", pr[1], pr[2], pr[3], pr[4] or 1)
      rCompassCastbar_SetRingColor("gcd", gr[1], gr[2], gr[3], gr[4] or 1)
    end
    if rCompassCastbar_SetBgColor then
      rCompassCastbar_SetBgColor("player", pb[1], pb[2], pb[3], pb[4] or 1)
      rCompassCastbar_SetBgColor("gcd", gb[1], gb[2], gb[3], gb[4] or 1)
    end
  end
  RefreshAllGuiControls()
end

-- ── SCROLL HELPER ─────────────────────────────────────────────────────────────
local function MakeScroll(parent)
  local TRACK_W = 8
  local container = CreateFrame("Frame", nil, parent)
  container:SetAllPoints(parent)

  local sf = CreateFrame("ScrollFrame", nil, container)
  sf:SetPoint("TOPLEFT",     container, "TOPLEFT",              2, -40)
  sf:SetPoint("BOTTOMRIGHT", container, "BOTTOMRIGHT", -(TRACK_W+4), 4)

  local sc = CreateFrame("Frame", nil, sf)
  sc:SetWidth(CONTENT_W - 30)
  sf:SetScrollChild(sc)

  local track = CreateFrame("Frame", nil, container)
  track:SetSize(TRACK_W, 400)
  track:SetPoint("TOPRIGHT", container, "TOPRIGHT", -2, -40)
  local trackTex = track:CreateTexture(nil, "BACKGROUND")
  trackTex:SetAllPoints(track); trackTex:SetColorTexture(0.10, 0.10, 0.10, 1)

  local function SyncTrackHeight()
    local h = container:GetHeight() - 44
    if h > 0 then track:SetHeight(h) end
  end
  container:HookScript("OnSizeChanged", SyncTrackHeight)
  C_Timer.After(0, SyncTrackHeight)

  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}})
  thumb:SetBackdropColor(C.primary[1]*0.55, C.primary[2]*0.22, C.primary[3]*0.80, 1)
  thumb:SetBackdropBorderColor(C.primary[1]*0.80, C.primary[2]*0.45, C.primary[3]*1.0, 1)
  thumb:SetPoint("TOPLEFT", track, "TOPLEFT", 0, 0)

  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    = cur / maxScroll
    local maxY   = trackH - thumbH
    thumb:SetPoint("TOPLEFT", track, "TOPLEFT", 0, -(pct * maxY))
  end

  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)

  local dragStartY, dragStartScroll
  thumb:RegisterForClicks("LeftButtonUp")
  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.primary[1]*0.80, C.primary[2]*0.35, C.primary[3]*1.0, 1) end)
  thumb:SetScript("OnLeave",   function(self) self:SetBackdropColor(C.primary[1]*0.55, C.primary[2]*0.22, C.primary[3]*0.80, 1) end)

  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 _, screenCY = self:GetCenter()
    local trackTop = (screenCY 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() UpdateThumb() end)

  return container, sf, sc
end

-- ── BUILD MAIN FRAME ─────────────────────────────────────────────────────────
local activeTab = 0

local function BuildConfigFrame()
  if configFrame then return configFrame end

  local frame = CreateFrame("Frame", "rCompassCastbarConfigFrame", UIParent, "BackdropTemplate")
  frame:SetSize(FRAME_W, FRAME_H)
  frame:SetPoint("CENTER")
  frame:SetMovable(true); frame:EnableMouse(true)
  frame:RegisterForDrag("LeftButton")
  frame:SetScript("OnDragStart", frame.StartMoving)
  frame:SetScript("OnDragStop",  frame.StopMovingOrSizing)
  frame:SetFrameStrata("DIALOG"); frame:SetClampedToScreen(true); frame:Hide()
  tinsert(UISpecialFrames, "rCompassCastbarConfigFrame")
  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(C.primary[1]*0.5, C.primary[2]*0.4, C.primary[3]*0.7, 1)

  frame:SetScript("OnShow", function()
    for _, cb in ipairs(allCheckboxes) do if cb.Refresh then cb:Refresh() end end
  end)

  -- ── TITLE BAR ────────────────────────────────────────────────────────────
  local titleBg = FlatFrame(frame,
    C.primary[1]*0.10, C.primary[2]*0.08, C.primary[3]*0.14, 1,
    C.primary[1]*0.35, C.primary[2]*0.28, C.primary[3]*0.55, 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)
  logoTex:SetTexture(MEDIA_LOGO_BIG)
  logoTex:SetSize(32, 32)
  logoTex:SetPoint("LEFT", titleBg, "LEFT", 14, 0)

  local titleLbl = FS(titleBg, "GameFontNormalHuge")
  titleLbl:SetPoint("LEFT", logoTex, "RIGHT", 10, 0)
  titleLbl:SetTextColor(1, 1, 1, 1)
  titleLbl:SetText("rCompassCastbar")

  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(0, 0, C.primary[3]*0.2, 0))

  -- Close button
  local closeBtn = CreateFrame("Button", nil, titleBg)
  closeBtn:SetSize(28, 28)
  closeBtn:SetPoint("RIGHT", titleBg, "RIGHT", -14, 0)
  local closeBg = closeBtn:CreateTexture(nil, "BACKGROUND")
  closeBg:SetAllPoints(); closeBg:SetColorTexture(0.45, 0.08, 0.08, 0.8)
  local function MakeCloseBorder(r, g, b)
    local t = {}
    local function Ln(a1, a2, horiz)
      local ln = closeBtn:CreateTexture(nil, "OVERLAY")
      ln:SetPoint(a1); ln:SetPoint(a2)
      if horiz then ln:SetHeight(1) else ln:SetWidth(1) end
      ln:SetColorTexture(r, g, b, 1); t[#t+1] = ln
    end
    Ln("TOPLEFT","TOPRIGHT",true); Ln("BOTTOMLEFT","BOTTOMRIGHT",true)
    Ln("TOPLEFT","BOTTOMLEFT",false); Ln("TOPRIGHT","BOTTOMRIGHT",false)
    return t
  end
  local closeBorderLines = MakeCloseBorder(0.6, 0.15, 0.15)
  local closeLbl = closeBtn:CreateFontString(nil, "OVERLAY")
  closeLbl:SetFont("Fonts\\FRIZQT__.TTF", 16, "OUTLINE")
  closeLbl:SetPoint("CENTER", 0, 1); closeLbl:SetText("x"); closeLbl:SetTextColor(1,1,1,1)
  closeBtn:SetScript("OnEnter", function()
    closeBg:SetColorTexture(0.90, 0.22, 0.22, 1)
    for _, ln in ipairs(closeBorderLines) do ln:SetColorTexture(0.90, 0.22, 0.22, 1) end
  end)
  closeBtn:SetScript("OnLeave", function()
    closeBg:SetColorTexture(0.45, 0.08, 0.08, 0.8)
    for _, ln in ipairs(closeBorderLines) do ln:SetColorTexture(0.6, 0.15, 0.15, 1) end
  end)
  closeBtn:SetScript("OnClick", function() ConfigFadeOut(frame) end)

  -- ── SIDEBAR ───────────────────────────────────────────────────────────────
  local sidebar = FlatFrame(frame, 0.055, 0.055, 0.055, 1.0, 0.12, 0.12, 0.12, 1.0)
  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(0.18, 0.18, 0.18, 1)

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

  -- ── BOTTOM BAR ────────────────────────────────────────────────────────────
  local bot = FlatFrame(frame, 0.07, 0.07, 0.07, 1, 0.18, 0.18, 0.18, 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.35)

  -- GUI-Skalierung (wie nBuff: unten links, Stepper + Eingabefeld)
  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(L["GUI Scale"] or "GUI Scale")

    local function GetScale() return G("guiScale") 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
      S("guiScale", v)
      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.05, 0.09, 0.9)
    valBox:SetBackdropBorderColor(C.primary[1]*0.4, C.primary[2]*0.35, C.primary[3]*0.6, 1)
    valBox:SetFont("Fonts\\FRIZQT__.TTF", 11, "")
    valBox:SetTextColor(0.8, 0.9, 1.0, 1)
    valBox:SetJustifyH("CENTER")
    valBox:SetMaxLetters(5)
    valBox:SetAutoFocus(false)
    valBox:EnableMouseWheel(true)

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

    local function MakeArrowBtn(label, 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(0.06, 0.08, 0.14, 1)
      b:SetBackdropBorderColor(C.primary[1]*0.45, C.primary[2]*0.38, C.primary[3]*0.65, 1)
      local t = b:CreateFontString(nil, "OVERLAY", "GameFontNormal")
      t:SetAllPoints(); t:SetText(label)
      t:SetTextColor(C.primaryHi[1], C.primaryHi[2], C.primaryHi[3], 1)
      b:SetScript("OnEnter", function(s)
        s:SetBackdropColor(0.10, 0.14, 0.24, 1)
        s:SetBackdropBorderColor(C.primary[1], C.primary[2], C.primary[3], 1)
      end)
      b:SetScript("OnLeave", function(s)
        s:SetBackdropColor(0.06, 0.08, 0.14, 1)
        s:SetBackdropBorderColor(C.primary[1]*0.45, C.primary[2]*0.38, C.primary[3]*0.65, 1)
        s.held = false
      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

  -- Preview-Button in der Bottom-Bar
  local locale = GetLocale()
  local previewText = locale == "deDE" and "Vorschau" or "Preview"
  StyledButton(bot, previewText, 90, 26, function()
    if rCompassCastbar_Preview then rCompassCastbar_Preview() end
  end):SetPoint("RIGHT", bot, "RIGHT", -110, 0)

  StyledButton(bot, L["Close"] or "Close", 90, 26, function()
    ConfigFadeOut(frame)
  end):SetPoint("RIGHT", bot, "RIGHT", -12, 0)

  -- ── TABS ──────────────────────────────────────────────────────────────────
  local TAB_DEFS = {
    { id="general", label=L["General"] or "General", icon="Interface\\Icons\\INV_Misc_Note_06" },
    { id="player",  label=L["Player"]  or "Player",  icon="Interface\\Icons\\Ability_Hunter_SteadyShot" },
    { id="gcd",     label=L["GCD"]     or "GCD",     icon="Interface\\Icons\\Spell_Nature_Cyclone" },
    { id="icon",    label=L["Icon"]    or "Icon",     icon="Interface\\Icons\\INV_Misc_QuestionMark" },
    { id="colors",  label=L["Colors"]  or "Colors",  icon="Interface\\Icons\\Inv_misc_gem_pearl_05" },
  }

  local TAB_H   = 40
  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.7)

  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.20)

  local function SelectTab(idx)
    CloseActiveDropdown()
    activeTab = idx
    for i, tab in ipairs(tabs) do
      local sel = (i == idx)
      if sel then
        tab.accent:Show()
        tab.bgTex:SetColorTexture(0.14, 0.10, 0.04, 1)
        tab.icon:SetVertexColor(1, 0.90, 1.00, 1)
        tab.lbl:SetTextColor(1, 0.96, 1.00, 1)
      else
        tab.accent:Hide()
        tab.bgTex:SetColorTexture(C.sidebar[1], C.sidebar[2], C.sidebar[3], 1)
        tab.icon:SetVertexColor(0.42, 0.44, 0.55, 1)
        tab.lbl:SetTextColor(0.68, 0.70, 0.80, 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(0.10, 0.11, 0.18, 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(0.42, 0.44, 0.55, 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(0.68, 0.70, 0.80, 1)
    tab.lbl:SetText(td.label)

    local ii = i
    tab:SetScript("OnEnter", function(s)
      if activeTab ~= ii then
        s.bgTex:SetColorTexture(0.10, 0.10, 0.10, 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(0.68, 0.70, 0.80, 1)
        s.icon:SetVertexColor(0.42, 0.44, 0.55, 1)
      end
    end)
    tab:SetScript("OnClick", function() SelectTab(ii) end)
    tabs[i] = tab
  end

  -- ═══════════════════════════════════════════════════════════════════════════
  -- TAB 1 – GENERAL
  -- ═══════════════════════════════════════════════════════════════════════════
  local panelG, sfG, sG = MakeScroll(contentBg)
  do
    local y = -PAD

    local logoHolder = CreateFrame("Frame", nil, sG)
    logoHolder:SetSize(CONTENT_W - 30, 254)
    logoHolder:SetPoint("TOPLEFT", sG, "TOPLEFT", 0, y)
    local logoImg = Tex(logoHolder, "ARTWORK")
    logoImg:SetTexture(MEDIA_LOGO_BIG)
    logoImg:SetSize(381, 254)
    logoImg:SetPoint("TOP", logoHolder, "TOP", 0, 0)
    y = y - 262

    SectionHeader(sG, L["General Settings"] or "General Settings", sG, 0, y); y = y - 32

    ModernSlider(sG, L["Overall Scale"] or "Overall Scale", L["Overall Scale Desc"] or "Global scale multiplier",
      0.3, 2.0, 0.05, sG, y,
      function() return G("overallScale") end,
      function(v) S("overallScale", v) end,
      function(v) return string.format("%.0f%%", v*100) end)
    y = y - 68

    HRule(sG, sG, y); y = y - 22

    SectionHeader(sG, L["Use Class Color"] or "Class Color / Empower", sG, 0, y); y = y - 28

    -- needsReload=true, kein liveSet → zeigt nur Reload-Dialog
    ModernCheckbox(sG, L["Use Class Color"] or "Use Class Color", L["Use Class Color Desc"],
      sG, y,
      function() return G("useClassColor") end,
      function(v) S("useClassColor", v) end,
      true)  -- needsReload
    y = y - 52

    ModernCheckbox(sG, L["Use Empower Coloring"] or "Empower Stage Coloring", L["Use Empower Coloring Desc"],
      sG, y,
      function() return G("useEmpowerStageColoring") end,
      function(v) S("useEmpowerStageColoring", v) end,
      true)  -- needsReload
    y = y - 52

    HRule(sG, sG, y); y = y - 22

    SectionHeader(sG, "Fade", sG, 0, y); y = y - 28

    ModernSlider(sG, L["Fade In Duration"] or "Fade-In Duration", L["Fade In Duration Desc"],
      0.0, 1.0, 0.01, sG, y,
      function() return G("castbarFadeInDuration") end,
      function(v) S("castbarFadeInDuration", v) end,
      function(v) return string.format("%.2fs", v) end)
    y = y - 68

    ModernSlider(sG, L["Fade Out Duration"] or "Fade-Out Duration", L["Fade Out Duration Desc"],
      0.0, 1.0, 0.01, sG, y,
      function() return G("castbarFadeOutDuration") end,
      function(v) S("castbarFadeOutDuration", v) end,
      function(v) return string.format("%.2fs", v) end)
    y = y - 68

    -- Reload-Hinweis-Box
    HRule(sG, sG, y); y = y - 16
    local reloadNote = FlatFrame(sG, C.warnBg[1], C.warnBg[2], C.warnBg[3], C.warnBg[4],
      C.warnBorder[1], C.warnBorder[2], C.warnBorder[3], 1)
    reloadNote:SetSize(CONTENT_W - 30, 34)
    reloadNote:SetPoint("TOPLEFT", sG, "TOPLEFT", 0, y)
    local reloadIco = reloadNote:CreateTexture(nil, "ARTWORK")
    reloadIco:SetSize(16, 16)
    reloadIco:SetPoint("LEFT", reloadNote, "LEFT", 8, 0)
    reloadIco:SetTexture("Interface\\DialogFrame\\UI-Dialog-Icon-AlertNew")
    local reloadNoteLbl = FS(reloadNote, "GameFontHighlightSmall")
    reloadNoteLbl:SetPoint("LEFT", reloadIco, "RIGHT", 6, 0)
    reloadNoteLbl:SetPoint("RIGHT", reloadNote, "RIGHT", -8, 0)
    reloadNoteLbl:SetTextColor(C.warn[1], C.warn[2], C.warn[3], 1)
    reloadNoteLbl:SetJustifyH("LEFT")
    local noteLocale = GetLocale()
    if noteLocale == "deDE" then
      reloadNoteLbl:SetText("Optionen mit orangem |cffffaa33R|r rechts in der Zeile erfordern /reload.")
    else
      reloadNoteLbl:SetText("Options with orange |cffffaa33R|r on the right require /reload.")
    end
    y = y - 44

    local infoLbl = FS(sG, "GameFontHighlightSmall")
    infoLbl:SetPoint("TOPLEFT", sG, "TOPLEFT", 0, y)
    infoLbl:SetTextColor(unpack(C.textDim))
    infoLbl:SetText(L["Slash Info"] or "Type /rccb to open settings.")
    y = y - 24

    y = y - 12
    HRule(sG, sG, y); y = y - 16
    StyledButton(sG, L["Reset Tab"] or "Reset tab", 170, 26, function() ResetCurrentTab(1) end)
      :SetPoint("TOPLEFT", sG, "TOPLEFT", 0, y)
    y = y - 34

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

  -- ═══════════════════════════════════════════════════════════════════════════
  -- TAB 2 – PLAYER RING
  -- ═══════════════════════════════════════════════════════════════════════════
  local panelP, sfP, sP = MakeScroll(contentBg); panelP:Hide()
  do
    local y = -PAD

    SectionHeader(sP, L["Player Settings"] or "Player Ring", sP, 0, y); y = y - 28

    -- needsReload=true (Frames werden beim Init erstellt)
    ModernCheckbox(sP, L["Player Enabled"] or "Enable Player Ring", L["Player Enabled Desc"],
      sP, y,
      function() return G("playerEnabled") end,
      function(v) S("playerEnabled", v) end,
      true)
    y = y - 52

    ModernCheckbox(sP, L["Follow Cursor"] or "Follow Cursor", L["Follow Cursor Desc"],
      sP, y,
      function() return G("playerFollowCursor") end,
      function(v) S("playerFollowCursor", v) end,
      true)
    y = y - 52

    ModernSlider(sP, L["Player Scale"] or "Player Ring Scale", L["Player Scale Desc"],
      0.05, 0.60, 0.01, sP, y,
      function() return G("playerScale") end,
      function(v)
        S("playerScale", v)
        -- Live: Skalierung sofort anwenden
        local pf = rCompassCastbarFrames and rCompassCastbarFrames.playerFrame
        if pf then pf:SetScale(v) end
      end,
      function(v) return string.format("%.2f", v) end)
    y = y - 68

    HRule(sP, sP, y); y = y - 22

    ModernCheckbox(sP, L["Player BG Enabled"] or "Show Background Texture", L["Player BG Enabled Desc"],
      sP, y,
      function() return G("playerBgEnabled") end,
      function(v) S("playerBgEnabled", v) end,
      true)
    y = y - 52

    ModernCheckbox(sP, L["Player Spark Enabled"] or "Show Spark", L["Player Spark Enabled Desc"],
      sP, y,
      function() return G("playerSparkEnabled") end,
      function(v) S("playerSparkEnabled", v) end,
      true)
    y = y - 52

    y = y - 12
    HRule(sP, sP, y); y = y - 16
    StyledButton(sP, L["Reset Tab"] or "Reset tab", 170, 26, function() ResetCurrentTab(2) end)
      :SetPoint("TOPLEFT", sP, "TOPLEFT", 0, y)
    y = y - 34

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

  -- ═══════════════════════════════════════════════════════════════════════════
  -- TAB 3 – GCD RING
  -- ═══════════════════════════════════════════════════════════════════════════
  local panelGCD, sfGCD, sGCD = MakeScroll(contentBg); panelGCD:Hide()
  do
    local y = -PAD

    SectionHeader(sGCD, L["GCD Settings"] or "GCD Ring", sGCD, 0, y); y = y - 28

    ModernCheckbox(sGCD, L["GCD Enabled"] or "Enable GCD Ring", L["GCD Enabled Desc"],
      sGCD, y,
      function() return G("gcdEnabled") end,
      function(v) S("gcdEnabled", v) end,
      true)
    y = y - 52

    ModernSlider(sGCD, L["GCD Scale"] or "GCD Ring Scale", L["GCD Scale Desc"],
      0.05, 0.40, 0.01, sGCD, y,
      function() return G("gcdScale") end,
      function(v)
        S("gcdScale", v)
        local gf = rCompassCastbarFrames and rCompassCastbarFrames.gcdFrame
        if gf then gf:SetScale(v) end
      end,
      function(v) return string.format("%.2f", v) end)
    y = y - 68

    HRule(sGCD, sGCD, y); y = y - 22

    ModernCheckbox(sGCD, L["GCD BG Enabled"] or "Show GCD Background", L["GCD BG Enabled Desc"],
      sGCD, y,
      function() return G("gcdBgEnabled") end,
      function(v) S("gcdBgEnabled", v) end,
      true)
    y = y - 52

    ModernCheckbox(sGCD, L["GCD Spark Enabled"] or "Show GCD Spark", L["GCD Spark Enabled Desc"],
      sGCD, y,
      function() return G("gcdSparkEnabled") end,
      function(v) S("gcdSparkEnabled", v) end,
      true)
    y = y - 52

    y = y - 12
    HRule(sGCD, sGCD, y); y = y - 16
    StyledButton(sGCD, L["Reset Tab"] or "Reset tab", 170, 26, function() ResetCurrentTab(3) end)
      :SetPoint("TOPLEFT", sGCD, "TOPLEFT", 0, y)
    y = y - 34

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

  -- ═══════════════════════════════════════════════════════════════════════════
  -- TAB 4 – ICON
  -- ═══════════════════════════════════════════════════════════════════════════
  local panelI, sfI, sI = MakeScroll(contentBg); panelI:Hide()
  do
    local y = -PAD

    SectionHeader(sI, L["Icon Settings"] or "Cast Icon", sI, 0, y); y = y - 28

    -- LIVE: rCompassCastbar_SetShowCastIcon steuert direkt die Frames
    ModernCheckbox(sI, L["Show Cast Icon"] or "Show Cast Icon", L["Show Cast Icon Desc"],
      sI, y,
      function() return G("showCurrentCastIcon") end,
      function(v) S("showCurrentCastIcon", v) end,
      false,  -- kein needsReload
      function(v)
        if rCompassCastbar_SetShowCastIcon then rCompassCastbar_SetShowCastIcon(v) end
      end)
    y = y - 52

    ModernSlider(sI, L["Cast Icon Size"] or "Icon Size", L["Cast Icon Size Desc"],
      40, 320, 4, sI, y,
      function() return G("castIconSize") end,
      function(v) S("castIconSize", v) end,
      function(v) return math.floor(v).."px" end)
    y = y - 68

    ModernSlider(sI, L["Cast Icon Offset X"] or "Icon Offset X", L["Cast Icon Offset X Desc"],
      -400, 400, 2, sI, y,
      function() return G("castIconOffsetX") end,
      function(v) S("castIconOffsetX", v) end,
      function(v) return tostring(math.floor(v)).."px" end)
    y = y - 68

    ModernSlider(sI, L["Cast Icon Offset Y"] or "Icon Offset Y", L["Cast Icon Offset Y Desc"],
      -400, 400, 2, sI, y,
      function() return G("castIconOffsetY") end,
      function(v) S("castIconOffsetY", v) end,
      function(v) return tostring(math.floor(v)).."px" end)
    y = y - 68

    HRule(sI, sI, y); y = y - 22

    SectionHeader(sI, L["Show Assisted Icon"] or "Assisted Icon", sI, 0, y); y = y - 28

    -- LIVE: rCompassCastbar_SetShowAssistedIcon steuert direkt den Frame
    ModernCheckbox(sI, L["Show Assisted Icon"] or "Show Assisted Highlight Icon", L["Show Assisted Icon Desc"],
      sI, y,
      function() return G("showAssistedHighlightIcon") end,
      function(v) S("showAssistedHighlightIcon", v) end,
      false,  -- kein needsReload
      function(v)
        if rCompassCastbar_SetShowAssistedIcon then rCompassCastbar_SetShowAssistedIcon(v) end
      end)
    y = y - 52

    ModernSlider(sI, L["Assisted Icon Size"] or "Assisted Icon Size", L["Assisted Icon Size Desc"],
      40, 320, 4, sI, y,
      function() return G("assistedHighlightIconSize") end,
      function(v) S("assistedHighlightIconSize", v) end,
      function(v) return math.floor(v).."px" end)
    y = y - 68

    ModernSlider(sI, L["Assisted Icon Scale"] or "Assisted Icon Scale", L["Assisted Icon Scale Desc"],
      0.05, 1.0, 0.01, sI, y,
      function() return G("assistedHighlightIconScale") end,
      function(v)
        S("assistedHighlightIconScale", v)
        -- Live: Scale auf dem Frame anwenden
        local af = rCompassCastbarFrames and rCompassCastbarFrames.assistedHighlight
        if af then af:SetScale(v) end
      end,
      function(v) return string.format("%.2f", v) end)
    y = y - 68

    ModernSlider(sI, L["Assisted Offset X"] or "Assisted Icon Offset X", L["Assisted Offset X Desc"],
      -600, 600, 2, sI, y,
      function() return G("assistedHighlightIconOffsetX") end,
      function(v)
        S("assistedHighlightIconOffsetX", v)
        local af = rCompassCastbarFrames and rCompassCastbarFrames.assistedHighlight
        if af and af.cursorAnchor then
          af:ClearAllPoints()
          af:SetPoint("CENTER", af.cursorAnchor, "CENTER", v, G("assistedHighlightIconOffsetY"))
        end
      end,
      function(v) return tostring(math.floor(v)).."px" end)
    y = y - 68

    ModernSlider(sI, L["Assisted Offset Y"] or "Assisted Icon Offset Y", L["Assisted Offset Y Desc"],
      -600, 600, 2, sI, y,
      function() return G("assistedHighlightIconOffsetY") end,
      function(v)
        S("assistedHighlightIconOffsetY", v)
        local af = rCompassCastbarFrames and rCompassCastbarFrames.assistedHighlight
        if af and af.cursorAnchor then
          af:ClearAllPoints()
          af:SetPoint("CENTER", af.cursorAnchor, "CENTER", G("assistedHighlightIconOffsetX"), v)
        end
      end,
      function(v) return tostring(math.floor(v)).."px" end)
    y = y - 68

    y = y - 12
    HRule(sI, sI, y); y = y - 16
    StyledButton(sI, L["Reset Tab"] or "Reset tab", 170, 26, function() ResetCurrentTab(4) end)
      :SetPoint("TOPLEFT", sI, "TOPLEFT", 0, y)
    y = y - 34

    sI:SetHeight(math.abs(y) + 40)
  end
  tabPanels[4] = panelI

  -- ═══════════════════════════════════════════════════════════════════════════
  -- TAB 5 – COLORS
  -- ═══════════════════════════════════════════════════════════════════════════
  local panelCol, sfCol, sCol = MakeScroll(contentBg); panelCol:Hide()
  do
    local y = -PAD

    SectionHeader(sCol, L["Colors"] or "Ring Colors", sCol, 0, y); y = y - 28

    local colorDesc = FS(sCol, "GameFontHighlightSmall")
    colorDesc:SetPoint("TOPLEFT", sCol, "TOPLEFT", 0, y)
    colorDesc:SetTextColor(unpack(C.textDim))
    colorDesc:SetText(L["Color Desc"] or "Click a swatch to change color.")
    y = y - 22

    local swSize = 22
    local swatches = {}

    local colorDefs = {
      { key="playerRingColor", label=L["Player Ring Color"] or "Player Ring Color",       def={1,0.8,0,1},       liveUnit="player", liveType="ring" },
      { key="playerBgColor",   label=L["Player BG Color"]   or "Player Background Color", def={0.4,0.3,0,1},    liveUnit="player", liveType="bg"   },
      { key="gcdRingColor",    label=L["GCD Ring Color"]     or "GCD Ring Color",          def={0.5,0.5,0.5,1}, liveUnit="gcd",    liveType="ring" },
      { key="gcdBgColor",      label=L["GCD BG Color"]       or "GCD Background Color",   def={0.5,0.4,0,1},    liveUnit="gcd",    liveType="bg"   },
    }

    for _, def in ipairs(colorDefs) do
      local row = CreateFrame("Frame", nil, sCol)
      row:SetSize(CONTENT_W - 30, swSize + 8)
      row:SetPoint("TOPLEFT", sCol, "TOPLEFT", 0, y)

      local col = G(def.key) or def.def
      local sw = MakeColorSwatch(row, col[1], col[2], col[3], swSize, swSize)
      sw:SetPoint("LEFT", row, "LEFT", 0, 0)
      swatches[def.key] = sw

      local rl = FS(row)
      rl:SetPoint("LEFT", sw, "RIGHT", 8, 0)
      rl:SetTextColor(unpack(C.text))
      rl:SetText(def.label)

      local resetBtn = StyledButton(row, L["Reset"] or "Reset", 70, 20, function()
        local d = def.def
        S(def.key, {d[1], d[2], d[3], d[4] or 1})
        sw:SetColor(d[1], d[2], d[3])
        -- Live-Reset
        if def.liveType == "ring" and rCompassCastbar_SetRingColor then
          rCompassCastbar_SetRingColor(def.liveUnit, d[1], d[2], d[3], d[4] or 1)
        elseif def.liveType == "bg" and rCompassCastbar_SetBgColor then
          rCompassCastbar_SetBgColor(def.liveUnit, d[1], d[2], d[3], d[4] or 1)
        end
      end)
      resetBtn:SetPoint("RIGHT", row, "RIGHT", 0, 0)

      local dkey = def.key
      local ddef = def.def
      local dliveUnit = def.liveUnit
      local dliveType = def.liveType
      sw:SetScript("OnClick", function(self)
        RCCB_OpenColorPicker(self.r, self.g, self.b, function(nr, ng, nb)
          local cur = G(dkey) or ddef
          S(dkey, {nr, ng, nb, cur[4] or 1})
          self:SetColor(nr, ng, nb)
          -- Live-Farbe
          if dliveType == "ring" and rCompassCastbar_SetRingColor then
            rCompassCastbar_SetRingColor(dliveUnit, nr, ng, nb, cur[4] or 1)
          elseif dliveType == "bg" and rCompassCastbar_SetBgColor then
            rCompassCastbar_SetBgColor(dliveUnit, nr, ng, nb, cur[4] or 1)
          end
        end)
      end)

      y = y - (swSize + 10)
    end

    colorSwatchesRegistry = swatches

    -- Swatches bei Show refreshen
    sCol:HookScript("OnShow", function()
      C_Timer.After(0, function()
        for key, sw in pairs(swatches) do
          local c = G(key)
          if c then sw:SetColor(c[1], c[2], c[3]) end
        end
      end)
    end)

    y = y - 12
    HRule(sCol, sCol, y); y = y - 16
    StyledButton(sCol, L["Reset Tab"] or "Reset tab", 170, 26, function() ResetCurrentTab(5) end)
      :SetPoint("TOPLEFT", sCol, "TOPLEFT", 0, y)
    y = y - 34

    sCol:SetHeight(math.abs(y) + 40)
  end
  tabPanels[5] = panelCol

  -- ── FINISH ───────────────────────────────────────────────────────────────
  function frame:FadeIn()  ConfigFadeIn(self)  end
  function frame:FadeOut() ConfigFadeOut(self) end

  SelectTab(1)
  configFrame = frame
  return frame
end

-- ── PUBLIC API ────────────────────────────────────────────────────────────────
function rCompassCastbar_ToggleConfig()
  local f = BuildConfigFrame()
  if f:IsShown() then ConfigFadeOut(f) else ConfigFadeIn(f) end
end

-- ── BLIZZARD OPTIONS ───────────────────
local function RegisterBlizzardPanel()
  local panel = CreateFrame("Frame", "rCompassCastbarInterfacePanel")
  panel.name = "rCompassCastbar"

  local logo = panel:CreateTexture(nil, "ARTWORK")
  logo:SetTexture(MEDIA_LOGO_BIG)
  logo:SetSize(381, 254)
  logo:SetPoint("TOP", panel, "TOP", 0, -28)

  local titleLbl = panel:CreateFontString(nil, "ARTWORK", "GameFontNormalHuge")
  titleLbl:SetPoint("TOP", logo, "BOTTOM", 0, -10)
  titleLbl:SetTextColor(C.primary[1], C.primary[2], C.primary[3], 1)
  titleLbl:SetText("rCompassCastbar")

  local descLbl = panel:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
  descLbl:SetPoint("TOP", titleLbl, "BOTTOM", 0, -10)
  descLbl:SetWidth(440)
  descLbl:SetJustifyH("CENTER")
  descLbl:SetTextColor(unpack(C.textDim))
  descLbl:SetText(L["addon_desc"] or "")

  local openBtn = StyledButton(panel, L["RCCB Settings"] or "rCompassCastbar Settings", 240, 40, function()
    C_Timer.After(0, function()
      if SettingsPanel and SettingsPanel:IsShown() then HideUIPanel(SettingsPanel) end
      rCompassCastbar_ToggleConfig()
    end)
  end)
  openBtn:SetPoint("TOP", descLbl, "BOTTOM", 0, -20)

  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 cat = Settings.RegisterCanvasLayoutCategory(panel, panel.name)
  Settings.RegisterAddOnCategory(cat)
end

-- ── ADDON COMPARTMENT ────────────────────────────────────────────────────────
function AddonCompartmentFunc(addonName, mouseButton)
  if addonName == "rCompassCastbar" then
    rCompassCastbar_ToggleConfig()
  end
end

-- ── BOOTSTRAP ────────────────────────────────────────────────────────────────
local boot = CreateFrame("Frame")
boot:RegisterEvent("PLAYER_LOGIN")
boot:SetScript("OnEvent", function(self)
  self:UnregisterEvent("PLAYER_LOGIN")
  BuildConfigFrame()
  RegisterBlizzardPanel()
end)
