diff --git a/Core/FormBrowser.cs b/Core/FormBrowser.cs
index fa94e2cc..abc88fee 100644
--- a/Core/FormBrowser.cs
+++ b/Core/FormBrowser.cs
@@ -18,6 +18,7 @@ private static UserConfig Config{
 
         private readonly ChromiumWebBrowser browser;
         private readonly TweetDeckBridge bridge;
+        private readonly FormNotification notification;
 
         public FormBrowser(){
             InitializeComponent();
@@ -29,6 +30,9 @@ public FormBrowser(){
             browser.RegisterJsObject("$TD",bridge);
 
             Controls.Add(browser);
+
+            notification = new FormNotification(this);
+            notification.Show(this);
         }
 
         protected override void WndProc(ref Message m){
@@ -97,5 +101,9 @@ public void OpenSettings(){
         public void OpenAbout(){
             // TODO
         }
+
+        public void OnTweetPopup(string tweetHtml, string tweetColumn){
+            notification.ShowNotification(new TweetNotification(tweetHtml));
+        }
     }
-}
+}
\ No newline at end of file
diff --git a/Core/FormNotification.Designer.cs b/Core/FormNotification.Designer.cs
new file mode 100644
index 00000000..c68cb224
--- /dev/null
+++ b/Core/FormNotification.Designer.cs
@@ -0,0 +1,54 @@
+namespace TweetDick.Core {
+    partial class FormNotification {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing) {
+            if (disposing && (components != null)) {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent() {
+            this.components = new System.ComponentModel.Container();
+            this.timer = new System.Windows.Forms.Timer(this.components);
+            this.SuspendLayout();
+            // 
+            // timer
+            // 
+            this.timer.Tick += new System.EventHandler(this.timer_Tick);
+            // 
+            // FormNotification
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(284, 118);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
+            this.Location = new System.Drawing.Point(32000, 32000);
+            this.Name = "FormNotification";
+            this.ShowInTaskbar = false;
+            this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
+            this.Text = "TweetDick";
+            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormNotification_FormClosing);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Timer timer;
+    }
+}
\ No newline at end of file
diff --git a/Core/FormNotification.cs b/Core/FormNotification.cs
new file mode 100644
index 00000000..504c5361
--- /dev/null
+++ b/Core/FormNotification.cs
@@ -0,0 +1,86 @@
+using System.Windows.Forms;
+using CefSharp;
+using CefSharp.WinForms;
+using System.Drawing;
+using System;
+using System.Text;
+using System.Collections.Generic;
+using TweetDick.Core.Handling;
+
+namespace TweetDick.Core{
+    partial class FormNotification : Form{
+        private readonly FormBrowser owner;
+        private readonly ChromiumWebBrowser browser;
+
+        private readonly Queue<TweetNotification> tweetQueue = new Queue<TweetNotification>(4);
+
+        public FormNotification(FormBrowser owner){
+            InitializeComponent();
+
+            this.owner = owner;
+
+            browser = new ChromiumWebBrowser(""){ MenuHandler = new MenuHandlerEmpty() };
+            Controls.Add(browser);
+        }
+
+        public void ShowNotification(TweetNotification notification){
+            Screen screen = Screen.FromControl(owner);
+            Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-16-Width,screen.WorkingArea.Y+16);
+
+            tweetQueue.Enqueue(notification);
+
+            if (!timer.Enabled){
+                LoadNextNotification();
+            }
+        }
+
+        public void HideNotification(){
+            browser.Load("about:blank");
+            Location = new Point(32000,32000);
+        }
+
+        private void LoadNextNotification(){
+            TweetNotification tweet = tweetQueue.Dequeue();
+
+            browser.Load("about:blank");
+            browser.LoadHtml(tweet.GenerateHtml(),"http://tweetdeck.twitter.com/");
+
+            timer.Stop();
+            timer.Interval = 5000;
+            timer.Start();
+        }
+
+        private void timer_Tick(object sender, EventArgs e){
+            if (tweetQueue.Count > 0){
+                LoadNextNotification();
+            }
+            else{
+                HideNotification();
+            }
+        }
+
+        private void FormNotification_FormClosing(object sender, FormClosingEventArgs e){
+            if (e.CloseReason == CloseReason.UserClosing){
+                HideNotification();
+                tweetQueue.Clear();
+                e.Cancel = true;
+            }
+        }
+
+        private class MenuHandlerEmpty : IContextMenuHandler{
+            public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
+                model.Clear();
+            }
+
+            public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
+                return false;
+            }
+
+            public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){}
+
+            public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
+                return false;
+            }
+        }
+    }
+}
diff --git a/Core/Handling/TweetDeckBridge.cs b/Core/Handling/TweetDeckBridge.cs
index f68e0c5d..0dc6ffc6 100644
--- a/Core/Handling/TweetDeckBridge.cs
+++ b/Core/Handling/TweetDeckBridge.cs
@@ -6,12 +6,30 @@ public TweetDeckBridge(FormBrowser form){
             this.form = form;
         }
 
+        public void LoadFontSizeClass(string fsClass){
+            form.InvokeSafe(() => {
+               TweetNotification.SetFontSizeClass(fsClass);
+            });
+        }
+
+        public void LoadNotificationHeadContents(string headContents){
+            form.InvokeSafe(() => {
+               TweetNotification.SetHeadTag(headContents); 
+            });
+        }
+
         public void OpenSettingsMenu(){
             form.InvokeSafe(() => {
                 form.OpenSettings();
             });
         }
 
+        public void OnTweetPopup(string tweetHtml, string tweetColumn){
+            form.InvokeSafe(() => {
+                form.OnTweetPopup(tweetHtml,tweetColumn);
+            });
+        }
+
         public void Log(string data){
             System.Diagnostics.Debug.WriteLine(data);
         }
diff --git a/Core/Handling/TweetNotification.cs b/Core/Handling/TweetNotification.cs
new file mode 100644
index 00000000..f9f30acd
--- /dev/null
+++ b/Core/Handling/TweetNotification.cs
@@ -0,0 +1,34 @@
+using System.Text;
+
+namespace TweetDick.Core.Handling{
+    sealed class TweetNotification{
+        private static string FontSizeClass { get; set; }
+        private static string HeadTag { get; set; }
+
+        public static void SetFontSizeClass(string newFSClass){
+            FontSizeClass = newFSClass;
+        }
+
+        public static void SetHeadTag(string headContents){
+            HeadTag = headContents;
+        }
+
+        private readonly string html;
+
+        public TweetNotification(string html){
+            this.html = html;
+        }
+
+        public string GenerateHtml(){
+            StringBuilder build = new StringBuilder();
+            build.Append("<!DOCTYPE html>");
+            build.Append("<html class='os-windows ").Append(FontSizeClass).Append("'>");
+            build.Append("<head>").Append(HeadTag).Append("</head>");
+            build.Append("<body class='hearty'><div class='app-columns-container'><div class='column' style='width:100%'>");
+            build.Append(html);
+            build.Append("</div></div></body>");
+            build.Append("</html>");
+            return build.ToString();
+        }
+    }
+}
diff --git a/Resources/code.js b/Resources/code.js
index 3e9c0cd3..6c0a9777 100644
--- a/Resources/code.js
+++ b/Resources/code.js
@@ -1,9 +1,19 @@
 (function($,$TD){
+  //
+  // Constant: List of valid font size classes.
+  //
+  var fontSizeClasses = [ "txt-base-smallest", "txt-base-small", "txt-base-medium", "txt-base-large", "txt-base-largest" ];
+  
   //
   // Variable: Says whether TweetDick events was initialized.
   //
   var isInitialized = false;
   
+  //
+  // Variable: Previous font size class in the <html> tag.
+  //
+  var prevFontSizeClass;
+  
   //
   // Function: Initializes TweetDick events. Called after the website app is loaded.
   //
@@ -29,9 +39,94 @@
       },0);
     });
     
+    // Tweet notifications
+    (function(){
+      var columns = $(".js-app-columns").first();
+
+      var refreshColumnObservers = function(){
+        columns.children().each(function(){
+          registerTweetObserverForColumn($(this));
+        });
+      };
+
+      new MutationObserver(refreshColumnObservers).observe(columns[0],{
+        childList: true
+      });
+
+      refreshColumnObservers();
+    })();
+    
     isInitialized = true;
   };
   
+  //
+  // Function: Registers an observer to a TweetDeck column, which reports new tweets.
+  //
+  var registerTweetObserverForColumn = function(column){
+    if (column[0].hasAttribute("data-tweetdick-observed"))return;
+    
+    var mid = column;
+    mid = mid.children().first();
+    mid = mid.children().first();
+    mid = mid.children(".js-column-content").first();
+    mid = mid.children(".js-column-scroller").first();
+    
+    var container = mid.children(".js-chirp-container").first();
+    if (container.length == 0)return;
+    
+    new MutationObserver(function(mutations){
+      // TODO check if popups are enabled first
+      
+      Array.prototype.forEach.call(mutations,function(mutation){
+        Array.prototype.forEach.call(mutation.addedNodes,function(node){
+          if (node.tagName != "ARTICLE")return;
+          
+          onNewTweet(column,node);
+        });
+      });
+    }).observe(container[0],{
+      childList: true
+    });
+    
+    column[0].setAttribute("data-tweetdick-observed","");
+  };
+  
+  //
+  // Function: Event callback for a new tweet.
+  //
+  var onNewTweet = function(column, tweet){
+    var html = $(tweet.outerHTML);
+    html.find("footer:first").remove();
+    
+    $TD.onTweetPopup(html.html(),""); // TODO
+  };
+  
+  //
+  // Function: Retrieves the font size using <html> class attribute.
+  //
+  var getFontSizeClass = function(){
+    for(var index = 0; index < fontSizeClasses.length; index++){
+      if (document.documentElement.classList.contains(fontSizeClasses[index])){
+        return fontSizeClasses[index];
+      }
+    }
+    
+    return fontSizeClasses[0];
+  };
+  
+  //
+  // Function: Retrieves the tags to be put into <head> for notification HTML code.
+  //
+  var getNotificationHeadContents = function(){
+    var tags = [];
+    
+    $(document.head).children("link[rel='stylesheet'],meta[charset],meta[http-equiv]").each(function(){
+      tags.push($(this)[0].outerHTML);
+    });
+    
+    return tags.join("");
+  };
+  
   //
   // Block: Observe the app <div> element and initialize TweetDick whenever possible.
   //
@@ -48,4 +143,31 @@
     attributes: true,
     attributeFilter: [ "class" ]
   });
+  
+  //
+  // Block: Observe changes in <html> class to update font size.
+  //
+  new MutationObserver(function(mutations){
+    var fsClass = getFontSizeClass();
+    
+    if (fsClass != prevFontSizeClass){
+      prevFontSizeClass = fsClass;
+      $TD.loadFontSizeClass(fsClass);
+    }
+  }).observe(document.documentElement,{
+    attributes: true,
+    attributeFilter: [ "class" ]
+  });
+  
+  //
+  // Block: Observe stylesheet swapping.
+  //
+  new MutationObserver(function(mutations){
+    $TD.loadNotificationHeadContents(getNotificationHeadContents());
+  }).observe(document.head.querySelector("[http-equiv='Default-Style']"),{
+    attributes: true,
+    attributeFilter: [ "content" ]
+  });
+  
+  $TD.loadNotificationHeadContents(getNotificationHeadContents());
 })($,$TD);
diff --git a/TweetDick.csproj b/TweetDick.csproj
index 8197786b..13c9dbb9 100644
--- a/TweetDick.csproj
+++ b/TweetDick.csproj
@@ -86,6 +86,13 @@
     <Compile Include="Core\FormBrowser.Designer.cs">
       <DependentUpon>FormBrowser.cs</DependentUpon>
     </Compile>
+    <Compile Include="Core\FormNotification.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Core\FormNotification.Designer.cs">
+      <DependentUpon>FormNotification.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Core\Handling\TweetNotification.cs" />
     <Compile Include="Core\RichTextLabel.cs">
       <SubType>Component</SubType>
     </Compile>