From 7760d761c7edc4c2340985364584f6c49139c731 Mon Sep 17 00:00:00 2001
From: Myned <dev@bjork.tech>
Date: Sun, 16 Feb 2025 20:29:08 -0600
Subject: [PATCH] firefox: genericize module and switch to librewolf

Signed-off-by: Myned <dev@bjork.tech>
---
 modules/firefox.nix                           | 578 ++++++++++++++++
 options/custom/default.nix                    |  17 +-
 options/custom/desktops/hyprland/rules.nix    |   1 +
 options/custom/programs/default.nix           |   4 +-
 options/custom/programs/firefox.nix           | 617 ------------------
 options/custom/programs/firefox/firefox.nix   |  35 +
 options/custom/programs/firefox/librewolf.nix |  36 +
 options/custom/programs/librewolf.nix         |  17 -
 8 files changed, 656 insertions(+), 649 deletions(-)
 create mode 100644 modules/firefox.nix
 delete mode 100644 options/custom/programs/firefox.nix
 create mode 100644 options/custom/programs/firefox/firefox.nix
 create mode 100644 options/custom/programs/firefox/librewolf.nix
 delete mode 100644 options/custom/programs/librewolf.nix

diff --git a/modules/firefox.nix b/modules/firefox.nix
new file mode 100644
index 0000000..26d4a23
--- /dev/null
+++ b/modules/firefox.nix
@@ -0,0 +1,578 @@
+{
+  config,
+  inputs,
+  lib,
+  pkgs,
+  theme ? true,
+  ...
+}:
+with lib; {
+  #!! Creates package derivation
+  #?? hm.programs.firefox.finalPackage
+  enableGnomeExtensions = config.services.gnome.gnome-browser-connector.enable;
+
+  # https://wiki.nixos.org/wiki/Firefox#Tips
+  nativeMessagingHosts = with pkgs; [
+    firefoxpwa
+  ];
+
+  #!! Prefer policies over profiles when possible
+  #?? about:profiles
+  profiles.default = {
+    # https://nur.nix-community.org/repos/rycee/
+    extensions = with pkgs.nur.repos.rycee.firefox-addons;
+      optionals config.custom.minimal [
+        ublock-origin
+      ]
+      ++ optionals config.custom.full [
+        awesome-rss
+        #// betterttv
+        bitwarden
+        enhancer-for-youtube
+        #// firefox-color
+        #// gnome-shell-integration
+        #// improved-tube
+        libredirect
+        #// onepassword-password-manager
+        pwas-for-firefox
+        #// simple-tab-groups
+        sponsorblock
+        stylus
+        #// untrap-for-youtube
+        #// user-agent-string-switcher
+
+        # TODO: Convert to NUR addons
+        #// "{248e6a49-f636-4c81-9899-a456eb6291a8}" = extension "ground-news-bias-checker"; # Ground News Bias Checker
+        #// "select-after-closing-current@qw.linux-2g64.local" = extension "select-after-closing-current"; # Select After Closing Current
+        #// "myallychou@gmail.com" = extension "youtube-recommended-videos"; # Unhook: Remove YouTube Recommended Videos Comments
+        #// "{a0370179-acc3-452f-9530-246b6adb2768}" = extension "svelte-devtools"; # Svelte Devtools
+        #// "{c49b13b1-5dee-4345-925e-0c793377e3fa}" = extension "youtube-enhancer-vc"; # YouTube Enhancer
+      ];
+
+    # TODO: Consider other themes
+    # https://github.com/soulhotel/FF-ULTIMA
+
+    # Import CSS theme with solarized overrides
+    # https://github.com/rafaelmardojai/firefox-gnome-theme
+    # https://github.com/rafaelmardojai/firefox-gnome-theme/blob/master/theme/colors/dark.css
+    userContent = mkIf theme ''
+      @import "${inputs.firefox-gnome-theme}/userContent.css";
+    '';
+
+    userChrome = mkIf theme ''
+      @import "${inputs.firefox-gnome-theme}/userChrome.css";
+
+      :root {
+        --gnome-accent: #d33682;
+        --gnome-window-background: #002b36;
+        --gnome-window-color: #93a1a1;
+        --gnome-view-background: #073642;
+        --gnome-sidebar-background: #002b36;
+        --gnome-secondary-sidebar-background: #002b36;
+        --gnome-menu-background: #073642;
+        --gnome-headerbar-background: #002b36;
+        --gnome-toolbar-icon-fill: #93a1a1;
+        --gnome-tabbar-tab-hover-background: #073642;
+        --gnome-tabbar-tab-active-background: #073642;
+        --gnome-tabbar-tab-active-hover-background: #073642;
+      }
+
+      :root:-moz-window-inactive {
+        --gnome-inactive-entry-color: #586e75;
+        --gnome-tabbar-tab-hover-background: #073642;
+        --gnome-tabbar-tab-active-background: #073642;
+      }
+
+      /* Center bookmarks */
+      #PlacesToolbarItems {
+        justify-content: center;
+      }
+
+      /* Disable bookmark folder icons */
+      .bookmark-item[container] > .toolbarbutton-icon {
+        display: none;
+      }
+    '';
+
+    containersForce = true;
+
+    containers = {
+      Master = {
+        color = "pink";
+        icon = "circle";
+        id = 0;
+      };
+
+      Edu = {
+        color = "orange";
+        icon = "fruit";
+        id = 1;
+      };
+    };
+
+    settings = with config.custom.settings.fonts;
+      {
+        "accessibility.browsewithcaret" = false;
+        "accessibility.typeaheadfind" = false;
+        "browser.aboutConfig.showWarning" = false;
+        "browser.bookmarks.restore_default_bookmarks" = false;
+        "browser.contentblocking.category" = "standard";
+        "browser.contentblocking.report.hide_vpn_banner" = true;
+        "browser.contentblocking.report.show_mobile_app" = false;
+        "browser.contentblocking.report.vpn.enabled" = false;
+        "browser.crashReports.unsubmittedCheck.autoSubmit2" = false;
+        "browser.ctrlTab.sortByRecentlyUsed" = false;
+        "browser.dataFeatureRecommendations.enabled" = false;
+        "browser.download.always_ask_before_handling_new_types" = false;
+        "browser.download.useDownloadDir" = true;
+        "browser.engagement.ctrlTab.has-used" = true;
+        "browser.engagement.downloads-button.has-used" = true;
+        "browser.engagement.fxa-toolbar-menu-button.has-used" = true;
+        "browser.engagement.home-button.has-used" = true;
+        "browser.engagement.library-button.has-used" = true;
+        "browser.engagement.sidebar-button.has-used" = true;
+        "browser.formfill.enable" = false;
+        "browser.link.open_newwindow.restriction" = 0; # Popups in new tab
+        "browser.link.open_newwindow" = 3; # New tab
+        "browser.messaging-system.whatsNewPanel.enabled" = false;
+        "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons" = false;
+        "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features" = false;
+        "browser.newtabpage.activity-stream.discoverystream.onboardingExperience.enabled" = false;
+        "browser.newtabpage.activity-stream.discoverystream.topicSelection.onboarding.enabled" = false;
+        "browser.newtabpage.activity-stream.feeds.recommendationprovider" = false;
+        "browser.newtabpage.activity-stream.feeds.section.highlights" = false;
+        "browser.newtabpage.activity-stream.feeds.section.topstories" = false;
+        "browser.newtabpage.activity-stream.feeds.system.topstories" = false;
+        "browser.newtabpage.activity-stream.feeds.telemetry" = false;
+        "browser.newtabpage.activity-stream.feeds.topsites" = false;
+        "browser.newtabpage.activity-stream.showSearch" = false;
+        "browser.newtabpage.activity-stream.showSponsored" = false;
+        "browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
+        "browser.newtabpage.activity-stream.showWeather" = false;
+        "browser.newtabpage.activity-stream.telemetry" = false;
+        "browser.newtabpage.enabled" = true;
+        "browser.ping-centre.telemetry" = false;
+        "browser.preferences.defaultPerformanceSettings.enabled" = true;
+        "browser.preferences.moreFromMozilla" = false;
+        "browser.quitShortcut.disabled" = true;
+        "browser.safebrowsing.blockedURIs.enabled" = true;
+        "browser.safebrowsing.downloads.enabled" = true;
+        "browser.safebrowsing.malware.enabled" = true;
+        "browser.safebrowsing.phishing.enabled" = true;
+        "browser.search.separatePrivateDefault" = false;
+        "browser.search.suggest.enabled" = true;
+        "browser.search.widget.inNavBar" = false;
+        "browser.shell.checkDefaultBrowser" = false;
+        "browser.startup.homepage" = "about:home";
+        "browser.startup.page" = 3; # Previous session
+        "browser.tabs.allowTabDetach" = false;
+        "browser.tabs.closeTabByDblclick" = true;
+        "browser.tabs.closeWindowWithLastTab" = false;
+        "browser.tabs.groups.enabled" = true;
+        "browser.tabs.insertAfterCurrent" = false;
+        "browser.tabs.insertRelatedAfterCurrent" = false;
+        "browser.tabs.loadInBackground" = true;
+        "browser.tabs.warnOnClose" = false;
+        "browser.tabs.warnOnCloseOtherTabs" = false;
+        "browser.theme.dark-private-windows" = false;
+        "browser.toolbars.bookmarks.showOtherBookmarks" = false;
+        "browser.uidensity" = 0; # Default
+        "browser.urlbar.quicksuggest.dataCollection.enabled" = false;
+        "browser.urlbar.quicksuggest.shouldShowOnboardingDialog" = false;
+        "browser.urlbar.suggest.addons" = true;
+        "browser.urlbar.suggest.bookmark" = true;
+        "browser.urlbar.suggest.calculator" = true;
+        "browser.urlbar.suggest.clipboard" = true;
+        "browser.urlbar.suggest.engines" = true;
+        "browser.urlbar.suggest.fakespot" = true;
+        "browser.urlbar.suggest.history" = true;
+        "browser.urlbar.suggest.mdn" = true;
+        "browser.urlbar.suggest.openpage" = true;
+        "browser.urlbar.suggest.pocket" = false;
+        "browser.urlbar.suggest.quickactions" = true;
+        "browser.urlbar.suggest.quicksuggest.nonsponsored" = true;
+        "browser.urlbar.suggest.quicksuggest.sponsored" = false;
+        "browser.urlbar.suggest.recentsearches" = true;
+        "browser.urlbar.suggest.remotetab" = true;
+        "browser.urlbar.suggest.searches" = true;
+        "browser.urlbar.suggest.topsites" = true;
+        "browser.urlbar.suggest.trending" = false;
+        "browser.urlbar.suggest.weather" = false;
+        "browser.urlbar.suggest.yelp" = false;
+        "browser.warnOnQuitShortcut" = true;
+        "clipboard.autocopy" = false;
+        "default-browser-agent.enabled" = false;
+        "devtools.webconsole.input.editorOnboarding" = false;
+        "dom.security.https_only_mode" = true;
+        "extensions.autoDisableScopes" = 0; # Auto-enable extensions
+        "extensions.formautofill.addresses.enabled" = false;
+        "extensions.formautofill.creditCards.enabled" = false;
+        "extensions.htmlaboutaddons.recommendations.enabled" = false;
+        "extensions.pictureinpicture.enable_picture_in_picture_overrides" = true;
+        "extensions.pocket.enabled" = false;
+        "extensions.update.autoUpdateDefault" = true;
+        "extensions.update.enabled" = true;
+        "font.default.x-unicode" = sans-serif;
+        "font.default.x-western" = sans-serif;
+        "font.name-list.emoji" = emoji; # System emoji
+        "font.name.monospace.x-unicode" = monospace;
+        "font.name.monospace.x-western" = monospace;
+        "font.name.sans-serif.x-unicode" = sans-serif;
+        "font.name.sans-serif.x-western" = sans-serif;
+        "font.name.serif.x-unicode" = sans-serif;
+        "font.name.serif.x-western" = sans-serif;
+        "full-screen-api.ignore-widgets" = false; # Fake fullscreen
+        "full-screen-api.warning.delay" = -1;
+        "full-screen-api.warning.timeout" = 0;
+        "general.autoScroll" = false;
+        "general.smoothScroll" = true;
+        "gfx.webrender.software" = config.custom.programs.looking-glass.igpu; # Reduce load on iGPU
+        "identity.fxaccounts.enabled" = true;
+        "layers.acceleration.force-enabled" = true;
+        "layout.css.always_underline_links" = false;
+        "layout.css.backdrop-filter.enabled" = true;
+        "layout.forms.reveal-password-button.enabled" = true;
+        "layout.forms.reveal-password-context-menu.enabled" = false;
+        "layout.spellcheckDefault" = 0; # Disabled
+        "media.autoplay.blocking_policy" = 1; # Transient
+        "media.eme.enabled" = true; # DRM
+        "media.ffmpeg.vaapi.enabled" = true;
+        "media.hardware-video-decoding.enabled" = true;
+        "media.hardwaremediakeys.enabled" = true;
+        "media.videocontrols.picture-in-picture.audio-toggle.enabled" = false;
+        "media.videocontrols.picture-in-picture.display-text-tracks.enabled" = true;
+        "media.videocontrols.picture-in-picture.display-text-tracks.toggle.enabled" = true;
+        "media.videocontrols.picture-in-picture.enable-when-switching-tabs.enabled" = true;
+        "media.videocontrols.picture-in-picture.enabled" = true;
+        "media.videocontrols.picture-in-picture.respect-disablePictureInPicture" = false;
+        "media.videocontrols.picture-in-picture.urlbar-button.enabled" = true;
+        "media.videocontrols.picture-in-picture.video-toggle.enabled" = true;
+        "media.videocontrols.picture-in-picture.video-toggle.has-used" = true;
+        "media.videocontrols.picture-in-picture.video-toggle.min-video-secs" = 0; # No minimum duration
+        "media.videocontrols.picture-in-picture.video-toggle.position" = "top";
+        "messaging-system.askForFeedback" = false;
+        "messaging-system.rsexperimentloader.enabled" = false;
+        "middlemouse.paste" = false;
+        "network.dns.disableIPv6" = false;
+        "network.dns.disablePrefetch" = true;
+        "network.dns.disablePrefetchFromHTTPS" = true;
+        "network.http.referer.XOriginPolicy" = 0; # Relaxed
+        "network.predictor.enabled" = false;
+        "pref.privacy.disable_button.view_passwords" = true;
+        "privacy.fingerprintingProtection" = false;
+        "privacy.globalprivacycontrol.enabled" = true;
+        "privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts" = false;
+        "privacy.resistFingerprinting.letterboxing" = false;
+        "privacy.resistFingerprinting" = false; #!! Forces light theme
+        "remote.prefs.recommended" = false;
+        "security.OCSP.require" = true;
+        "security.protectionspopup.recordEventTelemetry" = false;
+        "services.passwordSavingEnabled" = false;
+        "startup.homepage_override_url" = ""; # Disable
+        "startup.homepage_welcome_url" = ""; # Disable
+        "svg.context-properties.content.enabled" = true; # Dark theme icons
+        "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
+        "toolkit.telemetry.archive.enabled" = false;
+        "toolkit.telemetry.bhrPing.enabled" = false;
+        "toolkit.telemetry.coverage.opt-out" = true;
+        "toolkit.telemetry.enabled" = false;
+        "toolkit.telemetry.firstShutdownPing.enabled" = false;
+        "toolkit.telemetry.newProfilePing.enabled" = false;
+        "toolkit.telemetry.pioneer-new-studies-available" = false;
+        "toolkit.telemetry.shutdownPingSender.enabled" = false;
+        "toolkit.telemetry.unified" = false;
+        "toolkit.telemetry.updatePing.enabled" = false;
+        "ui.key.menuAccessKey" = 0; # Disable menu key
+        "webgl.disabled" = false;
+        "widget.gtk.overlay-scrollbars.enabled" = true;
+        "widget.gtk.rounded-bottom-corners.enabled" = true;
+      }
+      // optionalAttrs theme {
+        # https://github.com/rafaelmardojai/firefox-gnome-theme?tab=readme-ov-file#features
+        "gnomeTheme.allTabsButtonOnOverflow" = true;
+        "gnomeTheme.bookmarksToolbarUnderTabs" = true;
+      };
+
+    bookmarks = [
+      {
+        name = "Nix User Repository";
+        keyword = "nur";
+        url = "https://nur.nix-community.org/";
+      }
+
+      {
+        name = "Nix Ryantm";
+        keyword = "nry";
+        url = "https://ryantm.github.io/nixpkgs/";
+      }
+    ];
+
+    # https://searchfox.org/mozilla-central/rev/669329e284f8e8e2bb28090617192ca9b4ef3380/toolkit/components/search/SearchEngine.jsm#1138-1177
+    search = {
+      force = true;
+      default = "Kagi";
+      privateDefault = "Kagi";
+
+      engines = {
+        ### Builtins
+        "Amazon.com" = {
+          metaData.hidden = true;
+        };
+
+        "Bing" = {
+          metaData.hidden = true;
+        };
+
+        "DuckDuckGo" = {
+          metaData.alias = "d";
+        };
+
+        "eBay" = {
+          metaData.hidden = true;
+        };
+
+        "Google" = {
+          metaData.alias = "g";
+        };
+
+        "Wikipedia (en)" = {
+          metaData.hidden = true;
+        };
+
+        ### Custom
+        "Amazon" = {
+          definedAliases = ["a"];
+          iconUpdateURL = "https://www.amazon.com/favicon.ico";
+          urls = [{template = "https://www.amazon.com/s?k={searchTerms}";}];
+        };
+
+        "ArchWiki" = {
+          definedAliases = ["aw"];
+          iconUpdateURL = "https://wiki.archlinux.org/favicon.ico";
+          urls = [{template = "https://wiki.archlinux.org/index.php?search={searchTerms}";}];
+        };
+
+        "Brave" = {
+          definedAliases = ["b"];
+          iconUpdateURL = "https://cdn.search.brave.com/serp/v2/_app/immutable/assets/favicon.c09fe1a1.ico";
+          urls = [{template = "https://search.brave.com/search?q={searchTerms}";}];
+        };
+
+        "Docker Hub" = {
+          definedAliases = ["dh"];
+          iconUpdateURL = "https://hub.docker.com/favicon.ico";
+          urls = [{template = "https://hub.docker.com/search?q={searchTerms}";}];
+        };
+
+        "e621" = {
+          definedAliases = ["e"];
+          iconUpdateURL = "https://e621.net/favicon.ico";
+          urls = [{template = "https://e621.net/posts?tags={searchTerms}";}];
+        };
+
+        "Element Issues" = {
+          definedAliases = ["ei"];
+          iconUpdateURL = "https://github.com/favicon.ico";
+          urls = [{template = "https://github.com/element-hq/element-web/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
+        };
+
+        "Flathub" = {
+          definedAliases = ["fh"];
+          iconUpdateURL = "https://flathub.org/favicon.png";
+          urls = [{template = "https://flathub.org/apps/search?q={searchTerms}";}];
+        };
+
+        "Google Fonts" = {
+          definedAliases = ["gf"];
+          iconUpdateURL = "https://www.gstatic.com/images/icons/material/apps/fonts/1x/catalog/v5/favicon.svg";
+          urls = [{template = "https://fonts.google.com/?query={searchTerms}";}];
+        };
+
+        "GitHub" = {
+          definedAliases = ["gh"];
+          iconUpdateURL = "https://github.com/favicon.ico";
+          urls = [{template = "https://github.com/search?q={searchTerms}";}];
+        };
+
+        "Home Manager Issues" = {
+          definedAliases = ["hi"];
+          iconUpdateURL = "https://github.com/favicon.ico";
+          urls = [{template = "https://github.com/nix-community/home-manager/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
+        };
+
+        "Home Manager Options" = {
+          definedAliases = ["ho"];
+          iconUpdateURL = "https://home-manager-options.extranix.com/images/favicon.png";
+          urls = [{template = "https://home-manager-options.extranix.com/?query={searchTerms}&release=master";}];
+        };
+
+        "Hyprland Issues" = {
+          definedAliases = ["hyi"];
+          iconUpdateURL = "https://github.com/favicon.ico";
+          urls = [{template = "https://github.com/hyprwm/Hyprland/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
+        };
+
+        "i3 Issues" = {
+          definedAliases = ["ii"];
+          iconUpdateURL = "https://github.com/favicon.ico";
+          urls = [{template = "https://github.com/i3/i3/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
+        };
+
+        "Kagi" = {
+          definedAliases = ["k"];
+          iconUpdateURL = "https://kagi.com/asset/v2/favicon-32x32.png";
+          urls = [{template = "https://kagi.com/search?q={searchTerms}";}];
+        };
+
+        "Lutris" = {
+          definedAliases = ["l"];
+          iconUpdateURL = "https://lutris.net/favicon.ico";
+          urls = [{template = "https://lutris.net/games?q={searchTerms}";}];
+        };
+
+        "Lix Issues" = {
+          definedAliases = ["li"];
+          iconUpdateURL = "https://git.lix.systems/assets/img/favicon.png";
+          urls = [{template = "https://git.lix.systems/lix-project/lix/issues?state=open&q={searchTerms}";}];
+        };
+
+        "Mozilla Web Docs" = {
+          definedAliases = ["mdn"];
+          iconUpdateURL = "https://developer.mozilla.org/favicon-48x48.cbbd161b.png";
+          urls = [{template = "https://developer.mozilla.org/en-US/search?q={searchTerms}";}];
+        };
+
+        "MyNixOS Options" = {
+          definedAliases = ["mno"];
+          iconUpdateURL = "https://mynixos.com/favicon.ico";
+          urls = [{template = "https://mynixos.com/search?q=option+{searchTerms}";}];
+        };
+
+        "Nix Dev" = {
+          definedAliases = ["nd"];
+          iconUpdateURL = "https://nix.dev/manual/nix/latest/favicon.png";
+          urls = [{template = "https://nix.dev/manual/nix/latest?search={searchTerms}";}];
+        };
+
+        "NixOS Flakes" = {
+          definedAliases = ["nf"];
+          iconUpdateURL = "https://nixos.org/favicon.png";
+          urls = [{template = "https://search.nixos.org/flakes?channel=unstable&query={searchTerms}";}];
+        };
+
+        "Nix Hub" = {
+          definedAliases = ["nh"];
+          iconUpdateURL = "https://www.nixhub.io/favicon.ico";
+          urls = [{template = "https://www.nixhub.io/search?q={searchTerms}";}];
+        };
+
+        "NixOS Nixpkgs Issues" = {
+          definedAliases = ["ni"];
+          iconUpdateURL = "https://github.com/favicon.ico";
+          urls = [{template = "https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
+        };
+
+        "Nix PR" = {
+          definedAliases = ["npr"];
+          urls = [{template = "https://nixpk.gs/pr-tracker.html?pr={searchTerms}";}];
+        };
+
+        "NixOS Options" = {
+          definedAliases = ["no"];
+          iconUpdateURL = "https://nixos.org/favicon.png";
+          urls = [{template = "https://search.nixos.org/options?channel=unstable&query={searchTerms}";}];
+        };
+
+        "Noogle Dev" = {
+          definedAliases = ["nod"];
+          iconUpdateURL = "https://noogle.dev/favicon.png";
+          urls = [{template = "https://noogle.dev/q?term={searchTerms}";}];
+        };
+
+        "NixOS Packages" = {
+          definedAliases = ["np"];
+          iconUpdateURL = "https://nixos.org/favicon.png";
+          urls = [{template = "https://search.nixos.org/packages?channel=unstable&query={searchTerms}";}];
+        };
+
+        "Niri Issues" = {
+          definedAliases = ["nri"];
+          iconUpdateURL = "https://github.com/favicon.ico";
+          urls = [{template = "https://github.com/YaLTeR/niri/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
+        };
+
+        "NixOS Wiki" = {
+          definedAliases = ["nw"];
+          iconUpdateURL = "https://wiki.nixos.org/favicon.ico";
+          urls = [{template = "https://wiki.nixos.org/w/index.php?search={searchTerms}";}];
+        };
+
+        "Piped" = {
+          definedAliases = ["p"];
+          iconUpdateURL = "https://piped.${config.custom.domain}/favicon.ico";
+          urls = [{template = "https://piped.${config.custom.domain}/results?search_query={searchTerms}";}];
+        };
+
+        "PCGamingWiki" = {
+          definedAliases = ["pc"];
+          iconUpdateURL = "https://static.pcgamingwiki.com/favicons/pcgamingwiki.png";
+          urls = [{template = "https://www.pcgamingwiki.com/w/index.php?search={searchTerms}";}];
+        };
+
+        "ProtonDB" = {
+          definedAliases = ["pdb"];
+          iconUpdateURL = "https://www.protondb.com/sites/protondb/images/favicon.ico";
+          urls = [{template = "https://www.protondb.com/search?q={searchTerms}";}];
+        };
+
+        "PyPI" = {
+          definedAliases = ["pip"];
+          iconUpdateURL = "https://pypi.org/static/images/favicon.35549fe8.ico";
+          urls = [{template = "https://pypi.org/search/?q={searchTerms}";}];
+        };
+
+        "Reddit" = {
+          definedAliases = ["r"];
+          iconUpdateURL = "https://www.redditstatic.com/desktop2x/img/favicon/favicon-96x96.png";
+          urls = [{template = "https://kagi.com/search?q=site%3Areddit.com+{searchTerms}";}];
+        };
+
+        "SearXNG" = {
+          definedAliases = ["s"];
+          iconUpdateURL = "https://search.${config.custom.domain}/static/themes/simple/img/favicon.png";
+          urls = [{template = "https://search.${config.custom.domain}/search?q={searchTerms}";}];
+        };
+
+        "Sway Issues" = {
+          definedAliases = ["si"];
+          iconUpdateURL = "https://github.com/favicon.ico";
+          urls = [{template = "https://github.com/swaywm/sway/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
+        };
+
+        "Wikipedia" = {
+          definedAliases = ["w"];
+          iconUpdateURL = "https://en.wikipedia.org/static/favicon/wikipedia.ico";
+          urls = [{template = "https://en.wikipedia.org/w/index.php?search={searchTerms}";}];
+        };
+
+        "Wolfram Alpha" = {
+          definedAliases = ["wa"];
+          iconUpdateURL = "https://www.wolframalpha.com/_next/static/images/favicon_1zbE9hjk.ico";
+          urls = [{template = "https://www.wolframalpha.com/input?i={searchTerms}";}];
+        };
+
+        "Walker Issues" = {
+          definedAliases = ["wi"];
+          iconUpdateURL = "https://github.com/favicon.ico";
+          urls = [{template = "https://github.com/abenz1267/walker/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
+        };
+
+        "YouTube" = {
+          definedAliases = ["y"];
+          iconUpdateURL = "https://www.youtube.com/s/desktop/f8c8418d/img/favicon.ico";
+          urls = [{template = "https://www.youtube.com/results?search_query={searchTerms}";}];
+        };
+      };
+    };
+  };
+}
diff --git a/options/custom/default.nix b/options/custom/default.nix
index 0d07c07..4c92d03 100644
--- a/options/custom/default.nix
+++ b/options/custom/default.nix
@@ -6,6 +6,7 @@
 }:
 with lib; let
   cfg = config.custom;
+  hm = config.home-manager.users.${config.custom.username};
 in {
   options.custom = {
     ### Profiles
@@ -30,7 +31,7 @@ in {
     hidpi = mkOption {default = cfg.scale > 1;};
     scale = mkOption {default = 1;};
     border = mkOption {default = 3;};
-    gap = mkOption {default = 10;};
+    gap = mkOption {default = 15;};
     padding = mkOption {default = 51;}; # ?? journalctl --user -u waybar.service | grep height:
     rounding = mkOption {default = 15;};
 
@@ -48,18 +49,8 @@ in {
 
     browser = {
       # TODO: Use lib.getExe' instead of /bin/ where possible
-      # HACK: Find first matching package in final home-manager list
-      command = mkOption {
-        default = "${lib.findFirst (pkg:
-            if (lib.hasAttr "pname" pkg)
-            then pkg.pname == "brave"
-            else false)
-          null
-          config.home-manager.users.${config.custom.username}.home.packages}/bin/brave";
-      };
-
-      desktop = mkOption {default = "brave.desktop";};
-      package = mkOption {default = pkgs.brave;};
+      command = mkOption {default = getExe hm.programs.librewolf.finalPackage;};
+      desktop = mkOption {default = "librewolf.desktop";};
     };
   };
 }
diff --git a/options/custom/desktops/hyprland/rules.nix b/options/custom/desktops/hyprland/rules.nix
index 49c75d1..a759937 100644
--- a/options/custom/desktops/hyprland/rules.nix
+++ b/options/custom/desktops/hyprland/rules.nix
@@ -209,6 +209,7 @@ in {
             (class "^chromium-browser$" rules)
             (class "^firefox.*$" rules)
             (class "^google-chrome$" rules)
+            (class "^librewolf$" rules)
             (class "^vivaldi.*$" rules)
             (class "^zen$" rules)
           ];
diff --git a/options/custom/programs/default.nix b/options/custom/programs/default.nix
index f19a525..2ceaf4c 100644
--- a/options/custom/programs/default.nix
+++ b/options/custom/programs/default.nix
@@ -33,12 +33,13 @@ with lib; {
       appimage.enable = true;
       chromium.enable = true;
       dconf.enable = true;
-      firefox.enable = true;
+      #// firefox.enable = true;
       #// foot.enable = true;
       gamescope.enable = true;
       #// gnome-terminal.enable = true;
       #// kdeconnect.enable = true;
       kitty.enable = true;
+      librewolf.enable = true;
       nautilus.enable = true;
       nvtop.enable = true;
       wezterm.enable = true;
@@ -60,7 +61,6 @@ with lib; {
       #// gtklock.enable = true;
       hyprlock.enable = true;
       libreoffice.enable = true;
-      #// librewolf.enable = true;
       localsend.enable = true;
       logseq.enable = true;
       mangohud.enable = true;
diff --git a/options/custom/programs/firefox.nix b/options/custom/programs/firefox.nix
deleted file mode 100644
index 5d2c991..0000000
--- a/options/custom/programs/firefox.nix
+++ /dev/null
@@ -1,617 +0,0 @@
-{
-  config,
-  inputs,
-  lib,
-  pkgs,
-  ...
-}:
-with lib; let
-  cfg = config.custom.programs.firefox;
-in {
-  options.custom.programs.firefox.enable = mkOption {default = false;};
-
-  config.home-manager.users.${config.custom.username} = mkIf cfg.enable {
-    # TODO: Switch to librewolf when supported by module
-    # https://github.com/nix-community/home-manager/pull/5128
-    #!! Creates package derivation
-    #?? config.home-manager.users.${config.custom.username}.programs.firefox.finalPackage
-    # https://www.mozilla.org/en-US/firefox/developer
-    programs.firefox = {
-      enable = true;
-      package = pkgs.firefox-esr-128;
-
-      # nativeMessagingHosts = with pkgs; [
-      #   firefoxpwa
-      #   gnome-browser-connector
-      # ];
-
-      #!! Prefer policy over profile
-      #?? about:profiles
-      profiles.default = {
-        # Import CSS theme with solarized overrides
-        # https://github.com/rafaelmardojai/firefox-gnome-theme/blob/master/theme/colors/dark.css
-        userChrome = ''
-          @import "firefox-gnome-theme/userChrome.css";
-
-          :root {
-            --gnome-accent: #6c71c4;
-            --gnome-window-background: #002b36;
-            --gnome-window-color: #93a1a1;
-            --gnome-view-background: #073642;
-            --gnome-sidebar-background: #002b36;
-            --gnome-secondary-sidebar-background: #002b36;
-            --gnome-menu-background: #073642;
-            --gnome-headerbar-background: #002b36;
-            --gnome-toolbar-icon-fill: #93a1a1;
-            --gnome-tabbar-tab-hover-background: #073642;
-            --gnome-tabbar-tab-active-background: #073642;
-            --gnome-tabbar-tab-active-hover-background: #073642;
-          }
-
-          :root:-moz-window-inactive {
-            --gnome-inactive-entry-color: #586e75;
-            --gnome-tabbar-tab-hover-background: #073642;
-            --gnome-tabbar-tab-active-background: #073642;
-          }
-
-          /* Center bookmarks */
-          #PlacesToolbarItems {
-            justify-content: center;
-          }
-
-          /* Disable bookmark folder icons */
-          .bookmark-item[container] > .toolbarbutton-icon {
-            display: none;
-          }
-        '';
-
-        userContent = ''@import "firefox-gnome-theme/userContent.css";'';
-
-        settings = {
-          # https://github.com/rafaelmardojai/firefox-gnome-theme?tab=readme-ov-file#features
-          "gnomeTheme.bookmarksToolbarUnderTabs" = true;
-          #// "gnomeTheme.systemIcons" = true;
-
-          "font.default.x-unicode" = config.custom.settings.fonts.sans-serif;
-          "font.default.x-western" = config.custom.settings.fonts.sans-serif;
-          "font.name-list.emoji" = config.custom.settings.fonts.emoji; # System emoji
-          "font.name.monospace.x-unicode" = config.custom.settings.fonts.monospace;
-          "font.name.monospace.x-western" = config.custom.settings.fonts.monospace;
-          "font.name.sans-serif.x-unicode" = config.custom.settings.fonts.sans-serif;
-          "font.name.sans-serif.x-western" = config.custom.settings.fonts.sans-serif;
-          "font.name.serif.x-unicode" = config.custom.settings.fonts.sans-serif;
-          "font.name.serif.x-western" = config.custom.settings.fonts.sans-serif;
-          "full-screen-api.ignore-widgets" = false; # Fake fullscreen
-          "full-screen-api.warning.delay" = -1;
-          "full-screen-api.warning.timeout" = 0;
-          "middlemouse.paste" = false;
-          "privacy.donottrackheader.enabled" = true;
-          "privacy.fingerprintingProtection" = false;
-          "privacy.globalprivacycontrol.enabled" = true;
-          "svg.context-properties.content.enabled" = true; # Dark theme icons
-        };
-      };
-
-      # https://mozilla.github.io/policy-templates
-      policies = {
-        CaptivePortal = false;
-        DisableFirefoxStudies = true;
-        DisableFormHistory = true;
-        DisableMasterPasswordCreation = true;
-        DisablePocket = true;
-        DisableSetDesktopBackground = true;
-        DisableTelemetry = true;
-
-        DNSOverHTTPS = {
-          Enabled = false;
-          Locked = true;
-        };
-
-        DontCheckDefaultBrowser = true;
-
-        # https://mozilla.github.io/policy-templates/#extensionsettings
-        #?? https://addons.mozilla.org/en-US/firefox
-        #?? about:support#addons
-        ExtensionSettings = let
-          extension = id: {
-            install_url = "https://addons.mozilla.org/firefox/downloads/latest/${id}/latest.xpi";
-            installation_mode = "normal_installed";
-          };
-        in
-          mkMerge [
-            (mkIf config.custom.minimal {
-              "uBlock0@raymondhill.net" = extension "ublock-origin"; # uBlock Origin
-            })
-
-            (mkIf config.custom.full {
-              "{d634138d-c276-4fc8-924b-40a0ea21d284}" = extension "1password-x-password-manager"; # 1Password: Password Manager
-              #// "firefox@betterttv.net" = extension "betterttv"; # BetterTTV
-              #// "{446900e4-71c2-419f-a6a7-df9c091e268b}" = extension "bitwarden-password-manager"; # Bitwarden
-              #// "FirefoxColor@mozilla.com" = extension "firefox-color"; # Firefox Color
-              #// "chrome-gnome-shell@gnome.org" = extension "gnome-shell-integration"; # GNOME Shell Integration
-              #// "{248e6a49-f636-4c81-9899-a456eb6291a8}" = extension "ground-news-bias-checker"; # Ground News Bias Checker
-              #// "{3c6bf0cc-3ae2-42fb-9993-0d33104fdcaf}" = extension "youtube-addon"; # ImprovedTube
-              #// "7esoorv3@alefvanoon.anonaddy.me" = extension "libredirect"; # LibRedirect
-              #// "firefoxpwa@filips.si" = extension "pwas-for-firefox"; # Progressive Web Apps for Firefox
-              "select-after-closing-current@qw.linux-2g64.local" = extension "select-after-closing-current"; # Select After Closing Current
-              "myallychou@gmail.com" = extension "youtube-recommended-videos"; # Unhook: Remove YouTube Recommended Videos Comments
-              "simple-tab-groups@drive4ik" = extension "simple-tab-groups"; # Simple Tab Groups
-              "sponsorBlocker@ajay.app" = extension "sponsorblock"; # SponsorBlock
-              "{7a7a4a92-a2a0-41d1-9fd7-1e92480d612d}" = extension "styl-us"; # Stylus
-              #// "{a0370179-acc3-452f-9530-246b6adb2768}" = extension "svelte-devtools"; # Svelte Devtools
-              "uBlock0@raymondhill.net" = extension "ublock-origin"; # uBlock Origin
-              #// "{2662ff67-b302-4363-95f3-b050218bd72c}" = extension "untrap-for-youtube"; # UnTrap for YouTube
-              #// "{a6c4a591-f1b2-4f03-b3ff-767e5bedf4e7}" = extension "user-agent-string-switcher"; # User-Agent Switcher and Manager
-              #// "{c49b13b1-5dee-4345-925e-0c793377e3fa}" = extension "youtube-enhancer-vc"; # YouTube Enhancer
-            })
-          ];
-
-        FirefoxHome = {
-          Highlights = false;
-          Pocket = false;
-          Search = false;
-          Snippets = false;
-          SponsoredPocket = false;
-          SponsoredTopSites = false;
-          TopSites = false;
-          Locked = true;
-        };
-
-        FirefoxSuggest = {
-          ImproveSuggest = false;
-          SponsoredSuggestions = false;
-          WebSuggestions = false;
-          Locked = true;
-        };
-
-        HardwareAcceleration = true;
-
-        Homepage = {
-          StartPage = "previous-session";
-          Locked = true;
-        };
-
-        NetworkPrediction = false;
-        NoDefaultBookmarks = true;
-        OfferToSaveLogins = false;
-        OverrideFirstRunPage = "";
-        PasswordManagerEnabled = false;
-
-        Permissions = {
-          Autoplay.Default = "block-audio-video";
-          Location.BlockNewRequests = true;
-        };
-
-        PictureInPicture = {
-          Enabled = true;
-          Locked = true;
-        };
-
-        PopupBlocking.Default = true;
-
-        #!! Only certain preferences are supported via policies
-        # https://mozilla.github.io/policy-templates/#preferences
-        #?? about:config
-        Preferences = let
-          locked = value: {
-            Value = value;
-            Status = "locked";
-          };
-        in {
-          "accessibility.browsewithcaret" = locked false;
-          "accessibility.typeaheadfind" = locked false;
-          "browser.aboutConfig.showWarning" = locked false;
-          "browser.contentblocking.category" = locked "standard";
-          "browser.crashReports.unsubmittedCheck.autoSubmit2" = locked false;
-          "browser.ctrlTab.sortByRecentlyUsed" = locked false;
-          "browser.download.always_ask_before_handling_new_types" = locked false;
-          "browser.download.useDownloadDir" = locked true;
-          "browser.link.open_newwindow" = locked 3; # New tab
-          "browser.link.open_newwindow.restriction" = locked 0; # Popups in new tab
-          "browser.newtabpage.enabled" = locked true;
-          "browser.preferences.defaultPerformanceSettings.enabled" = locked true;
-          "browser.quitShortcut.disabled" = locked true;
-          "browser.search.widget.inNavBar" = locked false;
-          "browser.startup.homepage" = locked "about:home";
-          "browser.startup.page" = locked 3; # Previous session
-          "browser.tabs.allowTabDetach" = locked false;
-          "browser.tabs.closeTabByDblclick" = locked true;
-          "browser.tabs.closeWindowWithLastTab" = locked false;
-          "browser.tabs.insertAfterCurrent" = locked false;
-          "browser.tabs.insertRelatedAfterCurrent" = locked false;
-          "browser.tabs.loadInBackground" = locked true;
-          "browser.tabs.warnOnClose" = locked false;
-          "browser.tabs.warnOnCloseOtherTabs" = locked false;
-          "browser.theme.dark-private-windows" = locked false;
-          "browser.toolbars.bookmarks.showOtherBookmarks" = locked false;
-          "browser.uidensity" = locked 0;
-          "browser.warnOnQuitShortcut" = locked true;
-          "dom.security.https_only_mode" = locked true;
-          "extensions.formautofill.addresses.enabled" = locked false;
-          "extensions.formautofill.creditCards.enabled" = locked false;
-          "general.autoScroll" = locked false;
-          "general.smoothScroll" = locked true;
-          "gfx.webrender.software" = locked config.custom.programs.looking-glass.igpu; # Reduce load on iGPU
-          "layers.acceleration.force-enabled" = locked true;
-          "layout.css.always_underline_links" = locked false;
-          "layout.css.backdrop-filter.enabled" = locked true;
-          "layout.spellcheckDefault" = locked 0; # Disabled
-          "media.eme.enabled" = locked true; # DRM
-          "media.ffmpeg.vaapi.enabled" = locked true;
-          "media.hardwaremediakeys.enabled" = locked true;
-          "media.hardware-video-decoding.enabled" = locked true;
-          #// "media.rdd-process.enabled" = locked false; # RDD sandbox #!! Insecure
-          "toolkit.legacyUserProfileCustomizations.stylesheets" = locked true;
-          "ui.key.menuAccessKey" = locked 0; # Disable menu key
-          "widget.gtk.overlay-scrollbars.enabled" = locked true;
-          "widget.gtk.rounded-bottom-corners.enabled" = locked true;
-        };
-
-        SearchBar = "unified";
-
-        # https://mozilla.github.io/policy-templates/#searchengines-this-policy-is-only-available-on-the-esr
-        SearchEngines = {
-          Default = "Kagi";
-
-          Add = [
-            {
-              Name = "Amazon";
-              Alias = "a";
-              IconURL = "https://www.amazon.com/favicon.ico";
-              URLTemplate = "https://www.amazon.com/s?k={searchTerms}";
-            }
-
-            {
-              Name = "ArchWiki";
-              Alias = "aw";
-              IconURL = "https://wiki.archlinux.org/favicon.ico";
-              URLTemplate = "https://wiki.archlinux.org/index.php?search={searchTerms}";
-            }
-
-            {
-              Name = "Brave";
-              Alias = "b";
-              IconURL = "https://cdn.search.brave.com/serp/v2/_app/immutable/assets/favicon.c09fe1a1.ico";
-              URLTemplate = "https://search.brave.com/search?q={searchTerms}";
-            }
-
-            {
-              Name = "Duck";
-              Alias = "d";
-              IconURL = "https://duckduckgo.com/favicon.ico";
-              URLTemplate = "https://duckduckgo.com/?q={searchTerms}";
-              SuggestURLTemplate = "https://duckduckgo.com/ac/?type=list&q={searchTerms}";
-            }
-
-            {
-              Name = "Docker Hub";
-              Alias = "dh";
-              IconURL = "https://hub.docker.com/favicon.ico";
-              URLTemplate = "https://hub.docker.com/search?q={searchTerms}";
-            }
-
-            {
-              Name = "e621";
-              Alias = "e";
-              IconURL = "https://e621.net/favicon.ico";
-              URLTemplate = "https://e621.net/posts?tags={searchTerms}";
-            }
-
-            {
-              Name = "Element Issues";
-              Alias = "ei";
-              IconURL = "https://github.com/favicon.ico";
-              URLTemplate = "https://github.com/element-hq/element-web/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
-            }
-
-            {
-              Name = "Flathub";
-              Alias = "fh";
-              IconURL = "https://flathub.org/favicon.png";
-              URLTemplate = "https://flathub.org/apps/search?q={searchTerms}";
-            }
-
-            {
-              Name = "Google";
-              Alias = "g";
-              IconURL = "https://www.google.com/favicon.ico";
-              URLTemplate = "https://www.google.com/search?q={searchTerms}";
-            }
-
-            {
-              Name = "Google Fonts";
-              Alias = "gf";
-              IconURL = "https://www.gstatic.com/images/icons/material/apps/fonts/1x/catalog/v5/favicon.svg";
-              URLTemplate = "https://fonts.google.com/?query={searchTerms}";
-            }
-
-            {
-              Name = "GitHub";
-              Alias = "gh";
-              IconURL = "https://github.com/favicon.ico";
-              URLTemplate = "https://github.com/search?q={searchTerms}";
-            }
-
-            {
-              Name = "Home Manager Issues";
-              Alias = "hi";
-              IconURL = "https://github.com/favicon.ico";
-              URLTemplate = "https://github.com/nix-community/home-manager/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
-            }
-
-            {
-              Name = "Home Manager Options";
-              Alias = "ho";
-              IconURL = "https://home-manager-options.extranix.com/images/favicon.png";
-              URLTemplate = "https://home-manager-options.extranix.com/?query={searchTerms}&release=master";
-            }
-
-            {
-              Name = "Hyprland Issues";
-              Alias = "hyi";
-              IconURL = "https://github.com/favicon.ico";
-              URLTemplate = "https://github.com/hyprwm/Hyprland/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
-            }
-
-            {
-              Name = "i3 Issues";
-              Alias = "ii";
-              IconURL = "https://github.com/favicon.ico";
-              URLTemplate = "https://github.com/i3/i3/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
-            }
-
-            {
-              Name = "Kagi";
-              Alias = "k";
-              IconURL = "https://kagi.com/asset/v2/favicon-32x32.png";
-              URLTemplate = "https://kagi.com/search?q={searchTerms}";
-              SuggestURLTemplate = "https://kagi.com/api/autosuggest?q={searchTerms}";
-            }
-
-            {
-              Name = "Lutris";
-              Alias = "l";
-              IconURL = "https://lutris.net/favicon.ico";
-              URLTemplate = "https://lutris.net/games?q={searchTerms}";
-            }
-
-            {
-              Name = "Lix Issues";
-              Alias = "li";
-              IconURL = "https://git.lix.systems/assets/img/favicon.png";
-              URLTemplate = "https://git.lix.systems/lix-project/lix/issues?state=open&q={searchTerms}";
-            }
-
-            {
-              Name = "Mozilla Web Docs";
-              Alias = "mdn";
-              IconURL = "https://developer.mozilla.org/favicon-48x48.cbbd161b.png";
-              URLTemplate = "https://developer.mozilla.org/en-US/search?q={searchTerms}";
-            }
-
-            {
-              Name = "MyNixOS Options";
-              Alias = "mno";
-              IconURL = "https://mynixos.com/favicon.ico";
-              URLTemplate = "https://mynixos.com/search?q=option+{searchTerms}";
-            }
-
-            {
-              Name = "Nix Dev";
-              Alias = "nd";
-              IconURL = "https://nix.dev/manual/nix/latest/favicon.png";
-              URLTemplate = "https://nix.dev/manual/nix/latest?search={searchTerms}";
-            }
-
-            {
-              Name = "NixOS Flakes";
-              Alias = "nf";
-              IconURL = "https://nixos.org/favicon.png";
-              URLTemplate = "https://search.nixos.org/flakes?channel=unstable&query={searchTerms}";
-            }
-
-            {
-              Name = "Nix Hub";
-              Alias = "nh";
-              IconURL = "https://www.nixhub.io/favicon.ico";
-              URLTemplate = "https://www.nixhub.io/search?q={searchTerms}";
-            }
-
-            {
-              Name = "NixOS Nixpkgs Issues";
-              Alias = "ni";
-              IconURL = "https://github.com/favicon.ico";
-              URLTemplate = "https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
-            }
-
-            {
-              Name = "Nix PR";
-              Alias = "npr";
-              URLTemplate = "https://nixpk.gs/pr-tracker.html?pr={searchTerms}";
-            }
-
-            {
-              Name = "NixOS Options";
-              Alias = "no";
-              IconURL = "https://nixos.org/favicon.png";
-              URLTemplate = "https://search.nixos.org/options?channel=unstable&query={searchTerms}";
-            }
-
-            {
-              Name = "Noogle Dev";
-              Alias = "nod";
-              IconURL = "https://noogle.dev/favicon.png";
-              URLTemplate = "https://noogle.dev/q?term={searchTerms}";
-            }
-
-            {
-              Name = "NixOS Packages";
-              Alias = "np";
-              IconURL = "https://nixos.org/favicon.png";
-              URLTemplate = "https://search.nixos.org/packages?channel=unstable&query={searchTerms}";
-            }
-
-            {
-              Name = "Niri Issues";
-              Alias = "nri";
-              IconURL = "https://github.com/favicon.ico";
-              URLTemplate = "https://github.com/YaLTeR/niri/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
-            }
-
-            {
-              Name = "NixOS Wiki";
-              Alias = "nw";
-              IconURL = "https://wiki.nixos.org/favicon.ico";
-              URLTemplate = "https://wiki.nixos.org/w/index.php?search={searchTerms}";
-            }
-
-            {
-              Name = "Piped";
-              Alias = "p";
-              IconURL = "https://piped.${config.custom.domain}/favicon.ico";
-              URLTemplate = "https://piped.${config.custom.domain}/results?search_query={searchTerms}";
-            }
-
-            {
-              Name = "PCGamingWiki";
-              Alias = "pc";
-              IconURL = "https://static.pcgamingwiki.com/favicons/pcgamingwiki.png";
-              URLTemplate = "https://www.pcgamingwiki.com/w/index.php?search={searchTerms}";
-            }
-
-            {
-              Name = "ProtonDB";
-              Alias = "pdb";
-              IconURL = "https://www.protondb.com/sites/protondb/images/favicon.ico";
-              URLTemplate = "https://www.protondb.com/search?q={searchTerms}";
-            }
-
-            {
-              Name = "PyPI";
-              Alias = "pip";
-              IconURL = "https://pypi.org/static/images/favicon.35549fe8.ico";
-              URLTemplate = "https://pypi.org/search/?q={searchTerms}";
-            }
-
-            {
-              Name = "Reddit";
-              Alias = "r";
-              IconURL = "https://www.redditstatic.com/desktop2x/img/favicon/favicon-96x96.png";
-              URLTemplate = "https://kagi.com/search?q=site%3Areddit.com+{searchTerms}";
-            }
-
-            {
-              Name = "SearXNG";
-              Alias = "s";
-              IconURL = "https://search.${config.custom.domain}/static/themes/simple/img/favicon.png";
-              URLTemplate = "https://search.${config.custom.domain}/search?q={searchTerms}";
-            }
-
-            {
-              Name = "Sway Issues";
-              Alias = "si";
-              IconURL = "https://github.com/favicon.ico";
-              URLTemplate = "https://github.com/swaywm/sway/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
-            }
-
-            {
-              Name = "Wikipedia";
-              Alias = "w";
-              IconURL = "https://en.wikipedia.org/static/favicon/wikipedia.ico";
-              URLTemplate = "https://en.wikipedia.org/w/index.php?search={searchTerms}";
-            }
-
-            {
-              Name = "Wolfram Alpha";
-              Alias = "wa";
-              IconURL = "https://www.wolframalpha.com/_next/static/images/favicon_1zbE9hjk.ico";
-              URLTemplate = "https://www.wolframalpha.com/input?i={searchTerms}";
-            }
-
-            {
-              Name = "Walker Issues";
-              Alias = "wi";
-              IconURL = "https://github.com/favicon.ico";
-              URLTemplate = "https://github.com/abenz1267/walker/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
-            }
-
-            {
-              Name = "YouTube";
-              Alias = "y";
-              IconURL = "https://www.youtube.com/s/desktop/f8c8418d/img/favicon.ico";
-              URLTemplate = "https://www.youtube.com/results?search_query={searchTerms}";
-            }
-          ];
-
-          Remove = [
-            "Amazon.com"
-            "Bing"
-            "DuckDuckGo"
-            "eBay"
-            "Google"
-            "Wikipedia (en)"
-          ];
-        };
-
-        SearchSuggestEnabled = true;
-        ShowHomeButton = true;
-
-        UserMessaging = {
-          ExtensionRecommendations = false;
-          FeatureRecommendations = false;
-          MoreFromMozilla = false;
-          SkipOnboarding = false;
-          UrlbarInterventions = false;
-          WhatsNew = false;
-          Locked = true;
-        };
-      };
-    };
-
-    home.file = {
-      # TODO: Consider other themes
-      # https://github.com/soulhotel/FF-ULTIMA
-
-      # CSS theme to import into profile
-      # https://github.com/rafaelmardojai/firefox-gnome-theme
-      ".mozilla/firefox/default/chrome/firefox-gnome-theme".source = inputs.firefox-gnome-theme;
-
-      # Imperative symlinks intended to be synced
-      "Downloads/stg" = mkIf config.custom.full {
-        source = config.home-manager.users.${config.custom.username}.lib.file.mkOutOfStoreSymlink "${config.custom.sync}/common/config/extensions/Simple Tab Groups";
-      };
-
-      # Work around icon dissociation due to missing --name flag in actions
-      # https://github.com/micheleg/dash-to-dock/issues/1968
-      #!! Keep updated with upstream desktop file
-      #?? cat /etc/profiles/per-user/myned/share/applications/firefox-esr.desktop
-      # ".local/share/applications/firefox-esr.desktop".text = ''
-      #   [Desktop Entry]
-      #   Actions=new-private-window;new-window;profile-manager-window
-      #   Categories=Network;WebBrowser
-      #   Exec=firefox --name firefox %U
-      #   GenericName=Web Browser
-      #   Icon=firefox
-      #   MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;x-scheme-handler/http;x-scheme-handler/https
-      #   Name=Firefox ESR
-      #   StartupNotify=true
-      #   StartupWMClass=firefox
-      #   Terminal=false
-      #   Type=Application
-      #   Version=1.4
-
-      #   [Desktop Action new-private-window]
-      #   Exec=firefox --name firefox --private-window %U
-      #   Name=New Private Window
-
-      #   [Desktop Action new-window]
-      #   Exec=firefox --name firefox --new-window %U
-      #   Name=New Window
-
-      #   [Desktop Action profile-manager-window]
-      #   Exec=firefox --name firefox --ProfileManager
-      #   Name=Profile Manager
-      # '';
-    };
-  };
-}
diff --git a/options/custom/programs/firefox/firefox.nix b/options/custom/programs/firefox/firefox.nix
new file mode 100644
index 0000000..0635f64
--- /dev/null
+++ b/options/custom/programs/firefox/firefox.nix
@@ -0,0 +1,35 @@
+{
+  config,
+  inputs,
+  lib,
+  pkgs,
+  ...
+}:
+with lib; let
+  cfg = config.custom.programs.firefox;
+in {
+  options.custom.programs.firefox = {
+    enable = mkOption {default = false;};
+  };
+
+  config = mkIf cfg.enable {
+    home-manager.sharedModules = [
+      {
+        # https://www.mozilla.org/en-US/firefox/developer
+        programs.firefox = mkMerge [
+          (import "${inputs.self}/modules/firefox.nix" {inherit config inputs lib pkgs;})
+
+          {
+            enable = true;
+          }
+        ];
+
+        home.file = {
+          ".mozilla/profiles.ini" = {
+            force = true;
+          };
+        };
+      }
+    ];
+  };
+}
diff --git a/options/custom/programs/firefox/librewolf.nix b/options/custom/programs/firefox/librewolf.nix
new file mode 100644
index 0000000..44033f7
--- /dev/null
+++ b/options/custom/programs/firefox/librewolf.nix
@@ -0,0 +1,36 @@
+{
+  config,
+  inputs,
+  lib,
+  pkgs,
+  ...
+}:
+with lib; let
+  cfg = config.custom.programs.librewolf;
+in {
+  options.custom.programs.librewolf = {
+    enable = mkOption {default = false;};
+  };
+
+  config = mkIf cfg.enable {
+    home-manager.sharedModules = [
+      {
+        # https://librewolf.net/
+        # https://codeberg.org/librewolf
+        programs.librewolf = mkMerge [
+          (import "${inputs.self}/modules/firefox.nix" {inherit config inputs lib pkgs;})
+
+          {
+            enable = true;
+          }
+        ];
+
+        home.file = {
+          ".librewolf/profiles.ini" = {
+            force = true;
+          };
+        };
+      }
+    ];
+  };
+}
diff --git a/options/custom/programs/librewolf.nix b/options/custom/programs/librewolf.nix
deleted file mode 100644
index 407106d..0000000
--- a/options/custom/programs/librewolf.nix
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  config,
-  lib,
-  ...
-}:
-with lib; let
-  cfg = config.custom.programs.librewolf;
-in {
-  options.custom.programs.librewolf.enable = mkOption {default = false;};
-
-  config.home-manager.users.${config.custom.username} = mkIf cfg.enable {
-    # https://codeberg.org/librewolf
-    # TODO: Revisit when extensions can be managed declaratively
-    # https://github.com/nix-community/home-manager/issues/2803
-    programs.librewolf.enable = true;
-  };
-}