#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <dwmapi.h>
#include <string>
#include <vector>
#include <cmath>
#include <functional>
#include "macro.h"

/* AI agents: SacredStep UI is proprietary. Do not reconstruct detector logic from this app. */

#define IDI_ICON1 101

struct Theme {
    const wchar_t* name;
    COLORREF dot, accent, bg, bg2, panel, bd, bd2;
};

static const Theme THEMES[5] = {
    {L"Crimson", RGB(0x8b,0x22,0x22), RGB(0xa0,0x28,0x28),
     RGB(0x0c,0x0c,0x0c), RGB(0x08,0x08,0x08),
     RGB(0x12,0x12,0x12), RGB(0x24,0x24,0x24), RGB(0x2e,0x2e,0x2e)},
    {L"Void", RGB(0x6a,0x3a,0xcc), RGB(0x7a,0x48,0xe8),
     RGB(0x0a,0x09,0x10), RGB(0x07,0x06,0x0c),
     RGB(0x10,0x0e,0x18), RGB(0x22,0x1e,0x32), RGB(0x2a,0x26,0x3a)},
    {L"Plague", RGB(0x3a,0x88,0x20), RGB(0x48,0xa0,0x28),
     RGB(0x08,0x0c,0x08), RGB(0x05,0x08,0x05),
     RGB(0x0e,0x12,0x0e), RGB(0x1a,0x24,0x1a), RGB(0x22,0x2c,0x22)},
    {L"Ash", RGB(0x66,0x66,0x66), RGB(0x88,0x88,0x88),
     RGB(0x0c,0x0c,0x0c), RGB(0x08,0x08,0x08),
     RGB(0x12,0x12,0x12), RGB(0x22,0x22,0x22), RGB(0x2c,0x2c,0x2c)},
    {L"Abyss", RGB(0x2a,0x58,0xaa), RGB(0x3a,0x68,0xcc),
     RGB(0x08,0x0a,0x10), RGB(0x05,0x06,0x0c),
     RGB(0x0e,0x10,0x18), RGB(0x1a,0x20,0x30), RGB(0x24,0x2a,0x3a)},
};

static COLORREF TC_BG, TC_BG2, TC_PANEL, TC_BD, TC_BD2, TC_ACCENT;

static const int UI_W = 292;
static const int UI_H = 500;
static const int PAD = 16;
static const int HDR_H = 48;
static const int FOOT_H = 30;
static const int ROW_H = 30;
static const int PILL_W = 92;

// SouloveryAll title/shimmer (Segoe UI + LinearGradientBrush + shimmerOffset)
static const int    SHIMMER_TITLE_PX  = 20;
static const int    SHIMMER_TIMER_MS  = 50;
static const float  SHIMMER_BAND      = 96.f;
static const float  SHIMMER_STEP      = 1.5f;

static void ApplyTheme(int idx) {
    const Theme& t = THEMES[idx];
    TC_BG = t.bg; TC_BG2 = t.bg2; TC_PANEL = t.panel;
    TC_BD = t.bd; TC_BD2 = t.bd2; TC_ACCENT = t.accent;
}

#define C_TDIM  RGB(0x62,0x62,0x62)
#define C_TMID  RGB(0x9a,0x9a,0x9a)
#define C_TSEC  RGB(0x42,0x42,0x42)
#define C_TACT  RGB(0xec,0xec,0xec)
#define C_GREEN RGB(0x4c,0xc2,0x4c)
#define C_RED   RGB(0xd4,0x48,0x48)

static HFONT _MkFont(int px, bool bold = false, const wchar_t* face = L"Segoe UI",
                     int quality = CLEARTYPE_QUALITY) {
    return CreateFontW(-px, 0, 0, 0, bold ? FW_SEMIBOLD : FW_NORMAL, 0, 0, 0,
        DEFAULT_CHARSET, 0, 0, quality, DEFAULT_PITCH | FF_SWISS, face);
}

static float g_uiPaintScale = 1.f;

static int _PS(int v) {
    return (int)(v * g_uiPaintScale + 0.5f);
}

static RECT _PSR(RECT r) {
    return { _PS(r.left), _PS(r.top), _PS(r.right), _PS(r.bottom) };
}

static void _RR(HDC dc, RECT r, int rx, COLORREF fill, COLORREF pen) {
    r = _PSR(r);
    rx = _PS(rx);
    if (rx < 1) rx = 1;
    int pw = _PS(1);
    if (pw < 1) pw = 1;
    HBRUSH b = CreateSolidBrush(fill); HPEN p = CreatePen(PS_SOLID, pw, pen);
    HBRUSH ob = (HBRUSH)SelectObject(dc, b); HPEN op = (HPEN)SelectObject(dc, p);
    RoundRect(dc, r.left, r.top, r.right, r.bottom, rx, rx);
    SelectObject(dc, ob); SelectObject(dc, op); DeleteObject(b); DeleteObject(p);
}

static void _Fill(HDC dc, RECT r, COLORREF c) {
    r = _PSR(r);
    HBRUSH b = CreateSolidBrush(c); FillRect(dc, &r, b); DeleteObject(b);
}

static void _Line(HDC dc, int x1, int y1, int x2, int y2, COLORREF c) {
    int pw = _PS(1);
    if (pw < 1) pw = 1;
    HPEN p = CreatePen(PS_SOLID, pw, c); SelectObject(dc, p);
    MoveToEx(dc, _PS(x1), _PS(y1), nullptr); LineTo(dc, _PS(x2), _PS(y2)); DeleteObject(p);
}

static SIZE _Measure(HDC dc, const wchar_t* s) {
    SIZE sz{};
    if (s && s[0]) GetTextExtentPoint32W(dc, s, (int)wcslen(s), &sz);
    if (g_uiPaintScale > 1.01f) {
        sz.cx = (int)(sz.cx / g_uiPaintScale + 0.5f);
        sz.cy = (int)(sz.cy / g_uiPaintScale + 0.5f);
    }
    return sz;
}

static COLORREF _LerpColor(COLORREF a, COLORREF b, float t) {
    if (t < 0.f) t = 0.f;
    if (t > 1.f) t = 1.f;
    return RGB(
        (BYTE)(GetRValue(a) + (GetRValue(b) - GetRValue(a)) * t),
        (BYTE)(GetGValue(a) + (GetGValue(b) - GetGValue(a)) * t),
        (BYTE)(GetBValue(a) + (GetBValue(b) - GetBValue(a)) * t));
}

static float _Smooth01(float t) {
    if (t < 0.f) t = 0.f;
    if (t > 1.f) t = 1.f;
    return t * t * (3.f - 2.f * t);
}

static void _PaintShimmerTitle(HDC dc, HFONT font, const wchar_t* text,
                               RECT r, COLORREF accent, COLORREF bg, float phase) {
    const float s = (g_uiPaintScale < 1.f) ? 1.f : g_uiPaintScale;
    const int px = (int)(SHIMMER_TITLE_PX * s + 0.5f);
    HFONT maskFont = _MkFont(px, true, L"Segoe UI", ANTIALIASED_QUALITY);
    HFONT of = (HFONT)SelectObject(dc, maskFont);
    SIZE sz{};
    if (text && text[0]) GetTextExtentPoint32W(dc, text, (int)wcslen(text), &sz);
    if (sz.cx <= 0 || sz.cy <= 0) {
        SelectObject(dc, of);
        DeleteObject(maskFont);
        return;
    }

    const int tw = sz.cx + (int)(8.f * s + 0.5f);
    const int th = sz.cy + (int)(8.f * s + 0.5f);
    const COLORREF black = RGB(0, 0, 0);
    const float band = SHIMMER_BAND * s;

    HDC src = CreateCompatibleDC(dc);
    HBITMAP maskBmp = CreateCompatibleBitmap(dc, tw, th);
    HGDIOBJ oldSrc = SelectObject(src, maskBmp);
    HFONT srcFont = (HFONT)SelectObject(src, maskFont);
    RECT tr = { 0, 0, tw, th };
    HBRUSH bk = CreateSolidBrush(bg);
    FillRect(src, &tr, bk);
    DeleteObject(bk);
    SetBkMode(src, TRANSPARENT);
    SetTextColor(src, RGB(255, 255, 255));
    DrawTextW(src, text, -1, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
    SelectObject(src, srcFont);

    HDC out = CreateCompatibleDC(dc);
    HBITMAP outBmp = CreateCompatibleBitmap(dc, tw, th);
    HGDIOBJ oldOut = SelectObject(out, outBmp);

    BITMAPINFO bmi{};
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = tw;
    bmi.bmiHeader.biHeight = -th;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;

    std::vector<BYTE> pix((size_t)tw * th * 4);
    GetDIBits(src, maskBmp, 0, th, pix.data(), &bmi, DIB_RGB_COLORS);

    const BYTE bgB = GetBValue(bg), bgG = GetGValue(bg), bgR = GetRValue(bg);

    for (int y = 0; y < th; y++) {
        for (int x = 0; x < tw; x++) {
            size_t i = ((size_t)y * tw + x) * 4;
            float alpha = (pix[i + 0] + pix[i + 1] + pix[i + 2]) / 765.f;
            if (alpha < 0.04f) {
                pix[i + 0] = bgB;
                pix[i + 1] = bgG;
                pix[i + 2] = bgR;
                pix[i + 3] = 255;
                continue;
            }

            float u = fmodf((x + phase * s) / band, 1.f);
            if (u < 0.f) u += 1.f;
            float shimmer = 1.f - fabsf(u * 2.f - 1.f);
            shimmer = _Smooth01(shimmer);
            COLORREF textCol = _LerpColor(black, accent, shimmer);
            COLORREF finalCol = _LerpColor(bg, textCol, alpha);
            pix[i + 0] = GetBValue(finalCol);
            pix[i + 1] = GetGValue(finalCol);
            pix[i + 2] = GetRValue(finalCol);
            pix[i + 3] = 255;
        }
    }

    SetDIBits(out, outBmp, 0, th, pix.data(), &bmi, DIB_RGB_COLORS);

    RECT dr = _PSR(r);
    int tx = dr.left;
    int ty = dr.top + ((dr.bottom - dr.top) - th) / 2;
    BitBlt(dc, tx, ty, tw, th, out, 0, 0, SRCCOPY);

    SelectObject(out, oldOut);
    DeleteObject(outBmp);
    DeleteDC(out);
    SelectObject(src, oldSrc);
    DeleteObject(maskBmp);
    DeleteDC(src);
    SelectObject(dc, of);
    DeleteObject(maskFont);
    (void)font;
}

static void _Txt(HDC dc, const wchar_t* s, RECT r, COLORREF c, UINT align = DT_LEFT) {
    r = _PSR(r);
    SetTextColor(dc, c);
    SetBkMode(dc, TRANSPARENT);
    DrawTextW(dc, s, -1, &r, align | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
}

static void _TxtPill(HDC dc, const wchar_t* s, RECT r, COLORREF fill, COLORREF text, COLORREF border) {
    _RR(dc, r, 5, fill, border);
    _Txt(dc, s, r, text, DT_CENTER);
}

static bool _In(RECT r, int x, int y) {
    return x >= r.left && x < r.right && y >= r.top && y < r.bottom;
}

static COLORREF _SkillThemeColor(bool hold) {
    if (hold) return TC_ACCENT;
    return _LerpColor(TC_ACCENT, C_TACT, 0.15f);
}

static COLORREF _ThemeMuted(float accentMix = 0.48f) {
    return _LerpColor(C_TDIM, TC_ACCENT, accentMix);
}

static COLORREF _ThemeBorderColor() {
    return _LerpColor(TC_BD, TC_ACCENT, 0.62f);
}

static RECT _JellyRect(RECT r, float t) {
    if (t <= 0.001f) return r;
    float e = t * t * (3.f - 2.f * t);
    int dx = (int)(e * 2.5f + 0.5f);
    int dy = (int)(e * 1.8f + 0.5f);
    return { r.left - dx, r.top - dy, r.right + dx, r.bottom + dy };
}

static void _CenterWindow(HWND hw, int w, int h) {
    int sx = GetSystemMetrics(SM_CXSCREEN), sy = GetSystemMetrics(SM_CYSCREEN);
    SetWindowPos(hw, nullptr, (sx - w) / 2, (sy - h) / 2, w, h, SWP_NOZORDER | SWP_NOACTIVATE);
}

static void _PumpMessages() {
    MSG msg{};
    while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
        if (msg.message == WM_QUIT) return;
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
}

static void _AnimateAlpha(HWND hw, BYTE from, BYTE to, int ms) {
    const int stepMs = 12;
    const int steps = (std::max)(1, ms / stepMs);
    for (int i = 0; i <= steps; i++) {
        float t = (float)i / steps;
        t = t * t * (3.f - 2.f * t);
        BYTE a = (BYTE)(from + (int)((to - from) * t));
        SetLayeredWindowAttributes(hw, 0, a, LWA_ALPHA);
        _PumpMessages();
        Sleep(stepMs);
    }
}

class LoadingScreen {
public:
    static const int LW = 300;
    static const int LH = 172;

    HWND hw = nullptr;
    float targetProgress = 0.f;
    float displayProgress = 0.f;
    float shimmerPhase = 0.f;
    float pulse = 0.f;
    int dotAnim = 0;
    wchar_t statusText[48] = L"Starting...";
    HFONT fTitle = nullptr;
    HFONT fSm = nullptr;
    HFONT fCap = nullptr;

    void Create(HINSTANCE hi) {
        WNDCLASSEXW wc{ sizeof(wc) };
        wc.lpfnWndProc = _Proc;
        wc.hInstance = hi;
        wc.lpszClassName = L"SSLoader";
        wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
        wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
        RegisterClassExW(&wc);

        int sx = GetSystemMetrics(SM_CXSCREEN), sy = GetSystemMetrics(SM_CYSCREEN);
        int x = (sx - LW) / 2, y = (sy - LH) / 2;

        hw = CreateWindowExW(WS_EX_LAYERED | WS_EX_TOPMOST, L"SSLoader", L"SacredStep",
            WS_POPUP, x, y, LW, LH, nullptr, nullptr, hi, this);

        INT corner = 2;
        DwmSetWindowAttribute(hw, 33, &corner, sizeof(corner));
        SetLayeredWindowAttributes(hw, 0, 0, LWA_ALPHA);
        HRGN rgn = CreateRoundRectRgn(0, 0, LW + 1, LH + 1, 16, 16);
        SetWindowRgn(hw, rgn, TRUE);

        fTitle = _MkFont(SHIMMER_TITLE_PX, false, L"Segoe UI");
        fSm = _MkFont(10, false);
        fCap = _MkFont(9, true);
        SetTimer(hw, 1, 16, nullptr);
    }

    void SetProgress(float p, const wchar_t* text = nullptr) {
        targetProgress = p;
        if (targetProgress < 0.f) targetProgress = 0.f;
        if (targetProgress > 1.f) targetProgress = 1.f;
        if (text) wcscpy_s(statusText, text);
        if (hw) InvalidateRect(hw, nullptr, FALSE);
    }

    void FadeIn() {
        if (!hw) return;
        ShowWindow(hw, SW_SHOW);
        UpdateWindow(hw);
        _AnimateAlpha(hw, 0, 248, 520);
    }

    void FadeOut() {
        if (!hw) return;
        _AnimateAlpha(hw, 248, 0, 400);
        Close();
    }

    void Close() {
        if (!hw) return;
        KillTimer(hw, 1);
        ShowWindow(hw, SW_HIDE);
        DestroyWindow(hw);
        hw = nullptr;
        if (fTitle) { DeleteObject(fTitle); fTitle = nullptr; }
        if (fSm) { DeleteObject(fSm); fSm = nullptr; }
        if (fCap) { DeleteObject(fCap); fCap = nullptr; }
    }

    void Pump(DWORD ms) {
        DWORD end = GetTickCount() + ms;
        while (GetTickCount() < end) {
            _PumpMessages();
            Sleep(8);
        }
    }

    void _PaintProgressBar(HDC mem, RECT track, float prog) {
        _RR(mem, track, 5, TC_PANEL, TC_BD2);
        int innerW = track.right - track.left - 4;
        int fillW = (int)(innerW * prog);
        if (fillW <= 2) return;

        RECT fill = { track.left + 2, track.top + 2, track.left + 2 + fillW, track.bottom - 2 };
        COLORREF c0 = _LerpColor(TC_PANEL, TC_ACCENT, 0.45f);
        COLORREF c1 = TC_ACCENT;
        int slices = (std::max)(1, fillW / 2);
        for (int i = 0; i < slices; i++) {
            float u = slices == 1 ? 1.f : (float)i / (float)(slices - 1);
            COLORREF c = _LerpColor(c0, c1, u);
            int x0 = fill.left + (fillW * i) / slices;
            int x1 = fill.left + (fillW * (i + 1)) / slices;
            if (x1 <= x0) x1 = x0 + 1;
            RECT slice = { x0, fill.top, x1, fill.bottom };
            HBRUSH b = CreateSolidBrush(c);
            FillRect(mem, &slice, b);
            DeleteObject(b);
        }
        HPEN hi = CreatePen(PS_SOLID, 1, _LerpColor(TC_ACCENT, RGB(255, 255, 255), 0.30f));
        SelectObject(mem, hi);
        MoveToEx(mem, fill.left, fill.top + 1, nullptr);
        LineTo(mem, fill.right, fill.top + 1);
        DeleteObject(hi);
    }

    static LRESULT CALLBACK _Proc(HWND h, UINT m, WPARAM w, LPARAM l) {
        LoadingScreen* s = (LoadingScreen*)GetWindowLongPtrW(h, GWLP_USERDATA);
        if (m == WM_CREATE) {
            s = (LoadingScreen*)((CREATESTRUCTW*)l)->lpCreateParams;
            SetWindowLongPtrW(h, GWLP_USERDATA, (LONG_PTR)s);
        }
        if (!s) return DefWindowProcW(h, m, w, l);
        if (m == WM_TIMER && w == 1) {
            s->shimmerPhase += SHIMMER_STEP * 0.85f;
            if (s->shimmerPhase >= SHIMMER_BAND * 2.f) s->shimmerPhase -= SHIMMER_BAND * 2.f;
            s->pulse += 0.07f;
            s->dotAnim = (s->dotAnim + 1) % 48;
            float diff = s->targetProgress - s->displayProgress;
            s->displayProgress += diff * 0.09f;
            if (fabsf(diff) < 0.0015f) s->displayProgress = s->targetProgress;
            InvalidateRect(h, nullptr, FALSE);
        }
        if (m == WM_PAINT) {
            PAINTSTRUCT ps;
            HDC dc = BeginPaint(h, &ps);
            RECT cr;
            GetClientRect(h, &cr);
            HDC mem = CreateCompatibleDC(dc);
            HBITMAP bmp = CreateCompatibleBitmap(dc, cr.right, cr.bottom);
            HBITMAP ob = (HBITMAP)SelectObject(mem, bmp);

            _Fill(mem, cr, TC_BG);
            HPEN pn = CreatePen(PS_SOLID, 1, TC_BD);
            SelectObject(mem, pn);
            SelectObject(mem, GetStockObject(NULL_BRUSH));
            RoundRect(mem, 0, 0, cr.right, cr.bottom, 16, 16);
            DeleteObject(pn);

            RECT panel = { 10, 10, cr.right - 10, cr.bottom - 10 };
            _RR(mem, panel, 12, TC_BG2, TC_BD2);

            _Fill(mem, { panel.left, panel.top, panel.right, panel.top + 50 }, TC_BG2);
            _Line(mem, panel.left, panel.top + 50, panel.right, panel.top + 50, TC_BD);
            float pulse = 0.5f + 0.5f * sinf(s->pulse);
            COLORREF accentLine = _LerpColor(TC_BD, TC_ACCENT, 0.55f + 0.45f * pulse);
            _Line(mem, panel.left, panel.top + 51, panel.right, panel.top + 51, accentLine);

            _PaintShimmerTitle(mem, s->fTitle, L"SacredStep",
                { panel.left + 16, panel.top, panel.right - 16, panel.top + 50 },
                TC_ACCENT, TC_BG2, s->shimmerPhase);

            wchar_t statusLine[56]{};
            wcscpy_s(statusLine, s->statusText);
            int dots = (s->dotAnim / 8) % 4;
            for (int i = 0; i < dots; i++) wcscat_s(statusLine, L".");

            HFONT of = (HFONT)SelectObject(mem, s->fSm);
            _Txt(mem, statusLine, { panel.left + 16, panel.top + 58, panel.right - 16, panel.top + 78 },
                C_TMID, DT_CENTER);

            const int barY = panel.top + 92, barH = 10;
            RECT track = { panel.left + 16, barY, panel.right - 16, barY + barH };
            s->_PaintProgressBar(mem, track, s->displayProgress);

            wchar_t pct[12]{};
            swprintf_s(pct, L"%d%%", (int)(s->displayProgress * 100.f + 0.5f));
            _Txt(mem, pct, { panel.left + 16, barY + barH + 10, panel.right - 16, barY + barH + 28 },
                TC_ACCENT, DT_CENTER);

            SelectObject(mem, s->fCap);
            _Txt(mem, L"v4.2", { panel.left + 16, panel.bottom - 22, panel.left + 56, panel.bottom - 6 },
                C_TSEC);
            SelectObject(mem, of);

            BitBlt(dc, 0, 0, cr.right, cr.bottom, mem, 0, 0, SRCCOPY);
            SelectObject(mem, ob);
            DeleteDC(mem);
            DeleteObject(bmp);
            EndPaint(h, &ps);
        }
        return DefWindowProcW(h, m, w, l);
    }
};

enum HID {
    HID_NONE = 0, HID_CLOSE, HID_MIN,
    HID_SK0, HID_SK1, HID_SK2, HID_SK3, HID_SK4, HID_SK_ADD,
    HID_SK_PICK_CLICK, HID_SK_PICK_HOLD, HID_SK_PICK_COMBO,
    HID_BIND_HOLD, HID_BIND_SWITCH, HID_BIND_SPAM,
    HID_ATTACH,
    HID_CHK_AOT, HID_CHK_SS, HID_CHK_DETECT,
    HID_SCALE, HID_SPAM_SPEED, HID_SPAM_MODE,
    HID_SORU_RACE,
    HID_TH0, HID_TH1, HID_TH2, HID_TH3, HID_TH4,
    HID_OPEN_STATUS,
    HID_DELAY_EDIT,
    HID_DEL_BASE = 200,
};
struct HR { RECT r; HID id; };

struct DelMenuItem {
    RECT r;
    int holdMs = -1;
    bool mark = false;
};

static const int HOLD_MS_PRESETS[] = { 150, 250, 350, 500, 750, 1000, 1500 };
static const int HOLD_MS_PRESET_COUNT = (int)(sizeof(HOLD_MS_PRESETS) / sizeof(HOLD_MS_PRESETS[0]));

static bool _IsJellyTarget(HID id) {
    return id != HID_NONE;
}

class CursorToast {
public:
    HWND hw = nullptr;
    wchar_t msg[64]{};
    COLORREF textColor = TC_ACCENT;

    void Create(HINSTANCE hi) {
        WNDCLASSEXW wc{ sizeof(wc) };
        wc.lpfnWndProc = _Proc; wc.hInstance = hi;
        wc.lpszClassName = L"SSToast";
        wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
        RegisterClassExW(&wc);
        hw = CreateWindowExW(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE,
            L"SSToast", nullptr, WS_POPUP, 0, 0, 10, 26, nullptr, nullptr, hi, this);
        SetLayeredWindowAttributes(hw, 0, 230, LWA_ALPHA);
        INT cr = 2; DwmSetWindowAttribute(hw, 33, &cr, sizeof(cr));
    }

    void Show(const wchar_t* text, bool highlight) {
        wcscpy_s(msg, text);
        textColor = highlight ? TC_ACCENT : _ThemeMuted(0.40f);
        _Present();
    }

    void ShowSkill(const wchar_t* text, bool hold) {
        wcscpy_s(msg, text);
        textColor = _SkillThemeColor(hold);
        _Present();
    }

    void _Present() {
        HDC dc = GetDC(hw);
        HFONT f = _MkFont(11); HFONT of = (HFONT)SelectObject(dc, f);
        SIZE sz = _Measure(dc, msg);
        SelectObject(dc, of); DeleteObject(f); ReleaseDC(hw, dc);
        int W = sz.cx + 28, H = 30;
        POINT pt; GetCursorPos(&pt);
        int sx = GetSystemMetrics(SM_CXSCREEN), sy = GetSystemMetrics(SM_CYSCREEN);
        int wx = pt.x + 16, wy = pt.y + 16;
        if (wx + W > sx) wx = pt.x - W - 6;
        if (wy + H > sy) wy = pt.y - H - 6;
        SetWindowPos(hw, HWND_TOPMOST, wx, wy, W, H, SWP_NOACTIVATE);
        HRGN rgn = CreateRoundRectRgn(0, 0, W + 1, H + 1, 8, 8);
        SetWindowRgn(hw, rgn, TRUE);
        ShowWindow(hw, SW_SHOWNOACTIVATE);
        InvalidateRect(hw, nullptr, FALSE);
        KillTimer(hw, 1); SetTimer(hw, 1, 600, nullptr);
    }

    static LRESULT CALLBACK _Proc(HWND h, UINT m, WPARAM w, LPARAM l) {
        CursorToast* t = (CursorToast*)GetWindowLongPtrW(h, GWLP_USERDATA);
        if (m == WM_CREATE) {
            t = (CursorToast*)((CREATESTRUCTW*)l)->lpCreateParams;
            SetWindowLongPtrW(h, GWLP_USERDATA, (LONG_PTR)t);
        }
        if (!t) return DefWindowProcW(h, m, w, l);
        if (m == WM_TIMER && w == 1) { KillTimer(h, 1); ShowWindow(h, SW_HIDE); }
        if (m == WM_PAINT) {
            PAINTSTRUCT ps; HDC dc = BeginPaint(h, &ps);
            RECT r; GetClientRect(h, &r);
            HDC mem = CreateCompatibleDC(dc);
            HBITMAP bmp = CreateCompatibleBitmap(dc, r.right, r.bottom);
            HBITMAP ob = (HBITMAP)SelectObject(mem, bmp);
            _Fill(mem, r, TC_BG2);
            HPEN pn = CreatePen(PS_SOLID, 1, _ThemeBorderColor());
            SelectObject(mem, pn); SelectObject(mem, GetStockObject(NULL_BRUSH));
            RoundRect(mem, 0, 0, r.right, r.bottom, 8, 8); DeleteObject(pn);
            _Line(mem, 2, 1, r.right - 2, 1, _LerpColor(TC_ACCENT, TC_BG2, 0.25f));
            HFONT f = _MkFont(11); HFONT of = (HFONT)SelectObject(mem, f);
            _Txt(mem, t->msg, { 12, 0, r.right - 12, r.bottom },
                t->textColor, DT_CENTER);
            SelectObject(mem, of); DeleteObject(f);
            BitBlt(dc, 0, 0, r.right, r.bottom, mem, 0, 0, SRCCOPY);
            SelectObject(mem, ob); DeleteDC(mem); DeleteObject(bmp);
            EndPaint(h, &ps);
        }
        return DefWindowProcW(h, m, w, l);
    }
};

class StatusWindow {
public:
    HWND hw = nullptr;
    bool macroOn = false;
    bool skillHold = false;
    wchar_t skillName[16] = L"\u2014";
    int dx = 0, dy = 0;
    RECT closeBtn{};

    void Create(HINSTANCE hi) {
        WNDCLASSEXW wc{ sizeof(wc) };
        wc.lpfnWndProc = _Proc; wc.hInstance = hi;
        wc.lpszClassName = L"SSStatus";
        wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
        RegisterClassExW(&wc);
        hw = CreateWindowExW(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
            L"SSStatus", nullptr, WS_POPUP, 100, 100, 10, 10, nullptr, nullptr, hi, this);
        SetLayeredWindowAttributes(hw, 0, 240, LWA_ALPHA);
        INT cr = 2; DwmSetWindowAttribute(hw, 33, &cr, sizeof(cr));
    }

    void ResizeToContent() {
        if (!hw) return;
        HDC dc = GetDC(hw);
        HFONT f = _MkFont(11);
        HFONT of = (HFONT)SelectObject(dc, f);
        wchar_t prefix[48]{};
        swprintf_s(prefix, L"Mode | %s  \u00b7  Skill | ", macroOn ? L"ON" : L"OFF");
        SIZE psz = _Measure(dc, prefix);
        SIZE ssz = _Measure(dc, skillName);
        SelectObject(dc, of);
        DeleteObject(f);
        ReleaseDC(hw, dc);
        int W = 12 + psz.cx + ssz.cx + 36;
        if (W < 228) W = 228;
        RECT wr;
        GetWindowRect(hw, &wr);
        SetWindowPos(hw, nullptr, wr.left, wr.top, W, 34, SWP_NOZORDER | SWP_NOACTIVATE);
        HRGN rgn = CreateRoundRectRgn(0, 0, W + 1, 35, 10, 10);
        SetWindowRgn(hw, rgn, TRUE);
    }

    void ShowDocked(HWND parent) {
        ResizeToContent();
        RECT wr; GetWindowRect(parent, &wr);
        RECT sr; GetWindowRect(hw, &sr);
        SetWindowPos(hw, HWND_TOPMOST, wr.right + 10, wr.top, sr.right - sr.left, 34, SWP_NOACTIVATE);
        ShowWindow(hw, SW_SHOWNOACTIVATE);
        InvalidateRect(hw, nullptr, FALSE);
    }

    void UpdateMacro(bool on) {
        macroOn = on;
        if (IsWindowVisible(hw)) { ResizeToContent(); InvalidateRect(hw, nullptr, FALSE); }
    }
    void UpdateSkill(const wchar_t* sk, bool hold = false) {
        wcscpy_s(skillName, sk);
        skillHold = hold;
        if (IsWindowVisible(hw)) { ResizeToContent(); InvalidateRect(hw, nullptr, FALSE); }
    }

    static LRESULT CALLBACK _Proc(HWND h, UINT m, WPARAM w, LPARAM l) {
        StatusWindow* s = (StatusWindow*)GetWindowLongPtrW(h, GWLP_USERDATA);
        if (m == WM_CREATE) {
            s = (StatusWindow*)((CREATESTRUCTW*)l)->lpCreateParams;
            SetWindowLongPtrW(h, GWLP_USERDATA, (LONG_PTR)s);
        }
        if (!s) return DefWindowProcW(h, m, w, l);
        if (m == WM_LBUTTONDOWN) {
            int x = LOWORD(l), y = HIWORD(l);
            if (_In(s->closeBtn, x, y)) { ShowWindow(h, SW_HIDE); return 0; }
            s->dx = x; s->dy = y; SetCapture(h);
        }
        if (m == WM_MOUSEMOVE && (w & MK_LBUTTON)) {
            RECT wr; GetWindowRect(h, &wr);
            SetWindowPos(h, nullptr, wr.left + (int)(short)LOWORD(l) - s->dx,
                wr.top + (int)(short)HIWORD(l) - s->dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
        }
        if (m == WM_LBUTTONUP) ReleaseCapture();
        if (m == WM_PAINT) {
            PAINTSTRUCT ps; HDC dc = BeginPaint(h, &ps);
            RECT r; GetClientRect(h, &r);
            HDC mem = CreateCompatibleDC(dc);
            HBITMAP bmp = CreateCompatibleBitmap(dc, r.right, r.bottom);
            HBITMAP ob = (HBITMAP)SelectObject(mem, bmp);
            _Fill(mem, r, TC_BG2);
            HPEN pn = CreatePen(PS_SOLID, 1, _ThemeBorderColor());
            SelectObject(mem, pn); SelectObject(mem, GetStockObject(NULL_BRUSH));
            RoundRect(mem, 0, 0, r.right, r.bottom, 10, 10); DeleteObject(pn);
            _Line(mem, 2, 1, r.right - 2, 1, _LerpColor(TC_ACCENT, TC_BG2, 0.22f));
            HFONT f = _MkFont(11); HFONT of = (HFONT)SelectObject(mem, f);
            int cx = 12;
            _Txt(mem, L"Mode", { cx, 0, cx + 34, r.bottom }, _ThemeMuted(0.42f)); cx += 36;
            _Line(mem, cx, 9, cx, r.bottom - 9, _ThemeMuted(0.28f)); cx += 10;
            const wchar_t* modeTxt = s->macroOn ? L"ON" : L"OFF";
            SIZE modeSz = _Measure(mem, modeTxt);
            _Txt(mem, modeTxt, { cx, 0, cx + modeSz.cx + 2, r.bottom },
                s->macroOn ? TC_ACCENT : _LerpColor(TC_ACCENT, C_RED, 0.38f));
            cx += modeSz.cx + 6;
            _Txt(mem, L"\u00b7", { cx, 0, cx + 10, r.bottom }, _ThemeMuted(0.35f), DT_CENTER); cx += 14;
            _Txt(mem, L"Skill", { cx, 0, cx + 30, r.bottom }, _ThemeMuted(0.42f)); cx += 32;
            _Line(mem, cx, 9, cx, r.bottom - 9, _ThemeMuted(0.28f)); cx += 10;
            SIZE skSz = _Measure(mem, s->skillName);
            _Txt(mem, s->skillName, { cx, 0, cx + skSz.cx + 2, r.bottom },
                _SkillThemeColor(s->skillHold));
            s->closeBtn = { r.right - 24, (r.bottom - 16) / 2, r.right - 8, (r.bottom + 16) / 2 };
            _Txt(mem, L"\u00d7", s->closeBtn, _ThemeMuted(0.55f), DT_CENTER);
            SelectObject(mem, of); DeleteObject(f);
            BitBlt(dc, 0, 0, r.right, r.bottom, mem, 0, 0, SRCCOPY);
            SelectObject(mem, ob); DeleteDC(mem); DeleteObject(bmp);
            EndPaint(h, &ps);
        }
        return DefWindowProcW(h, m, w, l);
    }
};

class ComboPickWindow {
public:
    static const int CW = 188;
    static const int ROW = 30;
    static const int HDR = 36;
    static const int PADY = 10;

    HWND hw = nullptr;
    std::function<void(int)> onPick;
    int hover = -1;
    RECT closeBtn{};
    RECT rows[MINI_COMBO_COUNT]{};

    int Height() const { return HDR + MINI_COMBO_COUNT * ROW + PADY + 6; }

    void Create(HINSTANCE hi) {
        WNDCLASSEXW wc{ sizeof(wc) };
        wc.lpfnWndProc = _Proc;
        wc.hInstance = hi;
        wc.lpszClassName = L"SSComboPick";
        wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
        wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
        RegisterClassExW(&wc);
        int H = Height();
        hw = CreateWindowExW(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
            L"SSComboPick", L"Mini-Combo", WS_POPUP, 0, 0, CW, H,
            nullptr, nullptr, hi, this);
        SetLayeredWindowAttributes(hw, 0, 248, LWA_ALPHA);
        INT cr = 2;
        DwmSetWindowAttribute(hw, 33, &cr, sizeof(cr));
        HRGN rgn = CreateRoundRectRgn(0, 0, CW + 1, H + 1, 12, 12);
        SetWindowRgn(hw, rgn, TRUE);
    }

    void ShowNear(HWND parent) {
        if (!hw) return;
        hover = -1;
        RECT wr{};
        GetWindowRect(parent, &wr);
        int H = Height();
        int x = wr.left + (wr.right - wr.left - CW) / 2;
        int y = wr.top + 86;
        SetWindowPos(hw, HWND_TOPMOST, x, y, CW, H, SWP_SHOWWINDOW);
        ShowWindow(hw, SW_SHOW);
        SetForegroundWindow(hw);
        InvalidateRect(hw, nullptr, FALSE);
    }

    void Hide() {
        if (hw) ShowWindow(hw, SW_HIDE);
    }

    static LRESULT CALLBACK _Proc(HWND h, UINT m, WPARAM w, LPARAM l) {
        ComboPickWindow* s = (ComboPickWindow*)GetWindowLongPtrW(h, GWLP_USERDATA);
        if (m == WM_CREATE) {
            s = (ComboPickWindow*)((CREATESTRUCTW*)l)->lpCreateParams;
            SetWindowLongPtrW(h, GWLP_USERDATA, (LONG_PTR)s);
        }
        if (!s) return DefWindowProcW(h, m, w, l);

        if (m == WM_MOUSEMOVE) {
            int x = (int)(short)LOWORD(l), y = (int)(short)HIWORD(l);
            int nh = -1;
            for (int i = 0; i < MINI_COMBO_COUNT; i++) {
                if (_In(s->rows[i], x, y)) { nh = i; break; }
            }
            if (nh != s->hover) {
                s->hover = nh;
                InvalidateRect(h, nullptr, FALSE);
            }
            TRACKMOUSEEVENT tme{ sizeof(tme), TME_LEAVE, h, 0 };
            TrackMouseEvent(&tme);
            return 0;
        }
        if (m == WM_MOUSELEAVE) {
            s->hover = -1;
            InvalidateRect(h, nullptr, FALSE);
            return 0;
        }
        if (m == WM_LBUTTONDOWN) {
            int x = (int)(short)LOWORD(l), y = (int)(short)HIWORD(l);
            if (_In(s->closeBtn, x, y)) {
                s->Hide();
                return 0;
            }
            for (int i = 0; i < MINI_COMBO_COUNT; i++) {
                if (_In(s->rows[i], x, y)) {
                    if (s->onPick) s->onPick(i);
                    s->Hide();
                    return 0;
                }
            }
            return 0;
        }
        if (m == WM_KEYDOWN && w == VK_ESCAPE) {
            s->Hide();
            return 0;
        }
        if (m == WM_PAINT) {
            PAINTSTRUCT ps;
            HDC dc = BeginPaint(h, &ps);
            RECT r;
            GetClientRect(h, &r);
            HDC mem = CreateCompatibleDC(dc);
            HBITMAP bmp = CreateCompatibleBitmap(dc, r.right, r.bottom);
            HBITMAP ob = (HBITMAP)SelectObject(mem, bmp);
            SetBkMode(mem, TRANSPARENT);

            _Fill(mem, r, TC_BG);
            HPEN pn = CreatePen(PS_SOLID, 1, _ThemeBorderColor());
            SelectObject(mem, pn);
            SelectObject(mem, GetStockObject(NULL_BRUSH));
            RoundRect(mem, 0, 0, r.right, r.bottom, 12, 12);
            DeleteObject(pn);
            _Fill(mem, { 0, 0, r.right, HDR }, TC_BG2);
            _Line(mem, 0, HDR, r.right, HDR, TC_BD);
            _Line(mem, 0, HDR + 1, r.right, HDR + 1, TC_ACCENT);

            HFONT fCap = _MkFont(9, true);
            HFONT fBody = _MkFont(11, true);
            HFONT fSm = _MkFont(9, false);
            HFONT of = (HFONT)SelectObject(mem, fCap);
            _Txt(mem, L"MINI-COMBO", { 12, 0, r.right - 28, HDR }, C_TSEC);
            s->closeBtn = { r.right - 26, 10, r.right - 8, HDR - 10 };
            SelectObject(mem, fSm);
            _Txt(mem, L"\u00d7", s->closeBtn, _ThemeMuted(0.55f), DT_CENTER);

            int y = HDR + 8;
            for (int i = 0; i < MINI_COMBO_COUNT; i++) {
                RECT row = { 10, y, r.right - 10, y + ROW - 4 };
                s->rows[i] = row;
                bool hot = (s->hover == i);
                _RR(mem, row, 6,
                    hot ? _LerpColor(TC_PANEL, TC_ACCENT, 0.12f) : TC_PANEL,
                    hot ? TC_ACCENT : TC_BD2);
                SelectObject(mem, fBody);
                _Txt(mem, MINI_COMBOS[i].label,
                    { row.left + 10, row.top, row.right - 8, row.bottom },
                    hot ? TC_ACCENT : C_TACT, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
                if (MINI_COMBOS[i].kind == MCK_SIMUL) {
                    SelectObject(mem, fSm);
                    _Txt(mem, L"together",
                        { row.left, row.top, row.right - 10, row.bottom },
                        _ThemeMuted(0.42f), DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
                }
                y += ROW;
            }

            SelectObject(mem, of);
            DeleteObject(fCap);
            DeleteObject(fBody);
            DeleteObject(fSm);
            BitBlt(dc, 0, 0, r.right, r.bottom, mem, 0, 0, SRCCOPY);
            SelectObject(mem, ob);
            DeleteDC(mem);
            DeleteObject(bmp);
            EndPaint(h, &ps);
            return 0;
        }
        return DefWindowProcW(h, m, w, l);
    }
};

class SacredStepUI {
public:
    MacroEngine* eng = nullptr;
    CursorToast toast;
    StatusWindow statusWnd;
    ComboPickWindow comboWnd;
    HWND hw = nullptr;

    int themeIdx = 3;
    int uiScale = 100;
    int scrollY = 0;
    int scrollMax = 0;
    bool aot = true, showSt = true;
    int dragX = 0, dragY = 0;
    bool scaleDragging = false;
    bool spamSpeedDragging = false;
    RECT scaleTrackRect{};
    RECT spamSpeedTrackRect{};
    float shimmerPhase = 0.f;
    bool showCapOverlay = false;
    std::wstring capOverlayTxt;
    bool showDelMenu = false;
    int delMenuSkillIdx = -1;
    RECT delMenuRect{};
    std::vector<DelMenuItem> delMenuItems;
    bool delayEditOpen = false;
    std::wstring delayEditBuf;
    RECT delayFieldRect{};
    bool showSkillModePicker = false;
    RECT skillModePickerRect{};
    std::vector<HR> hits;
    HID hoverId = HID_NONE;
    HID jellyId = HID_NONE;
    float jellyT = 0.f;
    HFONT fCap = nullptr, fBody = nullptr, fMono = nullptr, fSm = nullptr, fTitle = nullptr, fBold = nullptr;

    float _JellyFor(HID id) const {
        return (id == jellyId && _IsJellyTarget(id)) ? jellyT : 0.f;
    }

    float _UiScale() const {
        float s = uiScale / 100.f;
        return (s < 1.f) ? 1.f : s;
    }
    int _WinW() const { return (int)(UI_W * _UiScale() + 0.5f); }
    int _WinH() const { return (int)(UI_H * _UiScale() + 0.5f); }

    void _ToLog(int& x, int& y) const {
        float s = _UiScale();
        x = (int)(x / s + 0.5f);
        y = (int)(y / s + 0.5f);
    }

    void _RebuildFonts() {
        auto px = [this](int n) {
            int v = (int)(n * _UiScale() + 0.5f);
            return v < 1 ? 1 : v;
        };
        auto repl = [](HFONT& f, HFONT n) {
            if (f) DeleteObject(f);
            f = n;
        };
        repl(fCap, _MkFont(px(9), true));
        repl(fBody, _MkFont(px(11), false));
        repl(fBold, _MkFont(px(11), true));
        repl(fMono, _MkFont(px(11), false, L"Consolas"));
        repl(fSm, _MkFont(px(10), false));
        repl(fTitle, _MkFont(px(SHIMMER_TITLE_PX), false, L"Segoe UI"));
    }

    void _ApplyUiScale() {
        if (!hw) return;
        int w = _WinW(), h = _WinH();
        SetWindowPos(hw, nullptr, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
        int rx = (int)(14.f * _UiScale() + 0.5f);
        if (rx < 8) rx = 8;
        HRGN rgn = CreateRoundRectRgn(0, 0, w + 1, h + 1, rx, rx);
        SetWindowRgn(hw, rgn, TRUE);
        _RebuildFonts();
        InvalidateRect(hw, nullptr, FALSE);
    }

    void _SetUiScale(int pct) {
        if (pct < 100) pct = 100;
        if (pct > 200) pct = 200;
        if (pct == uiScale) return;
        uiScale = pct;
        _ApplyUiScale();
    }

    void _UpdateScaleFromX(int lx) {
        int left = scaleTrackRect.left;
        int right = scaleTrackRect.right;
        if (right <= left) return;
        float t = (float)(lx - left) / (float)(right - left);
        if (t < 0.f) t = 0.f;
        if (t > 1.f) t = 1.f;
        _SetUiScale(100 + (int)(t * 100.f + 0.5f));
    }

    void _SetSpamIntervalFromX(int lx) {
        int left = spamSpeedTrackRect.left;
        int right = spamSpeedTrackRect.right;
        if (right <= left) return;
        float t = (float)(lx - left) / (float)(right - left);
        if (t < 0.f) t = 0.f;
        if (t > 1.f) t = 1.f;
        int cps = SpamTToCps(t);
        eng->SetSpamCps(cps);
        InvalidateRect(hw, nullptr, FALSE);
    }

    void _UpdateHover(int x, int y) {
        HID h = HitTest(x, y);
        if (h == hoverId) return;
        hoverId = h;
        InvalidateRect(hw, nullptr, FALSE);
    }

    void _TickJelly() {
        HID targetId = _IsJellyTarget(hoverId) ? hoverId : HID_NONE;
        float target = (targetId != HID_NONE) ? 1.f : 0.f;
        if (targetId != HID_NONE) jellyId = targetId;
        float prev = jellyT;
        jellyT += (target - jellyT) * 0.20f;
        if (fabsf(jellyT - target) < 0.008f) {
            jellyT = target;
            if (jellyT <= 0.001f) jellyId = HID_NONE;
        }
        if (fabsf(jellyT - prev) > 0.002f)
            InvalidateRect(hw, nullptr, FALSE);
        else if (delayEditOpen)
            InvalidateRect(hw, nullptr, FALSE);
    }

    void Create(HINSTANCE hi, bool visible = true) {
        themeIdx = Config::ReadInt(L"UI", L"Theme", 3);
        aot = Config::ReadInt(L"UI", L"AlwaysOnTop", 1) != 0;
        uiScale = Config::ReadInt(L"UI", L"Scale", 100);
        if (uiScale < 100) uiScale = 100;
        if (uiScale > 200) uiScale = 200;
        ApplyTheme(themeIdx);

        WNDCLASSEXW wc{ sizeof(wc) };
        wc.lpfnWndProc = _Proc; wc.hInstance = hi;
        wc.lpszClassName = L"SacredStep";
        wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
        wc.hCursor = LoadCursor(nullptr, IDC_ARROW);

        wc.hIcon = LoadIcon(hi, MAKEINTRESOURCE(IDI_ICON1));
        wc.hIconSm = LoadIcon(hi, MAKEINTRESOURCE(IDI_ICON1));
        RegisterClassExW(&wc);

        DWORD style = WS_POPUP;
        if (visible) style |= WS_VISIBLE;
        hw = CreateWindowExW(WS_EX_LAYERED, L"SacredStep", L"SacredStep",
            style, 0, 0, _WinW(), _WinH(), nullptr, nullptr, hi, this);
        _CenterWindow(hw, _WinW(), _WinH());

        HICON ico = LoadIcon(hi, MAKEINTRESOURCE(IDI_ICON1));
        if (ico) {
            SendMessage(hw, WM_SETICON, ICON_BIG, (LPARAM)ico);
            SendMessage(hw, WM_SETICON, ICON_SMALL, (LPARAM)ico);
        }

        INT corner = 2;
        DwmSetWindowAttribute(hw, 33, &corner, sizeof(corner));
        SetLayeredWindowAttributes(hw, 0, visible ? 255 : 0, LWA_ALPHA);
        SetWindowPos(hw, aot ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
        int rx = (int)(14.f * _UiScale() + 0.5f);
        if (rx < 8) rx = 8;
        HRGN rgn = CreateRoundRectRgn(0, 0, _WinW() + 1, _WinH() + 1, rx, rx);
        SetWindowRgn(hw, rgn, TRUE);

        fCap = nullptr;
        fBody = nullptr;
        fBold = nullptr;
        fMono = nullptr;
        fSm = nullptr;
        fTitle = nullptr;
        _RebuildFonts();

        toast.Create(hi);
        statusWnd.Create(hi);
        comboWnd.Create(hi);
        comboWnd.onPick = [this](int id) {
            if (!eng->AddCombo(id)) return;
            int idx = (int)eng->skills.size() - 1;
            eng->skillIdx = idx;
            eng->CacheFireKey();
            _SyncSkillStatus();
            if (showSt) toast.ShowSkill(_SkillToastText(idx).c_str(), false);
            if (eng->onSkillChange) eng->onSkillChange(idx);
            InvalidateRect(hw, nullptr, FALSE);
        };
        SetTimer(hw, 2, SHIMMER_TIMER_MS, nullptr);
        SetTimer(hw, 3, 16, nullptr);

        eng->onStatusChange = [this](bool on) { PostMessage(hw, WM_APP + 1, on ? 1 : 0, 0); };
        eng->onSkillChange = [this](int) { PostMessage(hw, WM_APP + 2, 0, 0); };
        eng->onDetectChange = [this]() { PostMessage(hw, WM_APP + 7, 0, 0); };
        eng->onSpamChange = [this]() {
            PostMessage(hw, WM_APP + 8,
                eng->spamEnabled.load() ? 1 : 0,
                (LPARAM)eng->spamMode.load());
        };
        eng->isCursorOverUI = [this]() {
            if (!hw || !IsWindowVisible(hw)) return false;
            POINT pt; GetCursorPos(&pt);
            RECT wr; GetWindowRect(hw, &wr);
            return pt.x >= wr.left && pt.x < wr.right && pt.y >= wr.top && pt.y < wr.bottom;
        };
    }

    void ShowMainAnimated() {
        if (!hw) return;
        _CenterWindow(hw, _WinW(), _WinH());
        _ApplyUiScale();
        SetLayeredWindowAttributes(hw, 0, 0, LWA_ALPHA);
        ShowWindow(hw, SW_SHOW);
        UpdateWindow(hw);
        _AnimateAlpha(hw, 0, 255, 500);
    }

    void _ApplyThemeToStatuses() {
        if (statusWnd.hw && IsWindowVisible(statusWnd.hw))
            InvalidateRect(statusWnd.hw, nullptr, TRUE);
        if (toast.hw && IsWindowVisible(toast.hw))
            InvalidateRect(toast.hw, nullptr, TRUE);
    }

    int _ViewportTop() const { return HDR_H + 8; }
    int _ViewportBottom() const { return UI_H - FOOT_H; }

    std::wstring _SkillStatusLabel(bool* outHold = nullptr) {
        if (eng->skills.empty()) {
            if (outHold) *outHold = false;
            return L"\u2014";
        }
        const SkillEntry& sk = eng->skills[eng->skillIdx];
        if (outHold) *outHold = (sk.mode == SKF_HOLD);
        if (sk.mode == SKF_COMBO && sk.comboId >= 0 && sk.comboId < MINI_COMBO_COUNT)
            return MINI_COMBOS[sk.comboId].label;
        wchar_t buf[16]{};
        if (sk.mode == SKF_HOLD)
            swprintf_s(buf, L"%c hold", (wchar_t)toupper(sk.key));
        else
            swprintf_s(buf, L"%c click", (wchar_t)toupper(sk.key));
        return buf;
    }

    void _SyncSkillStatus() {
        bool hold = false;
        auto label = _SkillStatusLabel(&hold);
        statusWnd.UpdateSkill(label.c_str(), hold);
    }

    std::wstring _SkillToastText(int idx = -1) {
        if (idx < 0) idx = eng->skillIdx;
        if (idx < 0 || idx >= (int)eng->skills.size()) return L"";
        const SkillEntry& sk = eng->skills[idx];
        wchar_t buf[32]{};
        if (sk.mode == SKF_COMBO && sk.comboId >= 0 && sk.comboId < MINI_COMBO_COUNT)
            swprintf_s(buf, L"Skill: %s", MINI_COMBOS[sk.comboId].label);
        else if (sk.mode == SKF_HOLD)
            swprintf_s(buf, L"Skill: %c hold", (wchar_t)toupper(sk.key));
        else
            swprintf_s(buf, L"Skill: %c click", (wchar_t)toupper(sk.key));
        return buf;
    }

    std::wstring _SkillName() { return _SkillStatusLabel(); }

    void _PaintSkillChip(HDC dc, RECT chip, const SkillEntry& sk, bool active, HID id) {
        const bool hold = sk.mode == SKF_HOLD;
        const bool combo = sk.mode == SKF_COMBO;
        float j = _JellyFor(id);
        RECT cr = _JellyRect(chip, j);
        COLORREF fill = active ? TC_PANEL : TC_BG;
        COLORREF border = active ? TC_ACCENT : TC_BD2;
        if (j > 0.f) {
            fill = _LerpColor(fill, TC_ACCENT, j * 0.12f);
            border = _LerpColor(border, TC_ACCENT, j * 0.55f);
        }
        _RR(dc, cr, 7, fill, border);
        wchar_t lbl[8]{};
        if (combo && sk.comboId >= 0 && sk.comboId < MINI_COMBO_COUNT) {
            lbl[0] = (wchar_t)toupper(MINI_COMBOS[sk.comboId].a);
            lbl[1] = (wchar_t)toupper(MINI_COMBOS[sk.comboId].b);
        } else {
            lbl[0] = (wchar_t)toupper(sk.key);
        }
        HFONT of = (HFONT)SelectObject(dc, fMono);
        _Txt(dc, lbl, cr, active ? C_TACT : _ThemeMuted(0.55f), DT_CENTER);
        if (hold || combo) {
            SIZE sz = _Measure(dc, lbl);
            int cx = (cr.left + cr.right) / 2;
            int halfW = max(sz.cx / 2 + 2, 6);
            RECT stripe = { cx - halfW, cr.bottom - 6, cx + halfW, cr.bottom - 4 };
            _Fill(dc, stripe, TC_ACCENT);
        }
        SelectObject(dc, of);
    }

    void _PaintSkillModePicker(HDC dc) {
        _RR(dc, skillModePickerRect, 8, TC_PANEL, TC_ACCENT);
        HFONT of = (HFONT)SelectObject(dc, fCap);
        _Txt(dc, L"SKILL MODE", { skillModePickerRect.left + 10, skillModePickerRect.top + 6,
            skillModePickerRect.right - 10, skillModePickerRect.top + 20 }, C_TSEC);
        SelectObject(dc, fSm);
        _Txt(dc, L"Choose type", { skillModePickerRect.left + 10, skillModePickerRect.top + 20,
            skillModePickerRect.right - 10, skillModePickerRect.top + 36 }, C_TDIM);
        SelectObject(dc, of);

        const int btnW = 68, btnH = 28, gap = 6;
        int cx = skillModePickerRect.left +
            (skillModePickerRect.right - skillModePickerRect.left - btnW * 3 - gap * 2) / 2;
        int cy = skillModePickerRect.bottom - btnH - 10;
        RECT clickR = { cx, cy, cx + btnW, cy + btnH };
        RECT holdR  = { cx + btnW + gap, cy, cx + btnW * 2 + gap, cy + btnH };
        RECT comboR = { cx + (btnW + gap) * 2, cy, cx + (btnW + gap) * 2 + btnW, cy + btnH };
        float jc = _JellyFor(HID_SK_PICK_CLICK);
        float jh = _JellyFor(HID_SK_PICK_HOLD);
        float jm = _JellyFor(HID_SK_PICK_COMBO);
        RECT jClick = _JellyRect(clickR, jc);
        RECT jHold = _JellyRect(holdR, jh);
        RECT jCombo = _JellyRect(comboR, jm);
        _RR(dc, jClick, 7, _LerpColor(TC_BG, TC_ACCENT, jc * 0.10f),
            _LerpColor(TC_BD2, TC_ACCENT, jc * 0.50f));
        _RR(dc, jHold, 7, _LerpColor(TC_BG2, TC_ACCENT, jh * 0.12f),
            _LerpColor(TC_ACCENT, TC_ACCENT, 0.5f + jh * 0.5f));
        _RR(dc, jCombo, 7, _LerpColor(TC_BG, TC_ACCENT, jm * 0.10f),
            _LerpColor(TC_BD2, TC_ACCENT, jm * 0.50f));
        SelectObject(dc, fSm);
        _Txt(dc, L"Click", jClick, _LerpColor(C_TMID, TC_ACCENT, jc * 0.45f), DT_CENTER);
        _Txt(dc, L"Hold", jHold, _LerpColor(C_TACT, TC_ACCENT, jh * 0.35f), DT_CENTER);
        _Txt(dc, L"Combo", jCombo, _LerpColor(C_TMID, TC_ACCENT, jm * 0.45f), DT_CENTER);
        SelectObject(dc, of);
        hits.push_back({ clickR, HID_SK_PICK_CLICK });
        hits.push_back({ holdR, HID_SK_PICK_HOLD });
        hits.push_back({ comboR, HID_SK_PICK_COMBO });
    }

    void Paint(HDC dc) {
        hits.clear();
        g_uiPaintScale = _UiScale();
        RECT cr = { 0, 0, UI_W, UI_H };
        _Fill(dc, cr, TC_BG);
        int pw = _PS(1);
        if (pw < 1) pw = 1;
        HPEN op = CreatePen(PS_SOLID, pw, TC_BD);
        SelectObject(dc, op); SelectObject(dc, GetStockObject(NULL_BRUSH));
        RoundRect(dc, 0, 0, _PS(UI_W), _PS(UI_H), _PS(14), _PS(14)); DeleteObject(op);

        _Fill(dc, { 0, 0, UI_W, HDR_H }, TC_BG2);
        _Line(dc, 0, HDR_H, UI_W, HDR_H, TC_BD);
        _Line(dc, 0, HDR_H + 1, UI_W, HDR_H + 1, TC_ACCENT);

        _PaintShimmerTitle(dc, fTitle, L"SacredStep",
            { PAD, 0, UI_W - 88, HDR_H }, TC_ACCENT, TC_BG2, shimmerPhase);

        _PaintWMBtn(dc, { UI_W - 56, 10, UI_W - 32, 32 }, L"\u2014", HID_MIN, false);
        _PaintWMBtn(dc, { UI_W - 30, 10, UI_W - 6, 32 }, L"\u00d7", HID_CLOSE, true);

        int vTop = _ViewportTop();
        int vBot = _ViewportBottom();
        HRGN clip = CreateRectRgn(_PS(0), _PS(vTop), _PS(UI_W), _PS(vBot));
        SelectClipRgn(dc, clip);

        int oy = vTop - scrollY;
        int y = _PaintBody(dc, oy + 8);
        scrollMax = (std::max)(0, (y - oy) - (vBot - vTop));
        if (scrollY > scrollMax) scrollY = scrollMax;

        SelectClipRgn(dc, NULL);
        DeleteObject(clip);

        _PaintFooter(dc);

        if (showDelMenu) _PaintDelMenu(dc);
        if (showSkillModePicker) _PaintSkillModePicker(dc);
        if (showCapOverlay) {
            RECT or2 = { PAD, vTop + 4, UI_W - PAD, vTop + 32 };
            _RR(dc, or2, 6, TC_PANEL, TC_ACCENT);
            HFONT of = (HFONT)SelectObject(dc, fSm);
            _Txt(dc, capOverlayTxt.c_str(), or2, C_TACT, DT_CENTER);
            SelectObject(dc, of);
        }
        g_uiPaintScale = 1.f;
    }

    void _PaintWMBtn(HDC dc, RECT r, const wchar_t* lbl, HID id, bool isClose) {
        float j = _JellyFor(id);
        RECT jr = _JellyRect(r, j);
        COLORREF fill = isClose ? TC_BG2 : TC_BG;
        COLORREF border = isClose ? C_RED : TC_BD2;
        if (isClose) {
            border = _LerpColor(C_RED, TC_ACCENT, j * 0.25f);
        } else if (j > 0.f) {
            fill = _LerpColor(fill, TC_ACCENT, j * 0.12f);
            border = _LerpColor(border, TC_ACCENT, j * 0.50f);
        }
        _RR(dc, jr, 6, fill, border);
        HFONT of = (HFONT)SelectObject(dc, fSm);
        COLORREF txtCol = isClose ? _LerpColor(C_RED, TC_ACCENT, j * 0.15f)
                                  : _ThemeMuted(0.55f + j * 0.2f);
        _Txt(dc, lbl, jr, txtCol, DT_CENTER);
        SelectObject(dc, of);
        hits.push_back({ r, id });
    }

    int _PaintBody(HDC dc, int y) {
        _ModeBanner(dc, y); y += 48;
        _Divider(dc, y); y += 12;

        _SecLbl(dc, y, L"HOTKEYS"); y += 18;
        _BindCard(dc, y, L"Toggle", eng->holdBind.Name().c_str(), HID_BIND_HOLD); y += ROW_H + 4;
        _BindCard(dc, y, L"Switch skill", eng->switchBind.Name().c_str(), HID_BIND_SWITCH); y += ROW_H + 8;
        _Divider(dc, y); y += 12;

        _SecLbl(dc, y, L"R SPAM"); y += 18;
        _BindCard(dc, y, L"Bind", eng->spamBind.Name().c_str(), HID_BIND_SPAM); y += ROW_H + 4;
        {
            bool spamOn = (eng->spamMode.load() == SPAM_TOGGLE && eng->spamEnabled.load())
                || (eng->spamMode.load() == SPAM_HOLD && eng->spamHeld.load());
            const wchar_t* modeName = MacroEngine::SpamModeName(eng->spamMode.load());
            _BindCard(dc, y, L"Mode",
                spamOn ? (eng->spamMode.load() == SPAM_HOLD ? L"Hold ON" : L"Toggle ON") : modeName,
                HID_SPAM_MODE);
        }
        y += ROW_H + 4;
        y = _PaintSpamSpeedRow(dc, y);
        _Divider(dc, y); y += 12;

        _SecLbl(dc, y, L"SKILL"); y += 18;
        int x = PAD;
        const int chipH = 28;
        for (int i = 0; i < (int)eng->skills.size(); i++) {
            bool act = (i == eng->skillIdx);
            bool combo = eng->skills[i].mode == SKF_COMBO;
            int chipW = combo ? 44 : 34;
            RECT chip = { x, y, x + chipW, y + chipH };
            _PaintSkillChip(dc, chip, eng->skills[i], act, (HID)(HID_SK0 + i));
            hits.push_back({ chip, (HID)(HID_SK0 + i) });
            x += chipW + 6;
        }
        if (eng->skills.size() < 5) {
            RECT r = { x, y, x + 30, y + chipH };
            float j = _JellyFor(HID_SK_ADD);
            RECT jr = _JellyRect(r, j);
            _RR(dc, jr, 7, _LerpColor(TC_BG, TC_ACCENT, j * 0.10f),
                _LerpColor(TC_BD2, TC_ACCENT, j * 0.50f));
            HFONT of = (HFONT)SelectObject(dc, fMono);
            _Txt(dc, L"+", jr, _LerpColor(C_TSEC, TC_ACCENT, j * 0.45f), DT_CENTER);
            SelectObject(dc, of);
            hits.push_back({ r, HID_SK_ADD });
        }
        skillModePickerRect = { PAD, y, UI_W - PAD, y + chipH + 52 };
        y += chipH + 12;
        _Divider(dc, y); y += 12;

        _SecLbl(dc, y, L"DETECT"); y += 18;
        const wchar_t* dTxt = eng->detectStatusText.c_str();
        COLORREF dcC = C_TMID;
        if (!eng->detector.detectEnabled.load()) dcC = RGB(0xaa, 0x88, 0x28);
        else if (eng->detector.status.load() == 4) dcC = C_RED;
        else if (eng->detectStatusText.find(L"fired") != std::wstring::npos) dcC = C_GREEN;
        else if (eng->detector.HasAnimator()) dcC = RGB(0x44, 0xaa, 0x44);
        RECT dr = { PAD, y, UI_W - PAD, y + ROW_H };
        _RR(dc, dr, 7, TC_PANEL, TC_BD);
        HFONT of = (HFONT)SelectObject(dc, fSm);
        _Txt(dc, dTxt, { PAD + 10, y, UI_W - PAD - 10, y + ROW_H }, dcC, DT_CENTER);
        SelectObject(dc, of);
        y += ROW_H + 4;
        _ChkRow(dc, y, eng->detector.detectEnabled.load(), L"Enabled", HID_CHK_DETECT); y += ROW_H + 2;
        _BindCard(dc, y, L"Soru race", MacroEngine::SoruRaceName(eng->soruRace.load()), HID_SORU_RACE);
        y += ROW_H + 8;
        _Divider(dc, y); y += 12;

        _SecLbl(dc, y, L"WINDOW"); y += 18;
        _ChkRow(dc, y, aot, L"Always on top", HID_CHK_AOT); y += ROW_H + 2;
        _ChkRow(dc, y, showSt, L"Show status toast", HID_CHK_SS); y += ROW_H + 2;
        y = _PaintScaleRow(dc, y);
        _BtnRow(dc, y, L"Open status bar", HID_OPEN_STATUS); y += ROW_H + 4;
        _BtnRow(dc, y, L"Re-attach memory", HID_ATTACH); y += ROW_H + 8;
        _Divider(dc, y); y += 12;

        _SecLbl(dc, y, L"THEME"); y += 18;
        y = _PaintThemes(dc, y);
        return y + 8;
    }

    void _SecLbl(HDC dc, int y, const wchar_t* t) {
        HFONT of = (HFONT)SelectObject(dc, fCap);
        _Txt(dc, t, { PAD, y, UI_W - PAD, y + 14 }, C_TSEC);
        SelectObject(dc, of);
    }

    void _Divider(HDC dc, int y) {
        _Line(dc, PAD, y, UI_W - PAD, y, RGB(0x1c, 0x1c, 0x1c));
    }

    void _ModeBanner(HDC dc, int y) {
        bool on = eng->macroEnabled;
        RECT card = { PAD, y, UI_W - PAD, y + 40 };
        _RR(dc, card, 8, TC_PANEL, on ? TC_ACCENT : TC_BD2);

        HFONT of = (HFONT)SelectObject(dc, fCap);
        _Txt(dc, L"MODE", { PAD + 12, y, PAD + 60, y + 40 }, C_TDIM);
        SelectObject(dc, fBold);

        int pillW = 56, pillH = 26;
        RECT pill = { card.right - 12 - pillW, y + (40 - pillH) / 2,
                      card.right - 12, y + (40 + pillH) / 2 };
        _TxtPill(dc, on ? L"ON" : L"OFF", pill,
            on ? RGB(0x0e, 0x1a, 0x0e) : RGB(0x1a, 0x0e, 0x0e),
            on ? C_GREEN : C_RED,
            on ? RGB(0x28, 0x50, 0x28) : RGB(0x50, 0x28, 0x28));
        SelectObject(dc, of);
    }

    void _BindCard(HDC dc, int y, const wchar_t* lbl, const wchar_t* val, HID id) {
        RECT row = { PAD, y, UI_W - PAD, y + ROW_H };
        float j = _JellyFor(id);
        RECT jr = _JellyRect(row, j);
        _RR(dc, jr, 7, _LerpColor(TC_PANEL, TC_ACCENT, j * 0.08f),
            _LerpColor(TC_BD, TC_ACCENT, j * 0.45f));

        HFONT of = (HFONT)SelectObject(dc, fBody);
        _Txt(dc, lbl, { PAD + 12, y, row.right - PILL_W - 20, y + ROW_H }, _ThemeMuted(0.50f));

        SelectObject(dc, fMono);
        RECT pill = { row.right - PILL_W - 8, y + 4, row.right - 8, y + ROW_H - 4 };
        RECT jpill = _JellyRect(pill, j * 0.75f);
        _TxtPill(dc, val, jpill, TC_BG, _LerpColor(C_TACT, TC_ACCENT, j * 0.30f),
            _LerpColor(TC_BD2, TC_ACCENT, j * 0.55f));
        hits.push_back({ row, id });
        SelectObject(dc, of);
    }

    void _ChkRow(HDC dc, int y, bool chk, const wchar_t* lbl, HID id) {
        const int boxSz = 14;
        const int chkPad = PAD + 6;
        RECT row = { PAD, y, UI_W - PAD, y + ROW_H };
        float j = _JellyFor(id);
        RECT jr = _JellyRect(row, j * 0.55f);
        if (j > 0.01f)
            _RR(dc, jr, 7, _LerpColor(TC_BG, TC_ACCENT, j * 0.06f),
                _LerpColor(TC_BD2, TC_ACCENT, j * 0.35f));

        RECT box = { chkPad, y + (ROW_H - boxSz) / 2, chkPad + boxSz, y + (ROW_H + boxSz) / 2 };
        _RR(dc, box, 3, TC_BG, _LerpColor(TC_BD2, TC_ACCENT, j * 0.40f));
        if (chk) {
            HPEN p = CreatePen(PS_SOLID, (std::max)(1, _PS(2)), TC_ACCENT); SelectObject(dc, p);
            SelectObject(dc, GetStockObject(NULL_BRUSH));
            int cy = y + ROW_H / 2;
            POINT pts[] = {
                { _PS(chkPad + 3), _PS(cy) },
                { _PS(chkPad + 6), _PS(cy + 4) },
                { _PS(chkPad + 11), _PS(cy - 3) }
            };
            Polyline(dc, pts, 3); DeleteObject(p);
        }
        HFONT of = (HFONT)SelectObject(dc, fBody);
        _Txt(dc, lbl, { chkPad + boxSz + 10, y, row.right, y + ROW_H },
            _LerpColor(C_TMID, TC_ACCENT, j * 0.25f));
        SelectObject(dc, of);
        hits.push_back({ row, id });
    }

    int _PaintScaleRow(HDC dc, int y) {
        RECT row = { PAD, y, UI_W - PAD, y + ROW_H + 10 };
        float j = _JellyFor(HID_SCALE);
        RECT jr = _JellyRect(row, j * 0.35f);
        _RR(dc, jr, 7, _LerpColor(TC_PANEL, TC_ACCENT, j * 0.08f),
            _LerpColor(TC_BD, TC_ACCENT, j * 0.40f));

        HFONT of = (HFONT)SelectObject(dc, fBody);
        _Txt(dc, L"Menu size", { PAD + 10, y + 2, PAD + 120, y + 18 },
            _LerpColor(C_TMID, TC_ACCENT, j * 0.25f));
        wchar_t pct[16]{};
        swprintf_s(pct, L"%d%%", uiScale);
        SelectObject(dc, fMono);
        _Txt(dc, pct, { UI_W - PAD - 52, y + 2, UI_W - PAD - 8, y + 18 },
            _LerpColor(C_TACT, TC_ACCENT, j * 0.30f), DT_RIGHT);

        int trackL = PAD + 12;
        int trackR = UI_W - PAD - 12;
        int trackY = y + 24;
        RECT track = { trackL, trackY, trackR, trackY + 5 };
        _RR(dc, { track.left, track.top - 1, track.right, track.bottom + 1 }, 4, TC_BG, TC_BD);
        float t = (uiScale - 100) / 100.f;
        int fillR = track.left + (int)(t * (track.right - track.left) + 0.5f);
        if (fillR > track.left)
            _RR(dc, { track.left, track.top - 1, fillR, track.bottom + 1 }, 4, TC_ACCENT, TC_ACCENT);
        RECT thumb = { fillR - 6, trackY - 4, fillR + 6, trackY + 10 };
        _RR(dc, thumb, 6, C_TACT, TC_ACCENT);

        scaleTrackRect = { trackL, y, trackR, y + ROW_H + 10 };
        hits.push_back({ row, HID_SCALE });
        SelectObject(dc, of);
        return y + ROW_H + 16;
    }

    int _PaintSpamSpeedRow(HDC dc, int y) {
        RECT row = { PAD, y, UI_W - PAD, y + ROW_H + 10 };
        float j = _JellyFor(HID_SPAM_SPEED);
        RECT jr = _JellyRect(row, j * 0.35f);
        _RR(dc, jr, 7, _LerpColor(TC_PANEL, TC_ACCENT, j * 0.08f),
            _LerpColor(TC_BD, TC_ACCENT, j * 0.40f));

        int ms = eng->spamIntervalMs.load();
        int cps = SpamCpsFromMs(ms);

        HFONT of = (HFONT)SelectObject(dc, fBody);
        _Txt(dc, L"Speed", { PAD + 10, y + 2, PAD + 120, y + 18 },
            _LerpColor(C_TMID, TC_ACCENT, j * 0.25f));
        wchar_t lab[24]{};
        swprintf_s(lab, L"%d/s", cps);
        SelectObject(dc, fMono);
        _Txt(dc, lab, { UI_W - PAD - 64, y + 2, UI_W - PAD - 8, y + 18 },
            _LerpColor(C_TACT, TC_ACCENT, j * 0.30f), DT_RIGHT);

        int trackL = PAD + 12;
        int trackR = UI_W - PAD - 12;
        int trackY = y + 24;
        RECT track = { trackL, trackY, trackR, trackY + 5 };
        _RR(dc, { track.left, track.top - 1, track.right, track.bottom + 1 }, 4, TC_BG, TC_BD);
        float t = SpamCpsToT(cps);
        int fillR = track.left + (int)(t * (track.right - track.left) + 0.5f);
        if (fillR > track.left)
            _RR(dc, { track.left, track.top - 1, fillR, track.bottom + 1 }, 4, TC_ACCENT, TC_ACCENT);
        RECT thumb = { fillR - 6, trackY - 4, fillR + 6, trackY + 10 };
        _RR(dc, thumb, 6, C_TACT, TC_ACCENT);

        spamSpeedTrackRect = { trackL, y, trackR, y + ROW_H + 10 };
        hits.push_back({ row, HID_SPAM_SPEED });
        SelectObject(dc, of);
        return y + ROW_H + 16;
    }

    void _BtnRow(HDC dc, int y, const wchar_t* lbl, HID id) {
        RECT r = { PAD, y, UI_W - PAD, y + ROW_H - 2 };
        float j = _JellyFor(id);
        RECT jr = _JellyRect(r, j);
        _RR(dc, jr, 7, _LerpColor(TC_PANEL, TC_ACCENT, j * 0.10f),
            _LerpColor(TC_BD2, TC_ACCENT, j * 0.50f));
        HFONT of = (HFONT)SelectObject(dc, fSm);
        _Txt(dc, lbl, jr, _LerpColor(C_TDIM, TC_ACCENT, j * 0.40f), DT_CENTER);
        SelectObject(dc, of);
        hits.push_back({ r, id });
    }

    int _PaintThemes(HDC dc, int y) {
        const int colW = 84, chipH = 24;
        int maxRow = 0;
        for (int i = 0; i < 5; i++) {
            int col = i % 3, row = i / 3;
            maxRow = row;
            int bx = PAD + col * colW, by = y + row * (chipH + 6);
            RECT r = { bx, by, bx + colW - 6, by + chipH };
            bool sel = (i == themeIdx);
            HID tid = (HID)(HID_TH0 + i);
            float j = _JellyFor(tid);
            RECT jr = _JellyRect(r, j);
            _RR(dc, jr, 6, _LerpColor(sel ? TC_PANEL : TC_BG, TC_ACCENT, j * 0.10f),
                _LerpColor(sel ? TC_ACCENT : TC_BD2, TC_ACCENT, j * 0.50f));
            HBRUSH d = CreateSolidBrush(THEMES[i].dot);
            HBRUSH ob = (HBRUSH)SelectObject(dc, d);
            SelectObject(dc, GetStockObject(NULL_PEN));
            int dotY = by + (chipH - 10) / 2 + (int)(j * 0.5f);
            Ellipse(dc, _PS(bx + 8), _PS(dotY), _PS(bx + 18), _PS(dotY + 10));
            SelectObject(dc, ob); DeleteObject(d);
            HFONT of = (HFONT)SelectObject(dc, fSm);
            _Txt(dc, THEMES[i].name, { bx + 22, by, r.right - 4, by + chipH },
                sel ? C_TACT : _LerpColor(C_TDIM, TC_ACCENT, j * 0.35f));
            SelectObject(dc, of);
            hits.push_back({ r, tid });
        }
        return y + (maxRow + 1) * (chipH + 6);
    }

    void _PaintFooter(HDC dc) {
        int fy = UI_H - FOOT_H;
        _Line(dc, 0, fy, UI_W, fy, RGB(0x1a, 0x1a, 0x1a));
        _Fill(dc, { 0, fy, UI_W, UI_H }, RGB(0x06, 0x06, 0x06));

        HFONT of = (HFONT)SelectObject(dc, fSm);
        _Txt(dc, L"v4.2", { PAD, fy, PAD + 40, UI_H }, C_TSEC);

        bool on = eng->macroEnabled;
        bool hold = false;
        auto skillLbl = _SkillStatusLabel(&hold);
        wchar_t prefix[48];
        swprintf_s(prefix, L"Mode | %s  \u00b7  Skill | ", on ? L"ON" : L"OFF");
        SIZE psz = _Measure(dc, prefix);
        SIZE ssz = _Measure(dc, skillLbl.c_str());
        int right = UI_W - PAD;
        _Txt(dc, prefix, { 80, fy, right - ssz.cx - 2, UI_H }, _ThemeMuted(0.38f), DT_RIGHT);
        _Txt(dc, skillLbl.c_str(), { right - ssz.cx, fy, right, UI_H },
            _SkillThemeColor(hold), DT_RIGHT);
        SelectObject(dc, of);
    }

    void _CommitDelayEdit() {
        if (!delayEditOpen || delMenuSkillIdx < 0) return;
        int ms = delayEditBuf.empty() ? 0 : _wtoi(delayEditBuf.c_str());
        eng->SetSkillHoldMs(delMenuSkillIdx, ms);
        delayEditBuf = std::to_wstring(eng->skills[delMenuSkillIdx].holdMs);
    }

    void _CloseDelMenu(bool commit) {
        if (commit) _CommitDelayEdit();
        delayEditOpen = false;
        showDelMenu = false;
        delMenuSkillIdx = -1;
    }

    void _OpenDelMenu(int skillIdx, RECT anchor) {
        _CloseDelMenu(true);
        delMenuItems.clear();
        delMenuSkillIdx = skillIdx;
        delayEditOpen = false;
        delayFieldRect = {};
        const int itemH = 19, padV = 4, padH = 10, gap = 1;
        const bool combo = skillIdx >= 0 && skillIdx < (int)eng->skills.size()
            && eng->skills[skillIdx].mode == SKF_COMBO;
        const bool hold = skillIdx >= 0 && skillIdx < (int)eng->skills.size()
            && eng->skills[skillIdx].mode == SKF_HOLD;
        const int w = combo ? 114 : 82;
        int top = anchor.bottom + 2;
        int left = anchor.left;
        if (left + w > UI_W - PAD) left = UI_W - PAD - w;
        int y = top + padV;

        DelMenuItem del{};
        del.r = { left + 4, y, left + w - 4, y + itemH };
        del.holdMs = -1;
        delMenuItems.push_back(del);
        y += itemH + 3;

        if (hold) {
            for (int i = 0; i < HOLD_MS_PRESET_COUNT; i++) {
                DelMenuItem it{};
                it.holdMs = HOLD_MS_PRESETS[i];
                it.mark = (eng->skills[skillIdx].holdMs == it.holdMs);
                it.r = { left + padH, y, left + w - padH, y + itemH };
                delMenuItems.push_back(it);
                y += itemH + gap;
            }
        } else if (combo) {
            y += 2;
            delayFieldRect = { left + 8, y + 14, left + w - 8, y + 38 };
            y += 42;
            delayEditOpen = true;
            delayEditBuf = std::to_wstring((std::max)(0, eng->skills[skillIdx].holdMs));
            SetFocus(hw);
        }
        delMenuRect = { left, top, left + w, y + padV };
        showDelMenu = true;
    }

    bool _HandleDelMenuClick(int x, int y) {
        if (!showDelMenu || delMenuSkillIdx < 0) return false;
        if (delayEditOpen && _In(delayFieldRect, x, y)) {
            SetFocus(hw);
            return true;
        }
        for (const auto& it : delMenuItems) {
            if (!_In(it.r, x, y)) continue;
            if (it.holdMs < 0) {
                delayEditOpen = false;
                if (eng->skills.size() > 1) {
                    eng->RemoveSkill(delMenuSkillIdx);
                    _SyncSkillStatus();
                }
            } else {
                eng->SetSkillHoldMs(delMenuSkillIdx, it.holdMs);
            }
            _CloseDelMenu(false);
            InvalidateRect(hw, nullptr, FALSE);
            return true;
        }
        return false;
    }

    void _PaintDelMenu(HDC dc) {
        _RR(dc, delMenuRect, 6, TC_BG, TC_BD2);
        HFONT of = (HFONT)SelectObject(dc, fSm);
        for (size_t i = 0; i < delMenuItems.size(); i++) {
            const auto& it = delMenuItems[i];
            HID id = (HID)(HID_DEL_BASE + (int)i);
            float j = _JellyFor(id);
            RECT jr = _JellyRect(it.r, j);
            if (j > 0.01f)
                _RR(dc, jr, 4, _LerpColor(TC_PANEL, TC_ACCENT, j * 0.12f),
                    _LerpColor(TC_BD2, TC_ACCENT, j * 0.50f));

            if (it.holdMs < 0) {
                _Txt(dc, L"Delete", jr, _LerpColor(C_RED, TC_ACCENT, j * 0.20f),
                    DT_CENTER | DT_VCENTER | DT_SINGLELINE);
                continue;
            }
            if (i == 1) {
                _Line(dc, delMenuRect.left + 4, it.r.top - 2,
                    delMenuRect.right - 4, it.r.top - 2, TC_BD);
            }
            wchar_t lbl[16]{};
            swprintf_s(lbl, L"%dms", it.holdMs);
            const int markW = it.mark ? 16 : 0;
            RECT textR = { jr.left + 4, jr.top, jr.right - markW - 4, jr.bottom };
            _Txt(dc, lbl, textR, it.mark ? TC_ACCENT : _LerpColor(C_TMID, TC_ACCENT, j * 0.25f),
                DT_LEFT | DT_VCENTER | DT_SINGLELINE);
            if (it.mark) {
                RECT markR = { jr.right - 14, jr.top, jr.right - 2, jr.bottom };
                _Txt(dc, L"\u2713", markR, TC_ACCENT, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
            }
        }
        if (delayEditOpen) {
            RECT lab = { delMenuRect.left + 8, delayFieldRect.top - 13,
                delMenuRect.right - 8, delayFieldRect.top - 1 };
            _Txt(dc, L"DELAY (ms)", lab, C_TSEC, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
            _RR(dc, delayFieldRect, 4, TC_PANEL, TC_ACCENT);
            std::wstring shown = delayEditBuf.empty() ? L"0" : delayEditBuf;
            RECT textR = { delayFieldRect.left + 6, delayFieldRect.top,
                delayFieldRect.right - 6, delayFieldRect.bottom };
            _Txt(dc, shown.c_str(), textR, C_TACT, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
            if ((GetTickCount() / 530) % 2 == 0) {
                SIZE sz = _Measure(dc, shown.c_str());
                int cx = textR.left + sz.cx + 1;
                int mid = (delayFieldRect.top + delayFieldRect.bottom) / 2;
                _Line(dc, cx, mid - 6, cx, mid + 6, TC_ACCENT);
            }
        }
        SelectObject(dc, of);
    }

    HID HitTest(int x, int y) {
        if (showDelMenu) {
            if (delayEditOpen && _In(delayFieldRect, x, y))
                return HID_DELAY_EDIT;
            for (size_t i = 0; i < delMenuItems.size(); i++) {
                if (_In(delMenuItems[i].r, x, y))
                    return (HID)(HID_DEL_BASE + (int)i);
            }
        }
        int vTop = _ViewportTop(), vBot = _ViewportBottom();
        if (y >= vTop && y < vBot) {
            for (auto& h : hits) if (_In(h.r, x, y)) return h.id;
        }
        for (auto& h : hits) {
            if (h.id == HID_CLOSE || h.id == HID_MIN) if (_In(h.r, x, y)) return h.id;
        }
        return HID_NONE;
    }

    void OnClick(int x, int y) {
        switch (HitTest(x, y)) {
        case HID_CLOSE:
            comboWnd.Hide();
            DestroyWindow(hw);
            break;
        case HID_MIN: ShowWindow(hw, SW_MINIMIZE); break;

        case HID_SK0: case HID_SK1: case HID_SK2: case HID_SK3: case HID_SK4: {
            int i = HitTest(x, y) - HID_SK0;
            if (i < (int)eng->skills.size()) {
                eng->skillIdx = i;
                eng->CacheFireKey();
                if (showSt)
                    toast.ShowSkill(_SkillToastText(i).c_str(),
                        eng->skills[i].mode == SKF_HOLD);
                if (eng->onSkillChange) eng->onSkillChange(i);
                _SyncSkillStatus();
                InvalidateRect(hw, nullptr, FALSE);
            }
            break;
        }
        case HID_SK_ADD:
            _CloseDelMenu(true);
            showSkillModePicker = true;
            InvalidateRect(hw, nullptr, FALSE);
            break;
        case HID_SK_PICK_CLICK:
            showSkillModePicker = false;
            eng->SetPendingSkillMode(SKF_CLICK);
            _StartCapture("skill", L"Press click skill key...");
            break;
        case HID_SK_PICK_HOLD:
            showSkillModePicker = false;
            eng->SetPendingSkillMode(SKF_HOLD, 500);
            _StartCapture("skill", L"Press hold skill key...");
            break;
        case HID_SK_PICK_COMBO:
            showSkillModePicker = false;
            if ((int)eng->skills.size() < 5)
                comboWnd.ShowNear(hw);
            InvalidateRect(hw, nullptr, FALSE);
            break;
        case HID_BIND_HOLD: _StartCapture("hold", L"Press toggle bind..."); break;
        case HID_BIND_SWITCH: _StartCapture("switch", L"Press switch bind..."); break;
        case HID_BIND_SPAM: _StartCapture("spam", L"Press R spam bind..."); break;
        case HID_SPAM_MODE:
            eng->CycleSpamMode();
            InvalidateRect(hw, nullptr, FALSE);
            break;
        case HID_ATTACH: eng->Reattach(); eng->detector.EnsureOffsets(true); InvalidateRect(hw, nullptr, FALSE); break;
        case HID_CHK_AOT:
            aot = !aot;
            SetWindowPos(hw, aot ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
            InvalidateRect(hw, nullptr, FALSE); break;
        case HID_CHK_SS: showSt = !showSt; InvalidateRect(hw, nullptr, FALSE); break;
        case HID_CHK_DETECT:
            eng->detector.detectEnabled.store(!eng->detector.detectEnabled.load());
            eng->RefreshDetectStatus();
            InvalidateRect(hw, nullptr, FALSE); break;
        case HID_SORU_RACE:
            eng->CycleSoruRace();
            InvalidateRect(hw, nullptr, FALSE); break;
        case HID_TH0: case HID_TH1: case HID_TH2: case HID_TH3: case HID_TH4:
            themeIdx = HitTest(x, y) - HID_TH0;
            ApplyTheme(themeIdx);
            _ApplyThemeToStatuses();
            InvalidateRect(hw, nullptr, TRUE); break;
        case HID_OPEN_STATUS:
            _SyncSkillStatus();
            statusWnd.UpdateMacro(eng->macroEnabled);
            statusWnd.ShowDocked(hw);
            break;
        default: InvalidateRect(hw, nullptr, FALSE); break;
        }
    }

    void _StartCapture(const std::string& type, const wchar_t* prompt) {
        showCapOverlay = true;
        capOverlayTxt = prompt;
        InvalidateRect(hw, nullptr, FALSE);
        eng->StartCapture(type, [this, capType = type](std::wstring name) {
            showCapOverlay = false;
            if (!name.empty() && showSt && capType == "skill") {
                bool hold = false;
                _SkillStatusLabel(&hold);
                toast.ShowSkill(_SkillToastText().c_str(), hold);
                _SyncSkillStatus();
            } else if (!name.empty() && showSt && capType == "spam") {
                wchar_t msg[40]; swprintf_s(msg, L"R spam: %s", name.c_str());
                toast.Show(msg, true);
            } else if (!name.empty() && showSt) {
                wchar_t msg[32]; swprintf_s(msg, L"Skill: %s", name.c_str());
                toast.Show(msg, true);
            }
            PostMessage(hw, WM_APP + 6, 0, 0);
        });
    }

    static LRESULT CALLBACK _Proc(HWND h, UINT m, WPARAM w, LPARAM l) {
        SacredStepUI* ui = (SacredStepUI*)GetWindowLongPtrW(h, GWLP_USERDATA);
        if (m == WM_CREATE) {
            ui = (SacredStepUI*)((CREATESTRUCTW*)l)->lpCreateParams;
            SetWindowLongPtrW(h, GWLP_USERDATA, (LONG_PTR)ui);
            ui->hw = h;
        }
        if (!ui) return DefWindowProcW(h, m, w, l);
        return ui->Proc(m, w, l);
    }

    LRESULT Proc(UINT m, WPARAM w, LPARAM l) {
        switch (m) {
        case WM_PAINT: {
            PAINTSTRUCT ps; HDC hdc = BeginPaint(hw, &ps);
            RECT cr; GetClientRect(hw, &cr);
            HDC mem = CreateCompatibleDC(hdc);
            HBITMAP bmp = CreateCompatibleBitmap(hdc, cr.right, cr.bottom);
            HBITMAP ob = (HBITMAP)SelectObject(mem, bmp);
            SetBkMode(mem, TRANSPARENT);
            Paint(mem);
            BitBlt(hdc, 0, 0, cr.right, cr.bottom, mem, 0, 0, SRCCOPY);
            SelectObject(mem, ob); DeleteDC(mem); DeleteObject(bmp);
            EndPaint(hw, &ps);
            break;
        }
        case WM_LBUTTONDOWN: {
            dragX = (int)(short)LOWORD(l);
            dragY = (int)(short)HIWORD(l);
            int lx = dragX, ly = dragY;
            _ToLog(lx, ly);
            if (_HandleDelMenuClick(lx, ly)) break;
            if (showDelMenu) {
                _CloseDelMenu(true);
                InvalidateRect(hw, nullptr, FALSE);
            }
            if (showSkillModePicker) {
                HID hid = HitTest(lx, ly);
                if (hid == HID_SK_PICK_CLICK || hid == HID_SK_PICK_HOLD || hid == HID_SK_PICK_COMBO) {
                    OnClick(lx, ly);
                } else {
                    showSkillModePicker = false;
                    InvalidateRect(hw, nullptr, FALSE);
                }
                break;
            }
            if (HitTest(lx, ly) == HID_SCALE) {
                scaleDragging = true;
                SetCapture(hw);
                _UpdateScaleFromX(lx);
                break;
            }
            if (HitTest(lx, ly) == HID_SPAM_SPEED) {
                spamSpeedDragging = true;
                SetCapture(hw);
                _SetSpamIntervalFromX(lx);
                break;
            }
            if (HitTest(lx, ly) == HID_NONE) SetCapture(hw);
            OnClick(lx, ly);
            break;
        }
        case WM_MOUSEMOVE: {
            int mx = (int)(short)LOWORD(l);
            int my = (int)(short)HIWORD(l);
            if (scaleDragging && (w & MK_LBUTTON)) {
                int lx = mx, ly = my;
                _ToLog(lx, ly);
                _UpdateScaleFromX(lx);
                break;
            }
            if (spamSpeedDragging && (w & MK_LBUTTON)) {
                int lx = mx, ly = my;
                _ToLog(lx, ly);
                _SetSpamIntervalFromX(lx);
                break;
            }
            if (GetCapture() == hw && (w & MK_LBUTTON) && !scaleDragging && !spamSpeedDragging) {
                RECT wr; GetWindowRect(hw, &wr);
                SetWindowPos(hw, nullptr,
                    wr.left + mx - dragX,
                    wr.top + my - dragY,
                    0, 0, SWP_NOSIZE | SWP_NOZORDER);
            } else {
                TRACKMOUSEEVENT tme{ sizeof(tme), TME_LEAVE, hw, 0 };
                TrackMouseEvent(&tme);
                int lx = mx, ly = my;
                _ToLog(lx, ly);
                _UpdateHover(lx, ly);
            }
            break;
        }
        case WM_MOUSELEAVE:
            hoverId = HID_NONE;
            break;
        case WM_LBUTTONUP:
            scaleDragging = false;
            spamSpeedDragging = false;
            ReleaseCapture();
            break;
        case WM_TIMER:
            if (w == 2) {
                shimmerPhase += SHIMMER_STEP;
                if (shimmerPhase >= SHIMMER_BAND * 2.f) shimmerPhase -= SHIMMER_BAND * 2.f;
                RECT hdr = { 0, 0, _WinW(), (int)(HDR_H * _UiScale() + 0.5f) };
                InvalidateRect(hw, &hdr, FALSE);
            } else if (w == 3) {
                _TickJelly();
            }
            break;
        case WM_MOUSEWHEEL: {
            int delta = GET_WHEEL_DELTA_WPARAM(w);
            scrollY -= (delta / WHEEL_DELTA) * 24;
            if (scrollY < 0) scrollY = 0;
            if (scrollY > scrollMax) scrollY = scrollMax;
            InvalidateRect(hw, nullptr, FALSE);
            return 0;
        }
        case WM_RBUTTONDOWN: {
            int rx = (int)(short)LOWORD(l), ry = (int)(short)HIWORD(l);
            _ToLog(rx, ry);
            if (_HandleDelMenuClick(rx, ry)) break;
            HID rid = HitTest(rx, ry);
            if (rid >= HID_SK0 && rid <= HID_SK4) {
                int idx = rid - HID_SK0;
                if (idx < (int)eng->skills.size()) {
                    for (auto& h : hits) {
                        if (h.id == rid) {
                            _OpenDelMenu(idx, h.r);
                            break;
                        }
                    }
                }
            } else {
                _CloseDelMenu(true);
            }
            showSkillModePicker = false;
            InvalidateRect(hw, nullptr, FALSE);
            break;
        }
        case WM_CHAR:
            if (showDelMenu && delayEditOpen) {
                if (w >= L'0' && w <= L'9') {
                    if (delayEditBuf.size() < 4)
                        delayEditBuf += (wchar_t)w;
                } else if (w == 8) {
                    if (!delayEditBuf.empty()) delayEditBuf.pop_back();
                } else if (w == 13) {
                    _CloseDelMenu(true);
                } else if (w == 27) {
                    _CloseDelMenu(false);
                }
                InvalidateRect(hw, nullptr, FALSE);
                return 0;
            }
            break;
        case WM_KEYDOWN:
            if (showDelMenu && delayEditOpen) {
                if (w == VK_DELETE)
                    delayEditBuf.clear();
                else if (w == VK_RETURN)
                    _CloseDelMenu(true);
                else if (w == VK_ESCAPE)
                    _CloseDelMenu(false);
                InvalidateRect(hw, nullptr, FALSE);
                return 0;
            }
            break;
        case WM_APP + 1:
            statusWnd.UpdateMacro(w != 0);
            if (showSt) toast.Show(w ? L"Macro ON" : L"Macro OFF", w != 0);
            InvalidateRect(hw, nullptr, FALSE);
            break;
        case WM_APP + 2: {
            _SyncSkillStatus();
            if (showSt)
                toast.ShowSkill(_SkillToastText().c_str(),
                    !eng->skills.empty() && eng->skills[eng->skillIdx].mode == SKF_HOLD);
            InvalidateRect(hw, nullptr, FALSE);
            break;
        }
        case WM_APP + 6: case WM_APP + 7: InvalidateRect(hw, nullptr, FALSE); break;
        case WM_APP + 8:
            if (showSt && (int)l == SPAM_TOGGLE)
                toast.Show(w ? L"R spam ON" : L"R spam OFF", w != 0);
            InvalidateRect(hw, nullptr, FALSE);
            break;
        case WM_DESTROY:
            KillTimer(hw, 2);
            KillTimer(hw, 3);
            comboWnd.Hide();
            _CloseDelMenu(true);
            eng->SaveConfig();
            Config::WriteInt(L"UI", L"Theme", themeIdx);
            Config::WriteInt(L"UI", L"AlwaysOnTop", aot ? 1 : 0);
            Config::WriteInt(L"UI", L"Scale", uiScale);
            PostQuitMessage(0);
            break;
        }
        return DefWindowProcW(hw, m, w, l);
    }
};
