diff --git a/Resources/Content/.all.js b/Resources/Content/.all.js
index 53b0fcf0..5747e563 100644
--- a/Resources/Content/.all.js
+++ b/Resources/Content/.all.js
@@ -6,6 +6,7 @@
 
 import introduction from "./introduction/introduction.js";
 import hide_cookie_bar from "./login/hide_cookie_bar.js";
+import redirect_plain_twitter_com from "./login/redirect_plain_twitter_com";
 import setup_document_attributes from "./login/setup_document_attributes.js";
 import add_skip_button from "./notification/add_skip_button.js";
 import disable_clipboard_formatting_notification from "./notification/disable_clipboard_formatting.js";
diff --git a/Resources/Content/tweetdeck/globals/patch_functions.js b/Resources/Content/api/patch.js
similarity index 96%
rename from Resources/Content/tweetdeck/globals/patch_functions.js
rename to Resources/Content/api/patch.js
index 513644fd..712ad632 100644
--- a/Resources/Content/tweetdeck/globals/patch_functions.js
+++ b/Resources/Content/api/patch.js
@@ -1,4 +1,4 @@
-import { crashDebug } from "../../api/utils.js";
+import { crashDebug } from "./utils.js";
 
 /**
  * @callback FunctionReplacementCallback
diff --git a/Resources/Content/login/redirect_plain_twitter_com.js b/Resources/Content/login/redirect_plain_twitter_com.js
new file mode 100644
index 00000000..31a6e1a6
--- /dev/null
+++ b/Resources/Content/login/redirect_plain_twitter_com.js
@@ -0,0 +1,23 @@
+import { replaceFunction } from "../api/patch.js";
+
+function redirectToTweetDeck() {
+	location.href = "https://tweetdeck.twitter.com";
+}
+
+function hookHistoryStateFunction(func, args) {
+	debugger;
+	if (args[2] === "/") {
+		redirectToTweetDeck();
+	}
+	else {
+		func.apply(this, args);
+	}
+}
+
+/**
+ * Redirects plain twitter.com to TweetDeck, so that users cannot accidentally land on twitter.com login.
+ */
+export default function() {
+	replaceFunction(window.history, "pushState", hookHistoryStateFunction);
+	replaceFunction(window.history, "replaceState", hookHistoryStateFunction);
+};
diff --git a/Resources/Content/login/setup_document_attributes.js b/Resources/Content/login/setup_document_attributes.js
index 0b48a437..5cae123e 100644
--- a/Resources/Content/login/setup_document_attributes.js
+++ b/Resources/Content/login/setup_document_attributes.js
@@ -1,3 +1,6 @@
+/**
+ * Sets up attributes on the <html> element for styling login/logout pages.
+ */
 export default function() {
 	if (location.pathname === "/login") {
 		document.documentElement.setAttribute("login", "");
diff --git a/Resources/Content/tweetdeck/bypass_t.co_links.js b/Resources/Content/tweetdeck/bypass_t.co_links.js
index 0e0b94c5..20dafc10 100644
--- a/Resources/Content/tweetdeck/bypass_t.co_links.js
+++ b/Resources/Content/tweetdeck/bypass_t.co_links.js
@@ -1,7 +1,7 @@
 import { $TD } from "../api/bridge.js";
+import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { checkPropertyExists } from "../api/utils.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 /**
  * @property {string[]} eventNames
diff --git a/Resources/Content/tweetdeck/configure_language_for_translations.js b/Resources/Content/tweetdeck/configure_language_for_translations.js
index e5c93a6a..d0527d84 100644
--- a/Resources/Content/tweetdeck/configure_language_for_translations.js
+++ b/Resources/Content/tweetdeck/configure_language_for_translations.js
@@ -1,7 +1,7 @@
 import { $TDX } from "../api/bridge.js";
+import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { ensurePropertyExists } from "../api/utils.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 /**
  * Sets language for automatic translations.
diff --git a/Resources/Content/tweetdeck/fix_dm_input_box_focus.js b/Resources/Content/tweetdeck/fix_dm_input_box_focus.js
index a920dc32..50a972c9 100644
--- a/Resources/Content/tweetdeck/fix_dm_input_box_focus.js
+++ b/Resources/Content/tweetdeck/fix_dm_input_box_focus.js
@@ -1,7 +1,7 @@
 import { $TDX } from "../api/bridge.js";
+import { runAfterFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { ensurePropertyExists } from "../api/utils.js";
-import { runAfterFunction } from "./globals/patch_functions.js";
 
 function focusDmInput() {
 	document.querySelector(".js-reply-tweetbox").focus();
diff --git a/Resources/Content/tweetdeck/fix_horizontal_scrolling_of_column_container.js b/Resources/Content/tweetdeck/fix_horizontal_scrolling_of_column_container.js
index 1eb98f92..0f353e46 100644
--- a/Resources/Content/tweetdeck/fix_horizontal_scrolling_of_column_container.js
+++ b/Resources/Content/tweetdeck/fix_horizontal_scrolling_of_column_container.js
@@ -1,7 +1,7 @@
 import { $ } from "../api/jquery.js";
+import { runAfterFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { ensurePropertyExists } from "../api/utils.js";
-import { runAfterFunction } from "./globals/patch_functions.js";
 import { prioritizeNewestEvent } from "./globals/prioritize_newest_event.js";
 
 /**
diff --git a/Resources/Content/tweetdeck/fix_media_preview_urls.js b/Resources/Content/tweetdeck/fix_media_preview_urls.js
index d85dcf35..9eecd331 100644
--- a/Resources/Content/tweetdeck/fix_media_preview_urls.js
+++ b/Resources/Content/tweetdeck/fix_media_preview_urls.js
@@ -1,6 +1,6 @@
+import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { ensurePropertyExists } from "../api/utils.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 const formatRegex = /\?.*format=(\w+)/;
 
diff --git a/Resources/Content/tweetdeck/fix_missing_bing_translator_languages.js b/Resources/Content/tweetdeck/fix_missing_bing_translator_languages.js
index 1026f53d..dc514935 100644
--- a/Resources/Content/tweetdeck/fix_missing_bing_translator_languages.js
+++ b/Resources/Content/tweetdeck/fix_missing_bing_translator_languages.js
@@ -1,6 +1,6 @@
+import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { ensurePropertyExists } from "../api/utils.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 /**
  * Adds missing languages for Bing Translator (Bengali, Icelandic, Tagalog, Tamil, Telugu, Urdu).
diff --git a/Resources/Content/tweetdeck/focus_composer_after_alt_tab.js b/Resources/Content/tweetdeck/focus_composer_after_alt_tab.js
index 9fa58de6..7ebe7eba 100644
--- a/Resources/Content/tweetdeck/focus_composer_after_alt_tab.js
+++ b/Resources/Content/tweetdeck/focus_composer_after_alt_tab.js
@@ -1,6 +1,6 @@
 import { $ } from "../api/jquery.js";
+import { replaceFunction } from "../api/patch.js";
 import { onAppReady } from "../api/ready.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 import { prioritizeNewestEvent } from "./globals/prioritize_newest_event.js";
 
 /**
diff --git a/Resources/Content/tweetdeck/hook_theme_settings.js b/Resources/Content/tweetdeck/hook_theme_settings.js
index 67f1bddb..136fc7ec 100644
--- a/Resources/Content/tweetdeck/hook_theme_settings.js
+++ b/Resources/Content/tweetdeck/hook_theme_settings.js
@@ -1,9 +1,9 @@
 import { $TD } from "../api/bridge.js";
+import { runAfterFunction } from "../api/patch.js";
 import { onAppReady } from "../api/ready.js";
 import { TD } from "../api/td.js";
 import { ensurePropertyExists } from "../api/utils.js";
 import { getClassStyleProperty } from "./globals/get_class_style_property.js";
-import { runAfterFunction } from "./globals/patch_functions.js";
 
 function refreshSettings() {
 	const fontSizeName = TD.settings.getFontSize();
diff --git a/Resources/Content/tweetdeck/limit_loaded_dm_count.js b/Resources/Content/tweetdeck/limit_loaded_dm_count.js
index 87aca70e..7d560fd8 100644
--- a/Resources/Content/tweetdeck/limit_loaded_dm_count.js
+++ b/Resources/Content/tweetdeck/limit_loaded_dm_count.js
@@ -1,8 +1,8 @@
 // noinspection JSUnusedGlobalSymbols
 
+import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { ensurePropertyExists } from "../api/utils.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 /**
  * Limits amount of loaded DMs to avoid massive lag from re-opening them several times.
diff --git a/Resources/Content/tweetdeck/make_retweets_lowercase.js b/Resources/Content/tweetdeck/make_retweets_lowercase.js
index 90b10e5d..cc64e2d7 100644
--- a/Resources/Content/tweetdeck/make_retweets_lowercase.js
+++ b/Resources/Content/tweetdeck/make_retweets_lowercase.js
@@ -1,7 +1,7 @@
+import { runAfterFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { checkPropertyExists } from "../api/utils.js";
 import { injectMustache } from "./globals/inject_mustache.js";
-import { runAfterFunction } from "./globals/patch_functions.js";
 
 /**
  * Makes texts saying 'Retweet' lowercase.
diff --git a/Resources/Content/tweetdeck/restore_cleared_column.js b/Resources/Content/tweetdeck/restore_cleared_column.js
index 5e2e6bd6..159ca46d 100644
--- a/Resources/Content/tweetdeck/restore_cleared_column.js
+++ b/Resources/Content/tweetdeck/restore_cleared_column.js
@@ -1,7 +1,7 @@
 import { $ } from "../api/jquery.js";
+import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { checkPropertyExists } from "../api/utils.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 /**
  * Allows restoring cleared columns by holding Shift.
diff --git a/Resources/Content/tweetdeck/setup_desktop_notifications.js b/Resources/Content/tweetdeck/setup_desktop_notifications.js
index aa5cf20d..fb5c558c 100644
--- a/Resources/Content/tweetdeck/setup_desktop_notifications.js
+++ b/Resources/Content/tweetdeck/setup_desktop_notifications.js
@@ -1,9 +1,9 @@
 import { $TD, $TDX } from "../api/bridge.js";
 import { $ } from "../api/jquery.js";
+import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { checkPropertyExists, ensurePropertyExists } from "../api/utils.js";
 import { getColumnName } from "./globals/get_column_name.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 /**
  * Event callback for a new tweet.
diff --git a/Resources/Content/tweetdeck/setup_sound_notifications.js b/Resources/Content/tweetdeck/setup_sound_notifications.js
index 8836a7b9..6cd76364 100644
--- a/Resources/Content/tweetdeck/setup_sound_notifications.js
+++ b/Resources/Content/tweetdeck/setup_sound_notifications.js
@@ -1,6 +1,6 @@
 import { $TDX } from "../api/bridge.js";
+import { replaceFunction } from "../api/patch.js";
 import { isAppReady } from "../api/ready.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 /**
  * Adds support for sound notification settings.
diff --git a/Resources/Content/tweetdeck/setup_tweetduck_account_bamboozle.js b/Resources/Content/tweetdeck/setup_tweetduck_account_bamboozle.js
index 44242e67..01c51171 100644
--- a/Resources/Content/tweetdeck/setup_tweetduck_account_bamboozle.js
+++ b/Resources/Content/tweetdeck/setup_tweetduck_account_bamboozle.js
@@ -1,6 +1,6 @@
+import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { checkPropertyExists } from "../api/utils.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 /**
  * Replaces displayed name and avatar of the official TweetDuck account.
diff --git a/Resources/Content/tweetdeck/setup_video_player.js b/Resources/Content/tweetdeck/setup_video_player.js
index b78c03ab..c8671ac1 100644
--- a/Resources/Content/tweetdeck/setup_video_player.js
+++ b/Resources/Content/tweetdeck/setup_video_player.js
@@ -1,9 +1,9 @@
 import { $TD } from "../api/bridge.js";
+import { replaceFunction, runAfterFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { checkPropertyExists, noop } from "../api/utils.js";
 import { getHoveredTweet } from "./globals/get_hovered_tweet.js";
 import { injectMustache } from "./globals/inject_mustache.js";
-import { replaceFunction, runAfterFunction } from "./globals/patch_functions.js";
 
 /**
  * @param {HTMLElement} ele
diff --git a/Resources/Content/tweetdeck/skip_pre_login_page.js b/Resources/Content/tweetdeck/skip_pre_login_page.js
index e05a1dac..cfde8e1e 100644
--- a/Resources/Content/tweetdeck/skip_pre_login_page.js
+++ b/Resources/Content/tweetdeck/skip_pre_login_page.js
@@ -1,6 +1,6 @@
+import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { ensurePropertyExists } from "../api/utils.js";
-import { replaceFunction } from "./globals/patch_functions.js";
 
 /**
  * Skips the pre-login page so that users immediately see the login page.
diff --git a/TweetDuck.csproj b/TweetDuck.csproj
index a1a924c5..f70d86f9 100644
--- a/TweetDuck.csproj
+++ b/TweetDuck.csproj
@@ -389,6 +389,7 @@
     <Content Include="Resources\Content\.all.js" />
     <Content Include="Resources\Content\api\bridge.js" />
     <Content Include="Resources\Content\api\jquery.js" />
+    <Content Include="Resources\Content\api\patch.js" />
     <Content Include="Resources\Content\api\ready.js" />
     <Content Include="Resources\Content\api\td.js" />
     <Content Include="Resources\Content\api\utils.js" />
@@ -398,6 +399,7 @@
     <Content Include="Resources\Content\load.js" />
     <Content Include="Resources\Content\login\hide_cookie_bar.js" />
     <Content Include="Resources\Content\login\login.css" />
+    <Content Include="Resources\Content\login\redirect_plain_twitter_com.js" />
     <Content Include="Resources\Content\login\setup_document_attributes.js" />
     <Content Include="Resources\Content\notification\add_skip_button.js" />
     <Content Include="Resources\Content\notification\disable_clipboard_formatting.js" />
@@ -436,7 +438,6 @@
     <Content Include="Resources\Content\tweetdeck\globals\get_hovered_column.js" />
     <Content Include="Resources\Content\tweetdeck\globals\get_hovered_tweet.js" />
     <Content Include="Resources\Content\tweetdeck\globals\inject_mustache.js" />
-    <Content Include="Resources\Content\tweetdeck\globals\patch_functions.js" />
     <Content Include="Resources\Content\tweetdeck\globals\prioritize_newest_event.js" />
     <Content Include="Resources\Content\tweetdeck\globals\reload_browser.js" />
     <Content Include="Resources\Content\tweetdeck\globals\reload_columns.js" />