diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index 15de138c957e80ec19104b3eedf95033905939e1..038579c0bdb3bf36cf33a56a51387dcc84c706c9 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -48,7 +48,6 @@
 
 // static
 std::set<std::string> LLFirstUse::sConfigVariables;
-std::map<std::string, LLNotificationPtr> LLFirstUse::sNotifications;
 
 // static
 void LLFirstUse::addConfigVariable(const std::string& var)
@@ -78,21 +77,10 @@ void LLFirstUse::resetFirstUse()
 	}
 }
 
-// static
-void LLFirstUse::useOverrideKeys()
-{
-	// Our orientation island uses key overrides to teach vehicle driving
-	// so don't show this message until you get off OI. JC
-	if (!gAgent.inPrelude())
-	{
-		firstUseNotification("FirstOverrideKeys", true, "FirstOverrideKeys");
-	}
-}
-
 // static
 void LLFirstUse::otherAvatarChatFirst(bool enable)
 {
-	firstUseNotification("FirstOtherChatBeforeUser", enable, "HintChat", LLSD(), LLSD().with("target", "nearby_chat_bar").with("direction", "top"));
+	firstUseNotification("FirstOtherChatBeforeUser", enable, "HintChat", LLSD(), LLSD().with("target", "incoming_chat").with("direction", "right"));
 }
 
 // static
@@ -143,24 +131,48 @@ void LLFirstUse::receiveLindens(bool enable)
 //static 
 void LLFirstUse::firstUseNotification(const std::string& control_var, bool enable, const std::string& notification_name, LLSD args, LLSD payload)
 {
-	LLNotificationPtr notif = sNotifications[notification_name];
+	init();
 
 	if (enable)
 	{
-		if (!notif && gWarningSettings.getBOOL(control_var))
+		LL_DEBUGS("LLFirstUse") << "Trigger first use notification " << notification_name << LL_ENDL;
+
+		// if notification doesn't already exist and this notification hasn't been disabled...
+		if (gWarningSettings.getBOOL(control_var))
 		{ // create new notification
-			sNotifications[notification_name] = LLNotifications::instance().add(LLNotification::Params().name(notification_name).substitutions(args).payload(payload));
-			gWarningSettings.setBOOL(control_var, FALSE);
+			LLNotifications::instance().add(LLNotification::Params().name(notification_name).substitutions(args).payload(payload.with("control_var", control_var)));
 		}
 	}	
 	else
-	{ // want to hide notification
-		if (notif)
-		{ // cancel existing notification
-			LLNotifications::instance().cancel(notif);
-			sNotifications.erase(notification_name);
-		}
-		gWarningSettings.setBOOL(control_var, FALSE);
+	{
+		LL_DEBUGS("LLFirstUse") << "Disabling first use notification " << notification_name << LL_ENDL;
+		LLNotifications::instance().cancelByName(notification_name);
+	}
+
+}
+
+// static
+void LLFirstUse::init()
+{
+	static bool initialized = false;
+	if (!initialized)
+	{
+		LLNotifications::instance().getChannel("Hints")->connectChanged(processNotification);
 	}
+	initialized = true;
+}
 
+//static 
+bool LLFirstUse::processNotification(const LLSD& notify)
+{
+	if (notify["sigtype"].asString() == "delete")
+	{
+		LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
+		if (notification)
+		{
+			// disable any future notifications
+			gWarningSettings.setBOOL(notification->getPayload()["control_var"], FALSE);
+		}
+	}
+	return false;
 }
diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h
index 48943cd9ab1b70a4ff742c9cf6eba640794e9b64..9c4ab140061edd1c8cbab1155d84e5f5dd69c796 100644
--- a/indra/newview/llfirstuse.h
+++ b/indra/newview/llfirstuse.h
@@ -90,7 +90,6 @@ class LLFirstUse
 	static void disableFirstUse();
 	static void resetFirstUse();
 
-	static void useOverrideKeys();
 	static void otherAvatarChatFirst(bool enable = true);
 	static void sit(bool enable = true);
 	static void notUsingDestinationGuide(bool enable = true);
@@ -103,7 +102,9 @@ class LLFirstUse
 protected:
 	static void firstUseNotification(const std::string& control_var, bool enable, const std::string& notification_name, LLSD args = LLSD(), LLSD payload = LLSD());
 	static std::set<std::string> sConfigVariables;
-	static std::map<std::string, boost::shared_ptr<LLNotification> > sNotifications;
+
+	static void init();
+	static bool processNotification(const LLSD& notify);
 };
 
 #endif
diff --git a/indra/newview/llhints.cpp b/indra/newview/llhints.cpp
index 14a9871a7d958a3e0bc9fbdd8146eda20df28fb1..c4cea86a318f6e873684f0cd4bb2f842b248e39a 100644
--- a/indra/newview/llhints.cpp
+++ b/indra/newview/llhints.cpp
@@ -63,11 +63,21 @@ class LLHintPopup : public LLPanel
 		}
 	};
 
+	struct TargetParams : public LLInitParam::Block<TargetParams>
+	{
+		Mandatory<std::string>	target;
+		Mandatory<EPopupDirection, PopupDirections> direction;
+
+		TargetParams()
+		:	target("target"),
+			direction("direction")
+		{}
+	};
+
 	struct Params : public LLInitParam::Block<Params, LLPanel::Params>
 	{
 		Mandatory<LLNotificationPtr>	notification;
-		Optional<std::string>			target;
-		Optional<EPopupDirection, PopupDirections>	direction;
+		Optional<TargetParams>			target_params;
 		Optional<S32>					distance;
 		Optional<LLUIImage*>			left_arrow,
 										up_arrow,
@@ -81,34 +91,31 @@ class LLHintPopup : public LLPanel
 										fade_out_time;
 
 		Params()
-		:	direction("direction", TOP),
-			distance("distance", 24),
-			target("target"),
-			left_arrow("left_arrow", LLUI::getUIImage("hint_arrow_left")),
-			up_arrow("up_arrow", LLUI::getUIImage("hint_arrow_up")),
-			right_arrow("right_arrow", LLUI::getUIImage("hint_arrow_right")),
-			down_arrow("down_arrow", LLUI::getUIImage("hint_arrow_down")),
-			left_arrow_offset("left_arrow_offset", 3),
-			up_arrow_offset("up_arrow_offset", -2),
-			right_arrow_offset("right_arrow_offset", -3),
-			down_arrow_offset("down_arrow_offset", 5),
-			fade_in_time("fade_in_time", 0.2f),
-			fade_out_time("fade_out_time", 0.5f)
+		:	distance("distance"),
+			left_arrow("left_arrow"),
+			up_arrow("up_arrow"),
+			right_arrow("right_arrow"),
+			down_arrow("down_arrow"),
+			left_arrow_offset("left_arrow_offset"),
+			up_arrow_offset("up_arrow_offset"),
+			right_arrow_offset("right_arrow_offset"),
+			down_arrow_offset("down_arrow_offset"),
+			fade_in_time("fade_in_time"),
+			fade_out_time("fade_out_time")
 		{}
 	};
 
 	LLHintPopup(const Params&);
 
-	void setHintTarget(LLHandle<LLView> target) { mTarget = target; }
 	/*virtual*/ BOOL postBuild();
 
-	void onClickClose() { hide(); }
+	void onClickClose() { hide(); LLNotifications::instance().cancel(mNotification); }
 	void draw();
 	void hide() { if(!mHidden) {mHidden = true; mFadeTimer.reset();} }
 
 private:
 	LLNotificationPtr	mNotification;
-	LLHandle<LLView>	mTarget;
+	std::string			mTarget;
 	EPopupDirection		mDirection;
 	S32					mDistance;
 	LLUIImagePtr		mArrowLeft,
@@ -125,14 +132,14 @@ class LLHintPopup : public LLPanel
 	bool				mHidden;
 };
 
-
+static LLDefaultChildRegistry::Register<LLHintPopup> r("hint_popup");
 
 
 LLHintPopup::LLHintPopup(const LLHintPopup::Params& p)
 :	mNotification(p.notification),
-	mDirection(p.direction),
+	mDirection(p.target_params.direction),
 	mDistance(p.distance),
-	mTarget(LLHints::getHintTarget(p.target)),
+	mTarget(p.target_params.target),
 	mArrowLeft(p.left_arrow),
 	mArrowUp(p.up_arrow),
 	mArrowRight(p.right_arrow),
@@ -146,7 +153,7 @@ LLHintPopup::LLHintPopup(const LLHintPopup::Params& p)
 	mFadeOutTime(p.fade_out_time),
 	LLPanel(p)
 {
-	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_hint.xml");
+	buildPanel(this, "panel_hint.xml", NULL, p);
 }
 
 BOOL LLHintPopup::postBuild()
@@ -172,80 +179,108 @@ void LLHintPopup::draw()
 		if (alpha == 0.f)
 		{
 			die();
+			return;
 		}
 	}
 	else
 	{
 		alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, mFadeInTime, 0.f, 1.f);
 	}
-	LLViewDrawContext context(alpha);
-
-	LLView* targetp = mTarget.get();
-	if (!targetp || !targetp->isInVisibleChain()) 
-	{
-		hide();
-	}
-	else
-	{
-		LLRect target_rect;
-		targetp->localRectToOtherView(targetp->getLocalRect(), &target_rect, getParent());
-
-		LLRect my_local_rect = getLocalRect();
-		LLRect my_rect;
-		LLRect arrow_rect;
-		LLUIImagePtr arrow_imagep;
+	
+	{	LLViewDrawContext context(alpha); 
 
-		switch(mDirection)
+		if (mTarget.empty())
 		{
-		case LEFT:
-			my_rect.setCenterAndSize(	target_rect.mLeft - (my_local_rect.getWidth() / 2 + mDistance), 
-										target_rect.getCenterY(), 
-										my_local_rect.getWidth(), 
-										my_local_rect.getHeight());
-			arrow_rect.setCenterAndSize(my_local_rect.mRight + mArrowRight->getWidth() / 2 + mArrowRightOffset,
-										my_local_rect.getCenterY(),
-										mArrowRight->getWidth(), 
-										mArrowRight->getHeight());
-			arrow_imagep = mArrowRight;
-			break;
-		case TOP:
-			my_rect.setCenterAndSize(	target_rect.getCenterX(), 
-										target_rect.mTop + (my_local_rect.getHeight() / 2 + mDistance), 
-										my_local_rect.getWidth(), 
-										my_local_rect.getHeight());
-			arrow_rect.setCenterAndSize(my_local_rect.getCenterX(),
-										my_local_rect.mBottom - mArrowDown->getHeight() / 2 + mArrowDownOffset,
-										mArrowDown->getWidth(), 
-										mArrowDown->getHeight());
-			arrow_imagep = mArrowDown;
-			break;
-		case RIGHT:
-			my_rect.setCenterAndSize(	target_rect.getCenterX(), 
-										target_rect.mTop - (my_local_rect.getHeight() / 2 + mDistance), 
-										my_local_rect.getWidth(), 
-										my_local_rect.getHeight());
-			arrow_rect.setCenterAndSize(my_local_rect.mLeft - mArrowLeft->getWidth() / 2 + mArrowLeftOffset,
-										my_local_rect.getCenterY(),
-										mArrowLeft->getWidth(), 
-										mArrowLeft->getHeight());
-			arrow_imagep = mArrowLeft;
-			break;
-		case BOTTOM:
-			my_rect.setCenterAndSize(	target_rect.getCenterX(), 
-										target_rect.mBottom - (my_local_rect.getHeight() / 2 + mDistance),
-										my_local_rect.getWidth(), 
-										my_local_rect.getHeight());
-			arrow_rect.setCenterAndSize(my_local_rect.getCenterX(),
-										my_local_rect.mTop + mArrowUp->getHeight() / 2 + mArrowUpOffset,
-										mArrowUp->getWidth(), 
-										mArrowUp->getHeight());
-			arrow_imagep = mArrowUp;
-			break;
+			// just draw contents, no arrow, in default position
+			LLPanel::draw();
+		}
+		else 
+		{
+			LLView* targetp = LLHints::getHintTarget(mTarget).get();
+			if (!targetp)
+			{
+				// target widget is no longer valid, go away
+				die();
+			}
+			else if (!targetp->isInVisibleChain()) 
+			{
+				// if target is invisible, don't draw, but keep alive in case widget comes back
+			}
+			else
+			{
+				LLRect target_rect;
+				targetp->localRectToOtherView(targetp->getLocalRect(), &target_rect, getParent());
+
+				LLRect my_local_rect = getLocalRect();
+				LLRect my_rect;
+				LLRect arrow_rect;
+				LLUIImagePtr arrow_imagep;
+
+				switch(mDirection)
+				{
+				case LEFT:
+					my_rect.setCenterAndSize(	target_rect.mLeft - (my_local_rect.getWidth() / 2 + mDistance), 
+												target_rect.getCenterY(), 
+												my_local_rect.getWidth(), 
+												my_local_rect.getHeight());
+					if (mArrowRight)
+					{
+						arrow_rect.setCenterAndSize(my_local_rect.mRight + mArrowRight->getWidth() / 2 + mArrowRightOffset,
+													my_local_rect.getCenterY(),
+													mArrowRight->getWidth(), 
+													mArrowRight->getHeight());
+						arrow_imagep = mArrowRight;
+					}
+					break;
+				case TOP:
+					my_rect.setCenterAndSize(	target_rect.getCenterX(), 
+												target_rect.mTop + (my_local_rect.getHeight() / 2 + mDistance), 
+												my_local_rect.getWidth(), 
+												my_local_rect.getHeight());
+					if (mArrowDown)
+					{
+						arrow_rect.setCenterAndSize(my_local_rect.getCenterX(),
+													my_local_rect.mBottom - mArrowDown->getHeight() / 2 + mArrowDownOffset,
+													mArrowDown->getWidth(), 
+													mArrowDown->getHeight());
+						arrow_imagep = mArrowDown;
+					}
+					break;
+				case RIGHT:
+					my_rect.setCenterAndSize(	target_rect.mRight + (my_local_rect.getWidth() / 2 + mDistance), 
+												target_rect.getCenterY(),
+												my_local_rect.getWidth(), 
+												my_local_rect.getHeight());
+					if (mArrowLeft)
+					{
+						arrow_rect.setCenterAndSize(my_local_rect.mLeft - mArrowLeft->getWidth() / 2 + mArrowLeftOffset,
+													my_local_rect.getCenterY(),
+													mArrowLeft->getWidth(), 
+													mArrowLeft->getHeight());
+						arrow_imagep = mArrowLeft;
+					}
+					break;
+				case BOTTOM:
+					my_rect.setCenterAndSize(	target_rect.getCenterX(), 
+												target_rect.mBottom - (my_local_rect.getHeight() / 2 + mDistance),
+												my_local_rect.getWidth(), 
+												my_local_rect.getHeight());
+					if (mArrowUp)
+					{
+						arrow_rect.setCenterAndSize(my_local_rect.getCenterX(),
+													my_local_rect.mTop + mArrowUp->getHeight() / 2 + mArrowUpOffset,
+													mArrowUp->getWidth(), 
+													mArrowUp->getHeight());
+						arrow_imagep = mArrowUp;
+					}
+					break;
+				}
+				setShape(my_rect);
+				LLPanel::draw();
+
+				if (arrow_imagep) arrow_imagep->draw(arrow_rect, LLColor4(1.f, 1.f, 1.f, alpha));
+			}
 		}
-		setShape(my_rect);
-		LLPanel::draw();
-
-		arrow_imagep->draw(arrow_rect, LLColor4(1.f, 1.f, 1.f, alpha));
 	}
 }
 
@@ -256,20 +291,23 @@ std::map<LLNotificationPtr, class LLHintPopup*> LLHints::sHints;
 //static
 void LLHints::show(LLNotificationPtr hint)
 {
-	LLHintPopup::Params p;
-	LLParamSDParser::instance().readSD(hint->getPayload(), p);
+	LLHintPopup::Params p(LLUICtrlFactory::getDefaultParams<LLHintPopup>());
 
+	LLParamSDParser::instance().readSD(hint->getPayload(), p);
 	p.notification = hint;
 
-	LLHintPopup* popup = new LLHintPopup(p);
-	
-	sHints[hint] = popup;
-
-	LLView* hint_holder = gViewerWindow->getHintHolder();
-	if (hint_holder)
+	if (p.validateBlock())
 	{
-		hint_holder->addChild(popup);
-		popup->centerWithin(hint_holder->getLocalRect());
+		LLHintPopup* popup = new LLHintPopup(p);
+
+		sHints[hint] = popup;
+
+		LLView* hint_holder = gViewerWindow->getHintHolder();
+		if (hint_holder)
+		{
+			hint_holder->addChild(popup);
+			popup->centerWithin(hint_holder->getLocalRect());
+		}
 	}
 }
 
@@ -286,7 +324,7 @@ void LLHints::hide(LLNotificationPtr hint)
 //static
 void LLHints::registerHintTarget(const std::string& name, LLHandle<LLView> target)
 {
-	sTargetRegistry.defaultRegistrar().add(name, target);
+	sTargetRegistry.defaultRegistrar().replace(name, target);
 }
 
 //static 
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 60b0b1e8dcfd553100795c2ce8adabd2175efed2..47bb0fe45b707906820c801797c44d1396a78223 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6402,6 +6402,7 @@ Mute everyone?
   label="Chat"
   type="hint">
     To join the conversation, type into the chat field below.
+    <unique/>
   </notification>
 
   <notification
@@ -6409,21 +6410,23 @@ Mute everyone?
   label="Stand"
   type="hint">
     To stand up and exit the sitting position, click the Stand button.
+    <unique/>
   </notification>
-  
+
   <notification
   name="HintDestinationGuide"
   label="Explore the World"
   type="hint">
     The Destination Guide contains thousands of new places to discover. Select a location and choose Teleport to start exploring.
+    <unique/>
   </notification>
-  
+
   <notification
     name="HintSidePanel"
     label="Side Panel"
     type="hint">
     Get quick access to your inventory, outfits, profiles and more in the side panel.
-    <!--<unique/>-->
+    <unique/>
   </notification>
 
   <notification
@@ -6431,7 +6434,7 @@ Mute everyone?
   label="Move"
   type="hint">
     To walk or run, open the Move Panel and use the directional arrows to navigate. You can also use the directional keys on your keyboard.
-    <!--<unique/>-->
+    <unique/>
   </notification>
 
   <notification
@@ -6439,6 +6442,7 @@ Mute everyone?
   label="Inventory"
   type="hint">
     Check your inventory to find items. Newest items can be easily found in the Recent tab.
+    <unique/>
   </notification>
 
   <notification
@@ -6446,6 +6450,7 @@ Mute everyone?
   label="You've got Linden Dollars!"
   type="hint">
     Here's your current balance of L$. Click Buy L$ to purchase more Linden Dollars.
+    <unique/>
   </notification>
 
   <global name="UnsupportedCPU">
diff --git a/indra/newview/skins/default/xui/en/panel_hint.xml b/indra/newview/skins/default/xui/en/panel_hint.xml
index 54ea08e5d430190b68fb81cb643924ef7fef382e..839dbc58f2552dcf624f176488ef0f52643878fb 100644
--- a/indra/newview/skins/default/xui/en/panel_hint.xml
+++ b/indra/newview/skins/default/xui/en/panel_hint.xml
@@ -1,12 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <panel
- name="hint"
  width="205"
- height="100"
- background_opaque="true"
- background_visible="true"
- layout="topleft" 
- bg_opaque_image="hint_background">
+ height="100">
   <text name="hint_title"
         font="SansSerifMedium" 
         left="8"
@@ -20,7 +15,7 @@
         left="8"
         right="197"
         top="26"
-        bottom="90"
+        bottom="92"
         follows="all" 
         text_color="White"
         wrap="true"/>
diff --git a/indra/newview/skins/default/xui/en/widgets/hint_popup.xml b/indra/newview/skins/default/xui/en/widgets/hint_popup.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fbd92f982efb20c537ed51df9b47464206ce43bd
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/hint_popup.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<hint_popup
+ name="hint"
+ background_opaque="true"
+ background_visible="true"
+ layout="topleft"
+ bg_opaque_image="hint_background"
+ distance="24"
+ left_arrow="hint_arrow_left"
+ up_arrow="hint_arrow_up" 
+ right_arrow="hint_arrow_right"
+ down_arrow="hint_arrow_down"
+ left_arrow_offset="3"
+ up_arrow_offset="-2"
+ right_arrow_offset="-3"
+ down_arrow_offset="5"
+ fade_in_time="0.2"
+ fade_out_time="0.3">
+</hint_popup>