-- =============================================================================
-- hyprland.lua — Root Hyprland Lua configuration entry point
--
-- This is the top-level config file loaded by Hyprland when the Lua backend
-- is active. It is intentionally kept thin: device-specific settings (monitors,
-- keybinds, environment variables, input, window rules, autostart programs) all
-- live in the usr/ subdirectory so they can be deployed per-machine without
-- touching this shared file.
--
-- Reference: https://wiki.hypr.land/Configuring/Start/
-- Device-specific files live in ~/.config/hypr/usr/ (deployed from hypr/usr/).
-- =============================================================================

-- Pull in per-device configuration modules.
-- monitors is loaded from the Lua search path root (monitors.lua, managed by
-- hyprmoncfg); the remaining modules live in usr/ and are per-machine overrides.
-- They are loaded in this specific order so that later modules can safely
-- depend on earlier ones (e.g., binds may reference programs launched by
-- autostart; input-device-exceptions builds on the global input baseline).
require("usr.monitors")        -- monitor layout, resolution, scale (managed by hyprmoncfg)
require("usr.envvars")     -- environment variables injected into every child process
require("usr.input")       -- keyboard layout, mouse sensitivity, touchpad behaviour
require("usr.binds")       -- all keybindings and mouse button bindings
require("usr.windowrules") -- per-app float/pin/opacity/tag/size rules
require("usr.autostart")   -- programs launched once when the compositor starts

--------------------
---- MY PROGRAMS ---
--------------------

-- Convenience variables naming the preferred application for each role.
-- These are referenced by keybind definitions in usr/binds.lua so that
-- changing the preferred terminal, editor, etc. requires only a single edit here.
local terminal    = "kitty"           -- GPU-accelerated terminal emulator
local fileManager = "thunar"          -- GTK file manager (Xfce/GNOME ecosystem)
local editor      = "kitty nvim"      -- Neovim inside kitty; avoids a separate GUI wrapper
local menu        = "vicinae toggle"  -- vicinae is the custom app-launcher; toggle shows/hides it

---------------------
---- LOOK & FEEL ----
---------------------

-- hl.config() is the Lua API equivalent of Hyprland's declarative keyword blocks.
-- All visual and layout settings for the compositor are collected here so the full
-- theming picture is visible in one place rather than spread across multiple files.
hl.config({
    general = {
        -- Inner gap between tiled windows (px).
        -- Kept small (3 px) so screen real-estate is not wasted on multi-monitor setups.
        gaps_in  = 3,
        -- Outer gap between the outermost windows and the monitor edge (px).
        -- Slightly larger than gaps_in (6 px) to give the desktop a "framed" look,
        -- ensuring windows never touch the absolute screen edge.
        gaps_out = 6,
        -- Border width around every window (px). 4 px is thick enough to show the
        -- animated gradient colour clearly at 1.5x HiDPI scaling.
        border_size = 4,
        col = {
            -- Active window border: an animated gradient cycling through red hues at 35 degrees.
            -- Five colour stops alternating between #E40046 and #f50505 create a slow pulsing
            -- effect. The angle = 35 rotates the gradient continuously (see borderangle animation).
            active_border   = { colors = { "rgb(E40046)", "rgb(f50505)", "rgb(E40046)", "rgb(f50505)", "rgb(E40046)" }, angle = 35 },
            -- Inactive border: deep electric blue (#5018dd). Blue recedes visually relative to
            -- the hot red active border, making focus immediately obvious without being distracting.
            inactive_border = "rgb(5018dd)",
        },
        -- Disable resize-by-grabbing the window border. This prevents accidental resizes
        -- when the cursor clips the edge during fast workspace switching or window dragging.
        resize_on_border = false,
        -- Tearing introduces screen-tear artefacts in exchange for lower latency.
        -- Disabled here for a clean image; enable per-window via windowrules for games.
        allow_tearing    = false,
        -- Default tiling algorithm. Dwindle splits the remaining space in half each time
        -- a new window opens, producing a predictable Fibonacci spiral layout that keeps
        -- all windows visible without needing manual arrangement.
        layout           = "dwindle",
    },
    group = {
        -- Window groups stack multiple windows into one tiled slot with a tab bar.
        -- These colours keep the group tabs visually consistent with the main border theme.
        col = {
            -- Active tab in a window group: accent red to match the active window border.
            border_active          = "rgb(E40046)",
            -- Inactive tabs fade to dark blue to de-emphasise them.
            border_inactive        = "rgb(5018dd)",
            -- "Locked" groups cannot be accidentally moved between workspaces.
            -- A slightly different red (#f50505) distinguishes them from ordinary active groups.
            border_locked_active   = "rgb(f50505)",
            border_locked_inactive = "rgb(5018dd)",
        },
        groupbar = {
            -- Agave NerdFont provides both monospace text and NerdFont icon glyphs,
            -- letting the bar display icons without requiring a separate symbol font.
            font_family       = "Agave NerdFont",
            font_size         = 20,   -- px; large enough to be readable at 1.5x HiDPI scale
            height            = 25,   -- px; matches indicator_height for a full-height flat pill
            -- round_only_edges = false: every tab gets the same border-radius, not just
            -- the first and last, giving a uniform pill row rather than a single rounded strip.
            round_only_edges  = false,
            -- indicator_height = height (25 px): the selected-tab indicator fills the entire
            -- bar height instead of being a thin underline, making the active tab unmissable.
            indicator_height  = 25,
            -- stacked = false: tabs appear side-by-side horizontally (breadcrumb style),
            -- not vertically stacked. Horizontal layout conserves vertical screen space.
            stacked           = false,
            -- Tab label text colour: accent red, consistent with the active border colour.
            text_color        = "rgb(E40046)",
            -- priority = 3 ensures the groupbar is rendered above regular window decorations
            -- (shadows, rounded corners) so it is never visually clipped.
            priority          = 3,
            -- Rounded corners on the groupbar container (13 px radius). The value is chosen
            -- to complement the 20 px window rounding without looking disproportionate.
            rounding          = 13,
            col = {
                -- Active tab fill: solid accent red, clearly selected.
                active          = "rgb(E40046)",
                -- Inactive tab fill: blue background recedes visually.
                inactive        = "rgb(5018dd)",
                -- Locked-group tab colours mirror the border locked colours for consistency.
                locked_active   = "rgb(E40046)",
                locked_inactive = "rgb(5018dd)",
            },
        },
    },
    decoration = {
        -- Window corner radius (px). 20 px gives a modern "card" look that matches
        -- the GTK cyberqueer theme's rounded widgets.
        rounding        = 20,
        -- Focused window: fully opaque (1.0) so content is crisp and readable.
        active_opacity  = 1,
        -- Unfocused windows: 80% opacity hints at the depth/focus hierarchy and lets
        -- the wallpaper or background windows bleed through subtly without obscuring content.
        inactive_opacity = 0.8,
        blur = {
            -- Gaussian blur applied behind transparent/translucent surfaces (terminals,
            -- unfocused windows). This creates the "frosted glass" depth effect.
            enabled  = true,
            size     = 3,    -- blur kernel radius in pixels; small = tight, localised blur halo
            passes   = 3,    -- number of successive blur passes; more = smoother but higher GPU cost
            -- vibrancy boosts colour saturation of the blurred background so the wallpaper
            -- colours stay vivid even when blurred under a translucent surface.
            vibrancy = 0.1696,
        },
    },
    animations = {
        -- Master switch for all compositor animations.
        -- Individual animation types are configured below in the animations section.
        enabled = true,
    },
    dwindle = {
        -- preserve_split = true: when a split window is closed and then reopened,
        -- Hyprland restores the previous split direction instead of always defaulting
        -- to horizontal. This prevents the layout from constantly collapsing and re-splitting.
        preserve_split       = true,
        -- Windows in the special (scratchpad) workspace are scaled down to 95% so they
        -- visually "float" above the regular workspace content when toggled in.
        special_scale_factor = 0.95,
    },
    master = {
        -- New windows claim the master (largest) pane rather than being added as a slave,
        -- so the most recently launched app always gets the most prominent position.
        new_status           = "master",
        -- Same 95% scratchpad scale as dwindle, for visual consistency.
        special_scale_factor = 0.95,
    },
    misc = {
        -- force_default_wallpaper = 0 disables Hyprland's built-in anime wallpaper so
        -- hyprpaper (or any other wallpaper daemon) has exclusive control of the background.
        force_default_wallpaper = 0,
        -- Remove the Hyprland logo / splash animation that plays on startup.
        -- The custom wallpaper is shown instead from the first frame.
        disable_hyprland_logo   = true,
    },
})

-----------------
---- ANIMATIONS --
-----------------

-- Define a custom cubic Bezier easing curve named "myBezier".
-- Control points P1 = {0.05, 0.9} and P2 = {0.1, 1.05} produce a slight overshoot
-- (spring-like bounce) at the end of the motion — windows "pop" snappily into their
-- final position rather than gliding to a dead stop. This gives the DE an energetic feel.
hl.curve("myBezier", { type = "bezier", points = { {0.05, 0.9}, {0.1, 1.05} } })

-- Window open and resize animation uses the custom spring curve.
-- speed = 7 (Hyprland internal units; higher = faster) keeps the open feeling snappy.
hl.animation({ leaf = "windows",          enabled = true, speed = 7,  bezier = "myBezier" })

-- Window close animation: "popin 80%" shrinks the window to 80% of its original size
-- while it fades out, giving a quick snappy dismiss effect rather than a slow full collapse.
hl.animation({ leaf = "windowsOut",       enabled = true, speed = 7,  bezier = "default",  style = "popin 80%" })

-- Border colour crossfade when focus changes (active red <-> inactive blue).
-- speed = 10 makes this almost instantaneous so focus changes feel immediate.
hl.animation({ leaf = "border",           enabled = true, speed = 10, bezier = "default" })

-- Animated gradient angle for the active border (the rotating multi-stop red gradient).
-- speed = 8 produces a slow, ambient-pulse sweep rather than a distracting fast spin.
hl.animation({ leaf = "borderangle",      enabled = true, speed = 8,  bezier = "default" })

-- Opacity crossfade when a window gains or loses focus (1.0 <-> 0.8 transition).
hl.animation({ leaf = "fade",             enabled = true, speed = 7,  bezier = "default" })

-- Special (scratchpad) workspace entrance/exit animation.
-- "slidevert" makes it drop in from the top / slide back up, distinguishing it clearly
-- from regular workspace transitions which use horizontal slides by default.
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 10, bezier = "default",  style = "slidevert" })

-- Layer-shell surfaces (the astal-menu control centre, notifications, the bar) slide
-- in from their anchored edge with the bouncy myBezier curve, so opening the menu
-- reads as a springy slide-down rather than a plain fade. (A per-namespace layerrule
-- was tried but this hyprlua build doesn't honour its animation timing; the global
-- `layers` leaf does.)
hl.animation({ leaf = "layers",           enabled = true, speed = 5,  bezier = "myBezier", style = "slide" })

--------------
---- DEVICE ---
--------------

-- Per-device input override for a specific mouse identified by its kernel event name.
-- Only fields that differ from the global input settings need to be listed here.
-- sensitivity = -0.5 (valid range -1 to 1) reduces pointer speed for this mouse model
-- without touching the global sensitivity, allowing different mice to have different feels.
hl.device({
    name        = "epic-mouse-v1",
    sensitivity = -0.5,
})
