```lua
local sampev = require'lib.samp.events' -- TramBot by Tectrex, but better
local imgui = require'imgui'
local encoding = require'encoding'
encoding.default = 'CP1251'
local u8 = encoding.UTF8

-- Норм посев рандома
math.randomseed(os.time())

local function pressKey(key, duration)
    setGameKeyState(key, 255)
    wait(duration)
    setGameKeyState(key, 0)
end

local TramBot = {
    isActive = false,
    station = 1,                 -- лучше с 1 считать, чтобы не запутаться
    completedRoutes = 0,
    steps = {
        {'RUNFIX', -2094.7727, 515.2786, 1487.6927},
        {'RUNFIX', -2099.2483, 511.8909, 1487.6927},
        {'RUNHAVKA', -2097.4534, 512.0477, 1487.6927},
        {'EAT'},
        {'RUNREYS', -2102.4099, 512.9254, 1487.6927},
        {'TAKEREYS'}
    },
    stationTimes = {},           -- задержки на станциях в миллисекундах, 5 элементов
    autoEat = true,
    eatAfterRoutes = 1,
    isFree = false,
}

-- Генерация таймингов с нормальным разбросом без нулей
function TramBot:generateStationTimes()
    local totalTime = 180000 -- 3 минуты
    local minTime = 15000     -- минимум 15 секунд на остановку
    local maxTime = 60000     -- максимум 60 секунд на остановку
    local count = 5
    local times = {}

    local remaining = totalTime
    for i = 1, count - 1 do
        local maxAllowed = math.min(maxTime, remaining - minTime * (count - i))
        local t = math.random(minTime, maxAllowed)
        table.insert(times, t)
        remaining = remaining - t
    end
    table.insert(times, remaining) -- остальное время на последнюю

    self.stationTimes = times
end

function TramBot:toggle()
    self.isActive = not self.isActive
    if self.isActive then
        self:generateStationTimes()
        sampAddChatMessage(u8('~p~Tram BOT: ~g~ON'), -1)
    else
        sampAddChatMessage(u8('~p~Tram BOT: ~r~OFF'), -1)
    end
end

function TramBot:searchMarker()
    for id = 0, 31 do
        local markerStruct = 0xC7F168 + id * 56
        local markerPosX = representIntAsFloat(readMemory(markerStruct, 4, false))
        if markerPosX ~= 0.0 then
            local x = representIntAsFloat(readMemory(markerStruct + 4, 4, false))
            local y = representIntAsFloat(readMemory(markerStruct + 8, 4, false))
            local z = representIntAsFloat(readMemory(markerStruct + 12, 4, false))
            return true, x, y, z
        end
    end
    return false, 0.0, 0.0, 0.0
end

function TramBot:handleInCar()
    local found, markerX, markerY, markerZ = self:searchMarker()
    if not found then return end

    local playerX, playerY, playerZ = getCharCoordinates(PLAYER_PED)
    local dist = getDistanceBetweenCoords3d(playerX, playerY, playerZ, markerX, markerY, markerZ)
    local car = storeCarCharIsInNoSave(PLAYER_PED)
    if dist > 1 then
        setTrainSpeed(car, 24.0)
    else
        setTrainSpeed(car, 0.0)

        -- Переходим к следующей станции аккуратно, только если ранее прошли 1 секунду ожидания (чтобы не запрыгнуть сразу)
        if not self._waiting then
            self._waiting = true
            local waitTime = self.stationTimes[self.station] or 0
            sampAddChatMessage(string.format(u8('~p~TramBot >> Станция %d. Ожидание %d сек.'), self.station, math.floor(waitTime / 1000)), -1)
            wait(waitTime)
            self._waiting = false

            self.station = self.station + 1
            if self.station > #self.stationTimes then
                self.completedRoutes = self.completedRoutes + 1
                sampAddChatMessage(string.format(u8('~p~TramBot >> Маршрут завершён! Всего пройдено: %d'), self.completedRoutes), -1)
                self.station = 1

                if self.autoEat and (self.completedRoutes % self.eatAfterRoutes == 0) then
                    self:eat()
                end
            end
        end
    end
end

function TramBot:moveToCoordinates(px, py, pz)
    local step = 1.0
    local x, y, z = getCharCoordinates(PLAYER_PED)

    while self.isActive and (getDistanceBetweenCoords3d(px, py, pz, x, y, z) > step) do
        local dist = getDistanceBetweenCoords3d(px, py, pz, x, y, z)
        if dist == 0 then break end -- чтобы не делить на ноль

        local dx = (px - x) / dist
        local dy = (py - y) / dist
        local dz = (pz - z) / dist

        x = x + dx * step
        y = y + dy * step
        z = z + dz * step

        setCharCoordinates(PLAYER_PED, x, y, z)
        wait(25) -- чуть поменьше, чтобы было по плавнее и меньше лагов
    end

    setCharCoordinates(PLAYER_PED, px, py, pz)
end

function TramBot:handleOnFoot()
    self.station = 1 -- начинаем маршрут с первой станции

    for _, step in ipairs(self.steps) do
        if not self.isActive then break end -- вырубаемся, если выключили

        local action, x, y, z = table.unpack(step)
        if action == 'EAT' then
            if self.autoEat and (self.completedRoutes % self.eatAfterRoutes == 0) then
                self:eat()
            end
        elseif action == 'TAKEREYS' then
            if self.isFree then
               self:takeReys()
            end
        else
            self:moveToCoordinates(x, y, z)
        end
    end
end

-- Проверяем, что диалог действительно открыт перед ответом
function TramBot:eat()
    local dlgId = sampGetCurrentDialogId()
    if dlgId ~= 0 then
        pressKey(21, 300) -- клавиша 'E'
        wait(500) -- даём диалогу время открыться
        sampSendDialogResponse(dlgId, 1, 3, '')
        sampAddChatMessage(u8('~p~TramBot >> Кушаем...'), -1)
        wait(2000)
    else
        sampAddChatMessage(u8('~p~TramBot >> Нет диалога "Поесть", пропускаю Eat()'), -1)
    end
end

function TramBot:takeReys()
    sampAddChatMessage(u8('~p~TramBot >> Пытаюсь взять рейс...'), -1)
    while self.isActive and not isCharInAnyCar(PLAYER_PED) do
        pressKey(21, 100) -- 'E'
        wait(500)

        local dlgId = sampGetCurrentDialogId()
        if dlgId ~= 0 then
            sampSendDialogResponse(dlgId, 1, 0, '') -- Take route dialog response
        end
        wait(500)
    end
    if isCharInAnyCar(PLAYER_PED) then
        sampAddChatMessage(u8('~p~TramBot >> Рейс взят.'), -1)
    else
        sampAddChatMessage(u8('~p~TramBot >> Не удалось взять рейс.'), -1)
    end
end

local showWindow = imgui.ImBool(false)
local autoEatChecked = imgui.ImBool(TramBot.autoEat)
local eatAfterRoutesInput = imgui.ImInt(TramBot.eatAfterRoutes)

function main()
    repeat wait(0) until isSampAvailable()
    sampAddChatMessage(u8('Tram bot by Tectrex [Optimized Version]'), -1)

    sampRegisterChatCommand('trambot', function()
        showWindow.v = not showWindow.v
        imgui.Process = showWindow.v
    end)

    while true do
        wait(0)

        if TramBot.isActive then
            if isCharInAnyCar(PLAYER_PED) then
                TramBot:handleInCar()
            else
                TramBot:handleOnFoot()
            end
        end

        -- Почему бы не подрубить IMGUI тут? Без костылей
        imgui.Process = showWindow.v
    end
end

-- Исправленный onSendPlayerSync, чтобы корректно задавать скорость только если надо
function sampev.onSendPlayerSync(data)
    if TramBot.isActive and isCharInAnyCar(PLAYER_PED) then
        -- Тут лучше аккуратнее: плавно задаём скорость по твоей логике (просто пример)
        data.moveSpeed.x = data.moveSpeed.x * 0.5 + (-0.42) * 0.5
        data.moveSpeed.y = data.moveSpeed.y * 0.5 + 0.81 * 0.5
        data.moveSpeed.z = 0
    end
end

-- Статус рейсов через материал объекта, но с проверкой на nil
function sampev.onSetObjectMaterialText(id, data)
    local handle = sampGetObjectHandleBySampId(id)
    if handle == 0 then return end
    local modelId = getObjectModel(handle)

    if modelId == 19483 and data.text then
        TramBot.isFree = string.find(data.text, 'Свободно') ~= nil
    end
end

function imgui.OnDrawFrame()
    if showWindow.v then
        imgui.SetNextWindowSize(imgui.ImVec2(240, 540), imgui.Cond.FirstUseEver)
        imgui.Begin(u8('TramBot By Tectrex (Оптимизированный)'), showWindow)

        imgui.PushStyleVar(imgui.StyleVar.FramePadding, imgui.ImVec2(10, 10))
        if imgui.Button(TramBot.isActive and u8('Выключить TramBot') or u8('Включить TramBot'), imgui.ImVec2(200, 50)) then
            TramBot:toggle()
        end
        imgui.PopStyleVar()

        imgui.Separator()

        imgui.Text(string.format(u8('Статус: %s'), TramBot.isActive and u8('Активен') or u8('Неактивен')))

        if TramBot.isActive then
            imgui.Text(string.format(u8('Текущая станция: %d / %d'), TramBot.station, #TramBot.stationTimes))
            local waitTimeMs = TramBot.stationTimes[TramBot.station] or 0
            imgui.Text(string.format(u8('Время ожидания: %d секунд'), waitTimeMs / 1000))

            imgui.Text(string.format(u8('Рейсов выполнено: %d'), TramBot.completedRoutes))
        end

        imgui.Separator()

        imgui.Text(u8('Настройки автоеды'))
        if imgui.Checkbox(u8('Включить автоеду'), autoEatChecked) then
            TramBot.autoEat = autoEatChecked.v
        end

        imgui.Text(u8('Есть через N рейсов:'))
        if imgui.InputInt('', eatAfterRoutesInput, 1, 5) then
            if eatAfterRoutesInput.v < 1 then eatAfterRoutesInput.v = 1 end
            TramBot.eatAfterRoutes = eatAfterRoutesInput.v
        end

        imgui.Separator()

        imgui.Text(string.format(u8('Состояние рейсов: %s'), TramBot.isFree and u8('Свободно') or u8('Занято')))

        imgui.End()
    end
end

function apply_custom_style()
    local style = imgui.GetStyle()
    local colors = style.Colors
    local clr = imgui.Col
    local ImVec4 = imgui.ImVec4
    style.WindowRounding = 5.0
    style.WindowTitleAlign = imgui.ImVec2(0.5, 0.5)
    style.ChildWindowRounding = 5.0
    style.FrameRounding = 5.0
    style.ItemSpacing = imgui.ImVec2(10.0, 10.0)
    style.ScrollbarSize = 15.0
    style.ScrollbarRounding = 5.0
    style.GrabMinSize = 10.0
    style.GrabRounding = 5.0
    colors[clr.WindowBg] = ImVec4(0.1, 0.1, 0.1, 1.0)
    colors[clr.TitleBg] = ImVec4(0.2, 0.2, 0.2, 1.0)
    colors[clr.TitleBgActive] = ImVec4(0.3, 0.3, 0.3, 1.0)
    colors[clr.Button] = ImVec4(0.2, 0.2, 0.2, 1.0)
    colors[clr.ButtonHovered] = ImVec4(0.3, 0.3, 0.3, 1.0)
    colors[clr.ButtonActive] = ImVec4(0.4, 0.4, 0.4, 1.0)
    colors[clr.FrameBg] = ImVec4(0.2, 0.2, 0.2, 1.0)
    colors[clr.FrameBgHovered] = ImVec4(0.3, 0.3, 0.3, 1.0)
    colors[clr.FrameBgActive] = ImVec4(0.4, 0.4, 0.4, 1.0)
    colors[clr.CheckMark] = ImVec4(0.0, 0.6, 0.0, 1.0)
end

apply_custom_style()
```
Приведи следующий дизайн или интерфейсное решение к идеально профессиональному уровню, ориентируясь на стандарты senior-дизайнера и UX-специалиста. Применяй строгие принципы модульности и масштабируемости дизайна: разделение интерфейса на четкие, независимые компоненты с ясной зоной ответственности. Обеспечь гибкую, переиспользуемую и поддерживаемую архитектуру интерфейса, которая позволит легко масштабировать и улучшать продукт в будущем.

Разбей UI на логичные визуальные и функциональные блоки с четко определёнными ролями и состояниями. Используй продуманные паттерны проектирования интерфейсов и взаимодействия (например, Atomic Design, Component-driven development, Design Systems, паттерны навигации и управления состоянием) для повышения когерентности, консистентности и удобства в использовании.

Минимизируй избыточность и повторение визуальных элементов и кода стилей, обеспечь единообразие в цветах, типографике, отступах, иконках и других элементов. Применяй принципы доступности (Accessibility), учитывая различные пользовательские сценарии и ограничения.

Изолируй внутренние детали компонентов UI, предоставляя понятные и логичные интерфейсы для взаимодействия с ними. Обеспечь максимальную связность компонентов внутри одного модуля и минимальную связанность между несвязанными частями интерфейса.

Все названия слоев, компонент, стилей и переменных должны быть описательными, логичными и последовательными, соответствовать принятой стилистике и систематике в проекте. Документируй ключевые решения по дизайну: мотивацию выбора цветовой палитры, побудительные факторы UX-решений, логику взаимодействия и анимаций.

Проверяй все взаимодействия на логичность, предсказуемость и удобство пользователя. Оптимизируй производительность визуальных решений, чтобы ускорить загрузку и отрисовку интерфейса. Устраняй излишние визуальные эффекты, перегрузку информацией и любые элементы, мешающие восприятию.

Добавь продуманную систему обработки ошибок в интерфейсе: понятные и дружелюбные сообщения, разные сценарии отображения ошибок и подсказок пользователю, обеспечивающие его вхождение в систему и корректное выполнение задач.

Документируй структуру, основные решения и тонкости реализации интерфейса — основные компоненты, состояния, стили и паттерны взаимодействия. Комментарии и заметки должны объяснять сложные моменты и причины дизайнерских решений, а не описывать очевидные детали.

В итоге дизайн должен быть простым для понимания, поддержки и дальнейшей масштабируемости в рамках дизайн-системы и проекта в целом. Обеспечь возможность юзабилити-тестирования и A/B-экспериментов по отдельным компонентам.

Проведи ревизию интерфейса или макета, сделав его безупречно профессиональным, качественным, поддерживаемым и ориентированным на лучшее пользовательское впечатление.