# settings/hyprland.nix
{ config, pkgs, lib, inputs, ... }:
let
  hyprland-pkgs = inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system};
  anyrun-pkgs   = inputs.anyrun.packages.${pkgs.stdenv.hostPlatform.system};

  isMacbook = config.networking.hostName == "FredOS-Macbook";
  isGaming  = !isMacbook;

in
{
  config = lib.mkIf (lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]) {
    programs.hyprland = {
      enable = true;
      xwayland.enable = true;
      package       = hyprland-pkgs.hyprland;
      portalPackage = hyprland-pkgs.xdg-desktop-portal-hyprland;
    };

    xdg.portal = {
      enable = true;
      # xdg-desktop-portal-hyprland is registered automatically by
      # programs.hyprland.portalPackage; listing it here too produced a
      # duplicate user-unit symlink during nixos-rebuild.
      extraPortals = with pkgs; [
        xdg-desktop-portal-gtk
      ];
      config.hyprland.default = [ "hyprland" "gtk" ];
    };

    security.polkit.enable = true;

    # Polkit GUI agent for GUI sudo prompts under Hyprland
    systemd.user.services.polkit-gnome-authentication-agent-1 = {
      description = "polkit-gnome-authentication-agent-1";
      wantedBy = [ "graphical-session.target" ];
      partOf = [ "graphical-session.target" ];
      after = [ "graphical-session.target" ];
      serviceConfig = {
        Type = "simple";
        ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1";
        Restart = "on-failure";
      };
    };

    environment.systemPackages = with pkgs; [
      ghostty
      mako
      grim
      slurp
      wl-clipboard
      cliphist
      brightnessctl
      swayosd
      playerctl
      hyprpaper
      hyprlock
      hypridle
      hyprshot
      networkmanagerapplet
      pavucontrol
      polkit_gnome
      quickshell
      qt6.qt5compat
    ];

    # Use upstream anyrun flake's HM module instead of the built-in one
    # for working daemon mode.
    home-manager.sharedModules = [
      ({ modulesPath, ... }: {
        disabledModules = [ "${modulesPath}/programs/anyrun.nix" ];
      })
      inputs.anyrun.homeManagerModules.default
    ];

    home-manager.users.fred = { config, lib, pkgs, inputs, ... }:
    let
      c    = config.lib.stylix.colors;
      rgb  = hex: "rgb(${hex})";
      rgba = hex: a: "rgba(${hex}${a})";
    in {
      # Stylix's Hyprland target injects settings.{general,decoration,group,misc}
      # as top-level keys, which render as hl.general()/hl.decoration()/… in Lua
      # mode — functions that don't exist.  Disable it and absorb the colours
      # into settings.config below.
      stylix.targets.hyprland.enable = false;

      # The disabled Hyprland target would normally enable this; do it
      # manually.  Stylix's hyprpaper target (auto-enabled) still handles
      # preload/wallpaper settings.
      services.hyprpaper.enable = true;

      wayland.windowManager.hyprland = {
        enable = true;
        configType = "lua";
        systemd.variables = [ "--all" ];
        package = hyprland-pkgs.hyprland;

        settings = {
          # hl.config({...}) — all static named-section configuration.
          # monitor is set per-host in hosts/FredOS-{Gaming,Macbook}.nix.
          config = {
            general = {
              gaps_in = 6;
              gaps_out = 12;
              border_size = 2;
              layout = "dwindle";
              resize_on_border = true;
              "col.active_border"   = rgb c.base0D;
              "col.inactive_border" = rgb c.base03;
            };

            decoration = {
              rounding = 8;
              blur = {
                enabled = true;
              };
              shadow.color = rgba c.base00 "99";
            };

            group = {
              "col.border_active"        = rgb c.base0D;
              "col.border_inactive"      = rgb c.base03;
              "col.border_locked_active" = rgb c.base0C;
              groupbar = {
                text_color    = rgb c.base05;
                "col.active"  = rgb c.base0D;
                "col.inactive" = rgb c.base03;
              };
            };

            render = {
              direct_scanout = false;
            };

            animations = {
              enabled = true;
            };

            input = {
              kb_layout = "gb,no";
              kb_options = "grp:alt_shift_toggle";
              follow_mouse = 1;
              accel_profile = "flat";
              sensitivity = 0;
            } // lib.optionalAttrs isMacbook {
              touchpad = {
                tap_to_click = true;
                tap_button_map = "lrm";
                natural_scroll = true;
              };
            };

            cursor = {
              no_warps = true;
            };

            dwindle = {
              preserve_split = true;
            };

            misc = {
              disable_hyprland_logo = true;
              disable_splash_rendering = true;
              # Apps demanding attention don't get to yank focus — they'll
              # show as urgent in the bar instead.
              focus_on_activate = false;
              vrr = 2;
              background_color = rgb c.base00;
            };

            # vfr moved from misc: to debug: in 0.55.0
            debug = {
              vfr = false; # keep compositor ticking, don't idle between frames
              disable_logs = false;
            };
          };
        };

        extraConfig =
          let
            powerMenu = pkgs.writeShellScript "power-menu" ''
              # Stop the daemon so standalone stdin mode can run cleanly.
              # systemd restarts it automatically afterwards (Restart=on-failure).
              systemctl --user stop anyrun.service 2>/dev/null || true
              choice=$(printf '%s\n' \
                $'\uf023  Lock' \
                $'\uf08b  Logout' \
                $'\uf01e  Reboot' \
                $'\uf011  Shutdown' \
                | ${anyrun-pkgs.anyrun}/bin/anyrun \
                    --plugins "${anyrun-pkgs.stdin}/lib/libstdin.so" \
                    --show-results-immediately true \
                    --hide-plugin-info true \
                    --close-on-click true)
              # Restart the daemon service (reset-failed clears the start-rate limiter).
              systemctl --user reset-failed anyrun.service 2>/dev/null
              systemctl --user start anyrun.service 2>/dev/null
              case "$choice" in
                *Lock)     ${pkgs.hyprlock}/bin/hyprlock ;;
                *Logout)   hyprctl dispatch exit ;;
                *Reboot)   systemctl reboot ;;
                *Shutdown) systemctl poweroff ;;
              esac
            '';
            kbdBrightUp = pkgs.writeShellScript "kbd-bright-up" ''
              ${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight set +10%
              brightness=$(${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight get)
              max=$(${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight max)
              echo $(( brightness * 100 / max )) > "$XDG_RUNTIME_DIR/wob.fifo"
            '';
            kbdBrightDown = pkgs.writeShellScript "kbd-bright-down" ''
              ${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight set 10%-
              brightness=$(${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight get)
              max=$(${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight max)
              echo $(( brightness * 100 / max )) > "$XDG_RUNTIME_DIR/wob.fifo"
            '';
          in
          ''
            -- Environment
            hl.env("XCURSOR_THEME", "Bibata-Modern-Ice")
            hl.env("XCURSOR_SIZE", "24")
            hl.env("HYPRCURSOR_THEME", "Bibata-Modern-Ice")
            hl.env("HYPRCURSOR_SIZE", "24")
            hl.env("ELECTRON_OZONE_PLATFORM_HINT", "wayland")
            hl.env("MOZ_ENABLE_WAYLAND", "1")
            hl.env("QT_QPA_PLATFORM", "wayland;xcb")
            hl.env("SDL_VIDEODRIVER", "wayland")
            hl.env("_JAVA_AWT_WM_NONREPARENTING", "1")
            ${lib.optionalString isGaming ''
            -- GPU pinning — Navi 22 is card1 on the dual-GPU gaming box.
            hl.env("AQ_DRM_DEVICES", "/dev/dri/card1")
            hl.env("DRI_PRIME", "pci-0000_03_00_0")
            ''}

            -- Startup
            hl.on("hyprland.start", function()
              -- Ensure hyprland-session.target starts even if HM's
              -- dbus-update-activation-environment chain fails upstream.
              hl.exec_cmd("systemctl --user start hyprland-session.target")
              hl.exec_cmd("qs")
              hl.exec_cmd("mako")

              hl.exec_cmd("wl-paste --type text --watch cliphist store")
              hl.exec_cmd("wl-paste --type image --watch cliphist store")
              hl.exec_cmd("hyprctl setcursor Bibata-Modern-Ice 24")
              hl.exec_cmd("swayosd-server")
              ${lib.optionalString isMacbook ''hl.exec_cmd("hypridle")''}
            end)

            -- Animation curve and definitions
            hl.curve("snap", { type = "bezier", points = { {0.05, 0.9}, {0.1, 1.0} } })
            hl.animation({ leaf = "windows",    enabled = true, speed = 1, bezier = "snap" })
            hl.animation({ leaf = "windowsOut", enabled = true, speed = 1, bezier = "snap", style = "popin 80%" })
            hl.animation({ leaf = "layers",     enabled = true, speed = 1, bezier = "snap" })
            hl.animation({ leaf = "border",     enabled = true, speed = 2, bezier = "default" })
            hl.animation({ leaf = "fade",       enabled = true, speed = 1, bezier = "default" })
            hl.animation({ leaf = "workspaces", enabled = true, speed = 1, bezier = "snap" })

            -- Window rules
            -- Battle.net tray icon leaks as a tiny floating XWayland window.
            hl.window_rule({
              match = { class = "steam_app_0", title = "^$", float = true },
              workspace = "special silent",
            })

            -- Binds
            local mod = "SUPER"

            -- Apps
            hl.bind(mod .. " + T", hl.dsp.exec_cmd("ghostty"))
            hl.bind(mod .. " + E", hl.dsp.exec_cmd("nemo"))
            hl.bind(mod .. " + R", hl.dsp.exec_cmd("anyrun close || anyrun"))
            hl.bind(mod .. " + Q", hl.dsp.window.close())
            hl.bind(mod .. " + SHIFT + E", hl.dsp.exit())

            -- Floating / layout
            hl.bind(mod .. " + V", hl.dsp.window.float({ action = "toggle" }))
            hl.bind(mod .. " + F", hl.dsp.window.fullscreen())
            hl.bind(mod .. " + P", hl.dsp.window.pseudo())
            hl.bind(mod .. " + S", hl.dsp.layout("togglesplit"))

            -- Focus
            hl.bind(mod .. " + left",  hl.dsp.focus({ direction = "left" }))
            hl.bind(mod .. " + right", hl.dsp.focus({ direction = "right" }))
            hl.bind(mod .. " + up",    hl.dsp.focus({ direction = "up" }))
            hl.bind(mod .. " + down",  hl.dsp.focus({ direction = "down" }))
            hl.bind(mod .. " + H",     hl.dsp.focus({ direction = "left" }))
            hl.bind(mod .. " + K",     hl.dsp.focus({ direction = "up" }))
            hl.bind(mod .. " + J",     hl.dsp.focus({ direction = "down" }))

            -- Power menu — dismiss launcher if open, then show menu
            hl.bind(mod .. " + L", hl.dsp.exec_cmd("anyrun close 2>/dev/null; ${powerMenu}"))

            -- Move windows
            hl.bind(mod .. " + SHIFT + left",  hl.dsp.window.move({ direction = "left" }))
            hl.bind(mod .. " + SHIFT + right", hl.dsp.window.move({ direction = "right" }))
            hl.bind(mod .. " + SHIFT + up",    hl.dsp.window.move({ direction = "up" }))
            hl.bind(mod .. " + SHIFT + down",  hl.dsp.window.move({ direction = "down" }))

            -- Workspaces
            for i = 0, 9 do
              local workspace_id = tostring((i == 0) and 10 or i)
              hl.bind(mod .. " + " .. i, hl.dsp.focus({ workspace = workspace_id }))
              hl.bind(mod .. " + SHIFT + " .. i, hl.dsp.window.move({ workspace = workspace_id, follow = false }))
            end

            -- Screenshots — Shift+Super+S matches GNOME binding
            hl.bind(mod .. " + SHIFT + S", hl.dsp.exec_cmd("hyprshot -m region --clipboard-only"))
            hl.bind("Print",               hl.dsp.exec_cmd("hyprshot -m output --clipboard-only"))

            -- Settings shortcut — Super+I matches GNOME binding
            hl.bind(mod .. " + I", hl.dsp.exec_cmd("pavucontrol"))

            -- Custom shortcuts
            hl.bind(mod .. " + Z", hl.dsp.exec_cmd("zen-beta"))

            -- Mouse window manipulation
            hl.bind(mod .. " + mouse:272", hl.dsp.window.drag(),   { mouse = true })
            hl.bind(mod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })

            -- Volume / brightness (repeating)
            hl.bind("XF86AudioRaiseVolume",  hl.dsp.exec_cmd("swayosd-client --output-volume raise"),       { repeating = true })
            hl.bind("XF86AudioLowerVolume",  hl.dsp.exec_cmd("swayosd-client --output-volume lower"),       { repeating = true })
            hl.bind("XF86AudioMute",         hl.dsp.exec_cmd("swayosd-client --output-volume mute-toggle"), { repeating = true })
            hl.bind("XF86MonBrightnessUp",   hl.dsp.exec_cmd("swayosd-client --brightness raise"),          { repeating = true })
            hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("swayosd-client --brightness lower"),          { repeating = true })
            ${lib.optionalString isMacbook ''
            hl.bind("XF86KbdBrightnessUp",   hl.dsp.exec_cmd("${kbdBrightUp}"),   { repeating = true })
            hl.bind("XF86KbdBrightnessDown", hl.dsp.exec_cmd("${kbdBrightDown}"), { repeating = true })
            ''}

            -- Media keys (locked — work through lockscreen)
            hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
            hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"),        { locked = true })
            hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"),    { locked = true })
          '';
      };

      programs.anyrun = {
        enable = true;
        config = {
          plugins = [ anyrun-pkgs.applications ];
          x.fraction = 0.5;
          y.fraction = 0.25;
          width.absolute = 350;
          height.absolute = 0;
          hideIcons = false;
          ignoreExclusiveZones = false;
          layer = "overlay";
          hidePluginInfo = true;
          closeOnClick = true;
          maxEntries = 8;
        };
        extraCss =
          let c = config.lib.stylix.colors; in
          ''
            * { all: unset; font-family: "FiraMono Nerd Font", monospace; font-size: 13px; }
            window { background: transparent; }
            box.main {
              background: #${c.base00};
              border: 1px solid #${c.base03};
              border-radius: 10px;
              padding: 8px;
              margin: 16px;
            }
            text {
              background: #${c.base01};
              color: #${c.base05};
              caret-color: #${c.base0D};
              padding: 8px 16px;
              border-radius: 6px;
              min-height: 0;
            }
            list.plugin { background: transparent; }
            .matches    { background: transparent; }
            .match {
              padding: 4px 16px;
              border-radius: 6px;
              color: #${c.base05};
              background: transparent;
            }
            .match:selected {
              background: #${c.base02};
              border: none;
            }
            label.match.description { color: #${c.base04}; font-size: 11px; }
          '';
        extraConfigFiles."applications.ron".text = ''
          Config(
            desktop_actions: false,
            max_entries: 8,
            terminal: Some("ghostty"),
          )
        '';
      };

      programs.hyprlock.enable = true;

      services.hypridle = lib.mkIf isMacbook {
        enable = true;
        settings = {
          general = {
            lock_cmd         = "pidof hyprlock || hyprlock";
            before_sleep_cmd = "loginctl lock-session";
            after_sleep_cmd  = "hyprctl dispatch dpms on";
          };
          listener = [
            {
              timeout    = 300;   # 5 min — lock
              on-timeout = "loginctl lock-session";
            }
            {
              timeout    = 420;   # 7 min — display off
              on-timeout = "hyprctl dispatch dpms off";
              on-resume  = "hyprctl dispatch dpms on";
            }
            {
              timeout    = 600;   # 10 min — suspend
              on-timeout = "systemctl suspend";
            }
          ];
        };
      };

      # Scope all HM Wayland services (hyprpaper, etc.) to the
      # Hyprland session so they don't crash-loop in a GNOME session.
      wayland.systemd.target = "hyprland-session.target";

      xdg.configFile."quickshell/shell.qml" = {
        text = ''
          //@ pragma UseQApplication
          import Quickshell
          import Quickshell.Hyprland
          import Quickshell.Services.SystemTray
          import Quickshell.Widgets
          import Quickshell.Io
          import QtQuick
          import QtQuick.Layouts
          import Qt5Compat.GraphicalEffects

          ShellRoot {
              Variants {
                  model: Quickshell.screens

                  PanelWindow {
                      id: bar
                      required property var modelData
                      screen: modelData

                      anchors {
                          top: true
                          left: true
                          right: true
                      }

                      implicitHeight: 30
                      color: "#D1${c.base00}"

                      // Left — workspaces
                      Row {
                          anchors.left: parent.left
                          anchors.leftMargin: 6
                          anchors.verticalCenter: parent.verticalCenter
                          spacing: 0

                          Repeater {
                              model: Hyprland.workspaces

                              Item {
                                  required property var modelData
                                  width: 28
                                  height: 30

                                  Text {
                                      anchors.centerIn: parent
                                      text: modelData.name
                                      color: modelData.focused ? "#${c.base05}" : "#${c.base03}"
                                      font.family: "FiraMono Nerd Font"
                                      font.pixelSize: 13
                                  }

                                  Rectangle {
                                      anchors.bottom: parent.bottom
                                      anchors.horizontalCenter: parent.horizontalCenter
                                      width: parent.width - 8
                                      height: 2
                                      color: "#${c.base05}"
                                      visible: modelData.focused
                                  }

                                  MouseArea {
                                      anchors.fill: parent
                                      onClicked: modelData.activate()
                                  }
                              }
                          }
                      }

                      // Center — clock
                      Text {
                          id: clockText
                          anchors.centerIn: parent
                          property date now: new Date()
                          text: now.toLocaleTimeString(Qt.locale(), "HH:mm")
                          color: "#${c.base05}"
                          font.family: "FiraMono Nerd Font"
                          font.pixelSize: 13
                          font.weight: Font.Medium

                          Timer {
                              interval: 1000
                              running: true
                              repeat: true
                              onTriggered: clockText.now = new Date()
                          }

                          MouseArea {
                              anchors.fill: parent
                              onClicked: {
                                  if (calPopup.visible) {
                                      calPopup.open = false;
                                      calCloseTimer.start();
                                  } else {
                                      calPopup.visible = true;
                                  }
                              }
                          }

                          Timer {
                              id: calCloseTimer
                              interval: 240
                              onTriggered: calPopup.visible = false
                          }
                      }

                      // Right — network, battery, tray
                      Row {
                          anchors.right: parent.right
                          anchors.rightMargin: 8
                          anchors.verticalCenter: parent.verticalCenter
                          spacing: 10

                          // Network status
                          Item {
                              id: netWidget
                              width: 16
                              height: 30

                              property string netState: "disconnected"
                              property string netConn: ""
                              property string netType: ""
                              property string netIcon: "\u{f0b0}"

                              Timer {
                                  interval: 5000
                                  running: true
                                  repeat: true
                                  triggeredOnStart: true
                                  onTriggered: netProc.running = true
                              }

                              Process {
                                  id: netProc
                                  command: ["${pkgs.networkmanager}/bin/nmcli", "-t", "-f", "DEVICE,TYPE,STATE,CONNECTION", "device"]
                                  stdout: SplitParser {
                                      onRead: data => {
                                          let fields = data.split(":");
                                          if (fields.length < 4) return;
                                          let type = fields[1];
                                          let state = fields[2];
                                          let conn = fields[3];
                                          if (type !== "ethernet" && type !== "wifi") return;
                                          if (state === "connected") {
                                              netWidget.netState = "connected";
                                              netWidget.netConn = conn;
                                              netWidget.netType = type;
                                              netWidget.netIcon = type === "wifi" ? "\u{f05a9}" : "\u{f0200}";
                                          } else if (netWidget.netState !== "connected") {
                                              netWidget.netState = "disconnected";
                                              netWidget.netConn = "";
                                              netWidget.netType = type;
                                              netWidget.netIcon = type === "wifi" ? "\u{f05aa}" : "\u{f0201}";
                                          }
                                      }
                                  }
                              }

                              Text {
                                  anchors.centerIn: parent
                                  text: netWidget.netIcon
                                  color: "#${c.base05}"
                                  font.family: "FiraMono Nerd Font"
                                  font.pixelSize: 14
                              }

                              Process {
                                  id: nmEditorProc
                                  command: ["${pkgs.networkmanagerapplet}/bin/nm-connection-editor"]
                              }

                              MouseArea {
                                  anchors.fill: parent
                                  onClicked: nmEditorProc.running = true
                              }
                          }

                          ${lib.optionalString isMacbook ''
                          // Battery
                          Item {
                              id: batteryWidget
                              width: batteryText.width + 4 + batteryIconText.width
                              height: 30

                              property int batteryLevel: 0
                              property bool charging: false
                              property string batteryIcon: "\u{f008e}"

                              function updateIcon() {
                                  if (charging) { batteryIcon = "\u{f0084}"; return; }
                                  if (batteryLevel >= 90) batteryIcon = "\u{f0079}";
                                  else if (batteryLevel >= 70) batteryIcon = "\u{f0082}";
                                  else if (batteryLevel >= 50) batteryIcon = "\u{f007f}";
                                  else if (batteryLevel >= 30) batteryIcon = "\u{f007c}";
                                  else if (batteryLevel >= 15) batteryIcon = "\u{f007a}";
                                  else batteryIcon = "\u{f008e}";
                              }

                              Timer {
                                  interval: 10000
                                  running: true
                                  repeat: true
                                  triggeredOnStart: true
                                  onTriggered: batteryProc.running = true
                              }

                              Process {
                                  id: batteryProc
                                  command: ["sh", "-c", "cat /sys/class/power_supply/BAT0/capacity; cat /sys/class/power_supply/BAT0/status"]
                                  stdout: SplitParser {
                                      onRead: data => {
                                          let trimmed = data.trim();
                                          let num = parseInt(trimmed);
                                          if (!isNaN(num) && num >= 0 && num <= 100) {
                                              batteryWidget.batteryLevel = num;
                                          } else if (trimmed.length > 0) {
                                              batteryWidget.charging = (trimmed === "Charging");
                                          }
                                          batteryWidget.updateIcon();
                                      }
                                  }
                              }

                              Row {
                                  anchors.verticalCenter: parent.verticalCenter
                                  spacing: 4

                                  Text {
                                      id: batteryText
                                      text: batteryWidget.batteryLevel + "%"
                                      color: batteryWidget.batteryLevel <= 15 ? "#${c.base08}"
                                           : batteryWidget.batteryLevel <= 30 ? "#${c.base0A}"
                                           : "#${c.base05}"
                                      font.family: "FiraMono Nerd Font"
                                      font.pixelSize: 13
                                  }

                                  Text {
                                      id: batteryIconText
                                      text: batteryWidget.batteryIcon
                                      color: batteryWidget.batteryLevel <= 15 ? "#${c.base08}"
                                           : batteryWidget.batteryLevel <= 30 ? "#${c.base0A}"
                                           : "#${c.base05}"
                                      font.family: "FiraMono Nerd Font"
                                      font.pixelSize: 14
                                  }
                              }
                          }
                          ''}

                          // Tray icons
                          Row {
                              id: trayArea
                              spacing: 8
                              anchors.verticalCenter: parent.verticalCenter

                              Repeater {
                                  model: SystemTray.items

                                  Item {
                                      required property var modelData
                                      width: 16
                                      height: 16

                                      Image {
                                          id: trayIcon
                                          anchors.fill: parent
                                          source: modelData.icon
                                          sourceSize.width: 16
                                          sourceSize.height: 16
                                          smooth: true
                                          mipmap: true
                                          visible: false
                                      }

                                      ColorOverlay {
                                          anchors.fill: trayIcon
                                          source: trayIcon
                                          color: "#${c.base05}"
                                      }

                                      MouseArea {
                                          anchors.fill: parent
                                          acceptedButtons: Qt.LeftButton | Qt.RightButton
                                          onClicked: (event) => {
                                              if (event.button === Qt.RightButton && modelData.hasMenu) {
                                                  contextMenu.trayItem = modelData;
                                                  menuOpener.menu = modelData.menu;
                                                  contextMenu.visible = true;
                                              } else {
                                                  modelData.activate();
                                              }
                                          }
                                      }
                                  }
                              }
                          }
                      }

                      // Custom-rendered context menu
                      PopupWindow {
                          id: contextMenu
                          property var trayItem: null
                          anchor.item: trayArea
                          anchor.edges: Edges.Bottom | Edges.Right
                          anchor.gravity: Edges.Bottom | Edges.Left
                          anchor.adjustment: PopupAdjustment.Slide
                          grabFocus: true
                          visible: false
                          color: "transparent"
                          implicitWidth: menuColumn.width + 2
                          implicitHeight: menuColumn.height + 2

                          QsMenuOpener {
                              id: menuOpener
                          }

                          Rectangle {
                              id: menuColumn
                              width: menuItems.width + 16
                              height: menuItems.height + 12
                              color: "#${c.base00}"
                              border.color: "#${c.base03}"
                              border.width: 1
                              radius: 8

                              Column {
                                  id: menuItems
                                  anchors.centerIn: parent
                                  width: 200

                                  Repeater {
                                      model: menuOpener.children

                                      Rectangle {
                                          required property var modelData
                                          width: 200
                                          height: modelData.isSeparator ? 9 : 28
                                          color: !modelData.isSeparator && itemMouse.containsMouse && modelData.enabled
                                                 ? "#${c.base02}" : "transparent"
                                          radius: modelData.isSeparator ? 0 : 4

                                          // Separator line
                                          Rectangle {
                                              visible: modelData.isSeparator
                                              anchors.centerIn: parent
                                              width: parent.width - 20
                                              height: 1
                                              color: "#${c.base03}"
                                          }

                                          // Menu item content
                                          RowLayout {
                                              visible: !modelData.isSeparator
                                              anchors.fill: parent
                                              anchors.leftMargin: 10
                                              anchors.rightMargin: 10
                                              spacing: 8

                                              Text {
                                                  Layout.fillWidth: true
                                                  text: modelData.text ?? ""
                                                  color: modelData.enabled ? "#${c.base05}" : "#${c.base03}"
                                                  font.family: "FiraMono Nerd Font"
                                                  font.pixelSize: 12
                                                  elide: Text.ElideRight
                                              }

                                              Text {
                                                  visible: modelData.buttonType !== QsMenuButtonType.None
                                                  text: modelData.checkState === Qt.Checked ? "\u2713" : ""
                                                  color: "#${c.base0D}"
                                                  font.family: "FiraMono Nerd Font"
                                                  font.pixelSize: 12
                                              }
                                          }

                                          MouseArea {
                                              id: itemMouse
                                              anchors.fill: parent
                                              hoverEnabled: true
                                              enabled: !modelData.isSeparator && modelData.enabled
                                              onClicked: {
                                                  modelData.triggered();
                                                  contextMenu.visible = false;
                                              }
                                          }
                                      }
                                  }
                              }
                          }

                          onVisibleChanged: {
                              if (!visible) {
                                  menuOpener.menu = null;
                              }
                          }
                      }

                      // Calendar popup
                      PopupWindow {
                          id: calPopup
                          anchor.window: bar
                          anchor.rect.x: bar.width / 2 - (fullWidth + 4) / 2
                          anchor.rect.y: bar.height
                          anchor.edges: Edges.Top | Edges.Left
                          anchor.gravity: Edges.Bottom | Edges.Right
                          anchor.adjustment: PopupAdjustment.Slide
                          grabFocus: true
                          visible: false
                          color: "transparent"

                          property bool open: false
                          property real fullWidth: calCol.width + 32
                          property real fullHeight: calCol.height + 24

                          implicitWidth: fullWidth + 4
                          implicitHeight: fullHeight + 4

                          onVisibleChanged: {
                              if (visible) {
                                  open = true;
                              } else {
                                  open = false;
                              }
                          }

                          // Concave corner — left
                          Rectangle {
                              id: cornerLeft
                              anchors.right: calContent.left
                              anchors.top: parent.top
                              width: 8
                              height: 8
                              color: "#D1${c.base00}"
                              visible: calPopup.open
                              opacity: calPopup.open ? 1.0 : 0.0
                              Behavior on opacity { NumberAnimation { duration: 150 } }

                              Rectangle {
                                  anchors.fill: parent
                                  color: "transparent"
                                  radius: 8
                                  Rectangle {
                                      anchors.fill: parent
                                      color: "transparent"
                                  }
                              }

                              Canvas {
                                  anchors.fill: parent
                                  onPaint: {
                                      var ctx = getContext("2d");
                                      ctx.clearRect(0, 0, width, height);
                                      ctx.fillStyle = "#D1${c.base00}";
                                      ctx.fillRect(0, 0, width, height);
                                      ctx.globalCompositeOperation = "destination-out";
                                      ctx.beginPath();
                                      ctx.arc(0, 0, width, 0, Math.PI / 2);
                                      ctx.fill();
                                  }
                              }
                          }

                          // Concave corner — right
                          Rectangle {
                              id: cornerRight
                              anchors.left: calContent.right
                              anchors.top: parent.top
                              width: 8
                              height: 8
                              color: "#D1${c.base00}"
                              visible: calPopup.open
                              opacity: calPopup.open ? 1.0 : 0.0
                              Behavior on opacity { NumberAnimation { duration: 150 } }

                              Canvas {
                                  anchors.fill: parent
                                  onPaint: {
                                      var ctx = getContext("2d");
                                      ctx.clearRect(0, 0, width, height);
                                      ctx.fillStyle = "#D1${c.base00}";
                                      ctx.fillRect(0, 0, width, height);
                                      ctx.globalCompositeOperation = "destination-out";
                                      ctx.beginPath();
                                      ctx.arc(width, 0, width, Math.PI / 2, Math.PI);
                                      ctx.fill();
                                  }
                              }
                          }

                          Rectangle {
                              id: calContent
                              anchors.horizontalCenter: parent.horizontalCenter
                              anchors.top: parent.top
                              anchors.topMargin: 0
                              width: calPopup.open ? calPopup.fullWidth : calPopup.fullWidth
                              height: calPopup.open ? calPopup.fullHeight : 0
                              color: "#D1${c.base00}"
                              border.width: 0
                              radius: 8
                              topLeftRadius: 0
                              topRightRadius: 0
                              clip: true

                              Behavior on height {
                                  NumberAnimation { duration: 220; easing.type: Easing.OutCubic }
                              }

                              Column {
                                  id: calCol
                                  anchors.horizontalCenter: parent.horizontalCenter
                                  anchors.top: parent.top
                                  anchors.topMargin: 12
                                  spacing: 8
                                  opacity: calPopup.open ? 1.0 : 0.0

                                  Behavior on opacity {
                                      NumberAnimation { duration: 150; easing.type: Easing.OutCubic }
                                  }

                                  // Date header
                                  Text {
                                      anchors.horizontalCenter: parent.horizontalCenter
                                      text: clockText.now.toLocaleDateString(Qt.locale(), "dddd, d MMMM yyyy")
                                      color: "#${c.base05}"
                                      font.family: "FiraMono Nerd Font"
                                      font.pixelSize: 14
                                      font.weight: Font.Medium
                                  }

                                  // Day headers
                                  Row {
                                      spacing: 0
                                      Repeater {
                                          model: ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"]
                                          Text {
                                              required property var modelData
                                              width: 28
                                              horizontalAlignment: Text.AlignHCenter
                                              text: modelData
                                              color: "#${c.base03}"
                                              font.family: "FiraMono Nerd Font"
                                              font.pixelSize: 11
                                          }
                                      }
                                  }

                                  // Calendar grid
                                  Grid {
                                      columns: 7
                                      spacing: 0

                                      Repeater {
                                          id: calRepeater
                                          model: 42

                                          Rectangle {
                                              required property int index
                                              width: 28
                                              height: 24
                                              radius: 4
                                              color: {
                                                  let d = clockText.now;
                                                  let first = new Date(d.getFullYear(), d.getMonth(), 1);
                                                  let startDay = (first.getDay() + 6) % 7;
                                                  let dayNum = index - startDay + 1;
                                                  let daysInMonth = new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
                                                  return (dayNum === d.getDate() && dayNum >= 1 && dayNum <= daysInMonth)
                                                      ? "#${c.base02}" : "transparent";
                                              }

                                              Text {
                                                  anchors.centerIn: parent
                                                  text: {
                                                      let d = clockText.now;
                                                      let first = new Date(d.getFullYear(), d.getMonth(), 1);
                                                      let startDay = (first.getDay() + 6) % 7;
                                                      let dayNum = parent.index - startDay + 1;
                                                      let daysInMonth = new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
                                                      return (dayNum >= 1 && dayNum <= daysInMonth) ? dayNum.toString() : "";
                                                  }
                                                  color: {
                                                      let d = clockText.now;
                                                      let first = new Date(d.getFullYear(), d.getMonth(), 1);
                                                      let startDay = (first.getDay() + 6) % 7;
                                                      let dayNum = parent.index - startDay + 1;
                                                      return (dayNum === d.getDate()) ? "#${c.base05}" : "#${c.base04}";
                                                  }
                                                  font.family: "FiraMono Nerd Font"
                                                  font.pixelSize: 11
                                              }
                                          }
                                      }
                                  }
                              }
                          }
                      }
                  }
              }
          }
        '';
      };

    };
  };
}
