Index: wp-admin/js/custom-background.js
===================================================================
--- wp-admin/js/custom-background.js	(revision 23000)
+++ wp-admin/js/custom-background.js	(working copy)
@@ -37,8 +37,8 @@
 				}
 			});
 
-			frame.toolbar.on( 'activate:select', function() {
-				frame.toolbar.view().set({
+			frame.on( 'toolbar:render:select', function( view ) {
+				view.set({
 					select: {
 						style: 'primary',
 						text:  $el.data('update'),
Index: wp-admin/js/custom-header.js
===================================================================
--- wp-admin/js/custom-header.js	(revision 23000)
+++ wp-admin/js/custom-header.js	(working copy)
@@ -24,8 +24,8 @@
 				}
 			});
 
-			frame.toolbar.on( 'activate:select', function() {
-				frame.toolbar.view().set({
+			frame.on( 'toolbar:render:select', function( view ) {
+				view.set({
 					select: {
 						style: 'primary',
 						text:  $el.data('update'),
Index: wp-includes/css/media-views-rtl.css
===================================================================
--- wp-includes/css/media-views-rtl.css	(revision 23000)
+++ wp-includes/css/media-views-rtl.css	(working copy)
@@ -1,25 +1,14 @@
 /**
  * Modal
  */
-.media-modal-title {
-	left: auto;
-	right: 0;
-}
-
 .media-modal-close {
 	right: auto;
-	left: 0;
+	left: 7px;
 }
 
 /**
  * Toolbar
  */
-.media-frame-toolbar > .media-toolbar {
-	left: 0;
-	right: 200px;
-}
-
-
 .media-toolbar-primary {
 	float: left;
 }
@@ -93,21 +82,51 @@
  * Menu
  */
 .media-menu {
-	left: auto;
-	right: 0;
 	border-right: 0;
 	border-left: 1px solid #d9d9d9;
 	box-shadow: inset 6px 0 6px -6px rgba( 0, 0, 0, 0.2 )
 }
 
 /**
+ * Router
+ */
+.media-router > a {
+	float: right;
+	border-right: 0;
+	border-left: 1px solid #dfdfdf;
+}
+.media-router > a:last-child {
+	border-left: 0;
+}
+
+/**
  * Frame
  */
-.media-frame .region-content {
+.media-frame-menu {
+	left: auto;
+	right: 0;
+}
+
+.media-frame-title,
+.media-frame-router,
+.media-frame-content,
+.media-frame-toolbar {
 	left: 0;
 	right: 200px;
 }
 
+.media-frame.hide-menu .media-frame-title,
+.media-frame.hide-menu .media-frame-router,
+.media-frame.hide-menu .media-frame-toolbar,
+.media-frame.hide-menu .media-frame-content {
+	right: 0;
+}
+
+.media-frame.hide-menu .media-frame-menu {
+	left: auto;
+	right: -200px;
+}
+
 /**
  * Attachment Browser Filters
  */
@@ -226,30 +245,6 @@
 }
 
 /**
- * Selection Preview
- */
-.selected-img {
-	float: right;
-	margin-right: 0;
-	margin-left: 14px;
-}
-
-.selection-preview img {
-	float: right;
-	margin-left: 0;
-	margin-right: 1px;
-}
-
-.selection-preview .count {
-	right: auto;
-	left: 0;
-}
-
-.selection-preview .clear-selection {
-	float: right;
-}
-
-/**
  * Attachment Details
  */
 .attachment-info .thumbnail {
@@ -289,8 +284,10 @@
  * Responsive layout
  */
 @media only screen and (max-width: 900px) {
-	.media-frame .region-content,
-	.media-frame-toolbar > .media-toolbar {
+	.media-frame-title,
+	.media-frame-router,
+	.media-frame-content,
+	.media-frame-toolbar {
 		left: 0;
 		right: 140px;
 	}
Index: wp-includes/css/media-views.css
===================================================================
--- wp-includes/css/media-views.css	(revision 23000)
+++ wp-includes/css/media-views.css	(working copy)
@@ -80,10 +80,10 @@
  */
 .media-modal {
 	position: fixed;
-	top: 60px;
-	left: 40px;
-	right: 40px;
-	bottom: 40px;
+	top: 30px;
+	left: 30px;
+	right: 30px;
+	bottom: 30px;
 	z-index: 160000;
 }
 
@@ -94,42 +94,24 @@
 	right: 0;
 	bottom: 0;
 	background: #000;
-	opacity: 0.8;
+	opacity: 0.7;
 	z-index: 159900;
 }
 
-.media-modal-backdrop div,
-.uploader-window-content {
+.media-modal-close {
 	position: absolute;
-	top: 10px;
-	left: 10px;
-	right: 10px;
-	bottom: 10px;
-	border: 1px dashed rgba( 255, 255, 255, 0.5 );
+	top: 7px;
+	right: 7px;
+	width: 30px;
+	height: 30px;
+	z-index: 1000;
 }
-
-.media-modal-title {
-	position: absolute;
-	top: -40px;
-	left: 0;
-	height: 40px;
-	padding: 0;
-	margin: 0;
-
-	line-height: 40px;
-	color: #fff;
-	font-size: 16px;
-	font-weight: 200;
-	text-shadow: 0 0 16px rgba( 0, 0, 0, 0.6 );
-}
-
-.media-modal-close {
-	position: absolute;
-	top: -27px;
-	right: 0;
+.media-modal-close span {
+	display: block;
+	margin: 8px auto 0;
+	width: 15px;
 	height: 15px;
-	width: 15px;
-	background-position: -80px 0;
+	background-position: -100px 0;
 }
 
 .media-modal-close:active {
@@ -165,18 +147,6 @@
 	border: 0 solid #dfdfdf;
 }
 
-.media-frame-toolbar > .media-toolbar {
-	top: auto;
-	left: 200px;
-	bottom: 0;
-	border-width: 1px 0 0 0;
-	box-shadow: 0 -4px 4px -4px rgba( 0, 0, 0, 0.1 );
-}
-
-.hide-toolbar .media-frame-toolbar > .media-toolbar {
-	bottom: -61px;
-}
-
 .media-toolbar-primary {
 	float: right;
 }
@@ -238,11 +208,6 @@
 	width: 100%;
 }
 
-.media-sidebar .selection-preview {
-	display: block;
-	padding-top: 5px;
-}
-
 .media-sidebar h3 {
 	position: relative;
 	font-weight: bold;
@@ -361,11 +326,10 @@
 	position: absolute;
 	top: 0;
 	left: 0;
+	right: 0;
 	bottom: 0;
-	width: 199px;
 	margin: 0;
 	padding: 16px 0;
-	z-index: 200;
 	border-right: 1px solid #d9d9d9;
 	box-shadow: inset -6px 0 6px -6px rgba( 0, 0, 0, 0.2 );
 	-webkit-user-select: none;
@@ -374,7 +338,8 @@
 	user-select: none;
 }
 
-.media-menu li {
+.media-menu > a {
+	display: block;
 	position: relative;
 	padding: 4px 20px;
 	margin: 0;
@@ -382,14 +347,16 @@
 	font-size: 14px;
 	color: #21759B;
 	text-shadow: 0 1px 0 #fff;
+	text-decoration: none;
 }
 
-.media-menu-item {
-	cursor: pointer;
+.media-menu > a:hover {
+	color: #21759B;
+	background: rgba( 0, 0, 0, 0.04 );
 }
 
-.media-menu li:hover {
-	background: rgba( 0, 0, 0, 0.04 );
+.media-menu > a:active {
+	outline: none;
 }
 
 .media-menu .active,
@@ -407,6 +374,63 @@
 }
 
 /**
+ * Menu
+ */
+.media-router {
+	position: relative;
+	padding: 0 6px;
+	margin: 0;
+	clear: both;
+	-webkit-user-select: none;
+	-moz-user-select: none;
+	-ms-user-select: none;
+	user-select: none;
+}
+
+.media-router > a {
+	position: relative;
+	float: left;
+	padding: 2px 10px;
+	margin: 0;
+	height: 18px;
+	line-height: 18px;
+	font-size: 14px;
+	border-right: 1px solid #dfdfdf;
+	text-shadow: 0 1px 0 #fff;
+	text-decoration: none;
+}
+
+.media-router > a:last-child {
+	border-right: 0;
+}
+
+.media-router > a:active {
+	outline: none;
+}
+
+.media-router .active,
+.media-router .active:hover {
+	color: #333;
+}
+
+.media-router .active:after {
+	content: '';
+	display: block;
+	margin: -100px auto 0;
+	width: 7px;
+	height: 7px;
+	background: #fff;
+	box-shadow: 1px 1px 1px rgba( 0, 0, 0, 0.2 );
+	z-index: 300;
+
+	-webkit-transform: rotate( 45deg ) translate( 75px, 75px );
+	-moz-transform:    rotate( 45deg ) translate( 75px, 75px );
+	-ms-transform:     rotate( 45deg ) translate( 75px, 75px );
+	-o-transform:      rotate( 45deg ) translate( 75px, 75px );
+	transform:         rotate( 45deg ) translate( 75px, 75px );
+}
+
+/**
  * Frame
  */
 .media-frame {
@@ -418,11 +442,40 @@
 	bottom: 0;
 }
 
-.media-frame .region-content {
+.media-frame-menu {
 	position: absolute;
 	top: 0;
+	left: 0;
+	bottom: 0;
+	width: 199px;
+	z-index: 150;
+}
+
+.media-frame-title {
+	position: absolute;
+	top: 0;
 	left: 200px;
 	right: 0;
+	height: 45px;
+	z-index: 200;
+}
+
+.media-frame-router {
+	position: absolute;
+	top: 45px;
+	left: 200px;
+	right: 0;
+	height: 30px;
+	z-index: 200;
+	border-bottom: 1px solid #dfdfdf;
+	box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
+}
+
+.media-frame-content {
+	position: absolute;
+	top: 75px;
+	left: 200px;
+	right: 0;
 	bottom: 61px;
 	height: auto;
 	width: auto;
@@ -430,14 +483,62 @@
 	overflow: auto;
 }
 
-.media-frame.hide-toolbar .region-content {
+.media-frame-toolbar {
+	position: absolute;
+	left: 200px;
+	right: 0;
 	bottom: 0;
+	height: 60px;
+	z-index: 100;
+	border: 0 solid #dfdfdf;
+	border-width: 1px 0 0 0;
+	box-shadow: 0 -4px 4px -4px rgba( 0, 0, 0, 0.1 );
 }
 
+.media-frame.hide-menu .media-frame-title,
+.media-frame.hide-menu .media-frame-router,
+.media-frame.hide-menu .media-frame-toolbar,
+.media-frame.hide-menu .media-frame-content {
+	left: 0;
+}
+
+.media-frame.hide-menu .media-frame-menu {
+	left: -200px;
+}
+
+.media-frame.hide-toolbar .media-frame-content {
+	bottom: 0;
+}
+
+.media-frame.hide-toolbar .media-frame-toolbar {
+	bottom: -61px;
+}
+
+.media-frame.hide-router .media-frame-content {
+	top: 45px;
+}
+
+.media-frame.hide-router .media-frame-router {
+	display: none;
+}
+
+.media-frame.hide-router .media-frame-title {
+	border-bottom: 1px solid #dfdfdf;
+	box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
+}
+
 .media-frame .media-toolbar .add-to-gallery {
 	display: none;
 }
 
+.media-frame-title h1 {
+	padding: 0 16px;
+	font-size: 22px;
+	font-weight: 200;
+	line-height: 45px;
+	margin: 0;
+}
+
 /**
  * Iframes
  */
@@ -721,6 +822,9 @@
  * Attachments Browser
  */
 .media-frame .attachments-browser {
+	position: relative;
+	width: 100%;
+	height: 100%;
 	overflow: hidden;
 }
 
@@ -903,7 +1007,12 @@
 }
 
 .uploader-window-content {
-	border-color: #fff;
+	position: absolute;
+	top: 10px;
+	left: 10px;
+	right: 10px;
+	bottom: 10px;
+	border: 1px dashed #fff;
 }
 
 .uploader-window h3 {
@@ -956,6 +1065,10 @@
 	margin: 4em 0;
 }
 
+.uploader-inline .has-upload-message .upload-ui {
+	margin: 0 0 4em;
+}
+
 .uploader-inline h3 {
 	font-size: 20px;
 	line-height: 28px;
@@ -963,6 +1076,12 @@
 	margin-bottom: 1.6em;
 }
 
+.uploader-inline .has-upload-message .upload-instructions {
+	font-size: 14px;
+	color: #464646;
+	font-weight: normal;
+}
+
 .uploader-inline .drop-instructions {
 	display: none;
 }
@@ -1058,7 +1177,7 @@
 	vertical-align: top;
 }
 
-.media-selection .attachment img {
+.media-selection .attachment .icon {
 	width: 50%;
 }
 
@@ -1098,69 +1217,6 @@
 }
 
 /**
- * Selection Preview
- */
-.selection-preview {
-	position: relative;
-	height: 60px;
-	overflow: hidden;
-}
-
-.selected-img {
-	float: left;
-	position: relative;
-	margin-right: 14px;
-}
-
-.selection-preview img {
-	max-width: 40px;
-	max-height: 40px;
-	float: left;
-	margin-top: 6px;
-	margin-left: 1px;
-	border: 2px solid white;
-	box-shadow:
-	    0 0 0 1px #ccc,
-	    3px 3px 0 0 #fff,
-	    3px 3px 0 1px #ccc,
-	    6px 6px 0 0 #fff,
-	    6px 6px 0 1px #ccc;
-}
-
-.selection-preview .selected-count-1 img {
-	margin-top: 8px;
-	box-shadow: 0 0 0 1px #ccc;
-}
-
-.selection-preview .selected-count-2 img {
-	margin-top: 7px;
-	box-shadow:
-	    0 0 0 1px #ccc,
-	    3px 3px 0 0 #fff,
-	    3px 3px 0 1px #ccc;
-}
-
-.selection-preview .count {
-	position: absolute;
-	bottom: 0;
-	right: 0;
-	height: 16px;
-	min-width: 8px;
-	padding: 0 4px;
-	font-size: 12px;
-	text-align: center;
-	font-weight: bold;
-	color: #999;
-	background: #fff;
-	box-shadow: -1px -1px 2px -1px rgba( 0, 0, 0, 0.2 );
-}
-
-.selection-preview .clear-selection {
-	float: left;
-	line-height: 60px;
-}
-
-/**
  * Spinner
  */
 .media-sidebar .settings-save-status {
@@ -1297,21 +1353,17 @@
 .embed-url {
 	display: block;
 	position: relative;
-	height: 75px;
-	padding: 16px 16px;
+	height: 40px;
+	padding: 0 16px 16px;
 	margin: 0;
-	z-index: 50;
+	z-index: 250;
+	background: #fff;
 	border-bottom: 1px solid #dfdfdf;
 	box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
 	font-size: 18px;
 	font-weight: 200;
 }
 
-.embed-url span {
-	display: block;
-	padding: 4px 0 6px 2px;
-}
-
 .media-frame .embed-url input {
 	font-size: 18px;
 	padding: 12px 14px;
@@ -1324,7 +1376,7 @@
 .embed-image-settings {
 	position: absolute;
 	background: #f5f5f5;
-	top: 108px;
+	top: 57px;
 	left: 0;
 	right: 0;
 	bottom: 0;
@@ -1388,32 +1440,7 @@
  * Responsive layout
  */
 @media only screen and (max-width: 900px) {
-	.media-modal {
-		bottom: 20px;
-		left: 20px;
-		right: 20px;
-		top: 40px;
-	}
-
-	.media-modal-title {
-		height: 30px;
-		line-height: 30px;
-		top: -30px;
-	}
-
-	.media-modal-close {
-		top: -23px;
-	}
-
-	.media-modal-backdrop div,
-	.uploader-window-content {
-		top: 5px;
-		left: 5px;
-		right: 5px;
-		bottom: 5px;
-	}
-
-	.media-menu {
+	.media-frame-menu {
 		width: 139px;
 	}
 
@@ -1421,8 +1448,10 @@
 		padding: 4px 10px;
 	}
 
-	.media-frame .region-content,
-	.media-frame-toolbar > .media-toolbar {
+	.media-frame-title,
+	.media-frame-router,
+	.media-frame-content,
+	.media-frame-toolbar {
 		left: 140px;
 	}
 
Index: wp-includes/js/media-editor.js
===================================================================
--- wp-includes/js/media-editor.js	(revision 23000)
+++ wp-includes/js/media-editor.js	(working copy)
@@ -384,7 +384,7 @@
 
 			workflow = workflows[ id ] = wp.media( _.defaults( options || {}, {
 				frame:    'post',
-				state:    'upload',
+				state:    'insert',
 				title:    wp.media.view.l10n.addMedia,
 				multiple: true
 			} ) );
@@ -408,11 +408,13 @@
 			}, this );
 
 			workflow.state('embed').on( 'select', function() {
-				var embed = workflow.state().toJSON();
+				var state = workflow.state(),
+					type = state.get('type'),
+					embed = state.props.toJSON();
 
 				embed.url = embed.url || '';
 
-				if ( 'link' === embed.type ) {
+				if ( 'link' === type ) {
 					_.defaults( embed, {
 						title:   embed.url,
 						linkUrl: embed.url
@@ -420,7 +422,7 @@
 
 					this.send.link( embed );
 
-				} else if ( 'image' === embed.type ) {
+				} else if ( 'image' === type ) {
 					_.defaults( embed, {
 						title:   embed.url,
 						linkUrl: '',
Index: wp-includes/js/media-views.js
===================================================================
--- wp-includes/js/media-views.js	(revision 23000)
+++ wp-includes/js/media-views.js	(working copy)
@@ -68,65 +68,71 @@
 	 * wp.media.controller.Region
 	 */
 	media.controller.Region = function( options ) {
-		_.extend( this, _.pick( options || {}, 'id', 'controller', 'selector' ) );
-
-		this.on( 'activate:empty', this.empty, this );
-		this.mode('empty');
+		_.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
 	};
 
 	// Use Backbone's self-propagating `extend` inheritance method.
 	media.controller.Region.extend = Backbone.Model.extend;
 
-	_.extend( media.controller.Region.prototype, Backbone.Events, {
-		trigger: (function() {
-			var eventSplitter = /\s+/,
-				trigger = Backbone.Events.trigger;
+	_.extend( media.controller.Region.prototype, {
+		mode: function( mode ) {
+			if ( ! mode )
+				return this._mode;
 
-			return function( events ) {
-				var mode = ':' + this._mode,
-					modeEvents = events.split( eventSplitter ).join( mode ) + mode;
-
-				trigger.apply( this, arguments );
-				trigger.apply( this, [ modeEvents ].concat( _.rest( arguments ) ) );
+			// Bail if we're trying to change to the current mode.
+			if ( mode === this._mode )
 				return this;
-			};
-		}()),
 
-		mode: function( mode ) {
-			if ( mode ) {
-				this.trigger( 'deactivate', this );
-				this._mode = mode;
-				return this.trigger( 'activate', this );
-			}
-			return this._mode;
+			this.trigger('deactivate');
+			this._mode = mode;
+			this.render( mode );
+			this.trigger('activate');
+			return this;
 		},
 
-		view: function( view ) {
-			var previous = this._view,
-				mode = this._mode,
-				id = this.id;
+		render: function( mode ) {
+			// If no mode is provided, just re-render the current mode.
+			// If the provided mode isn't active, perform a full switch.
+			if ( mode && mode !== this._mode )
+				return this.mode( mode );
 
-			// If no argument is provided, return the current view.
-			if ( ! view )
-				return previous;
+			var set = { view: null },
+				view;
 
-			// If we're attempting to switch to the current view, bail.
-			if ( view === previous )
+			this.trigger( 'create', set );
+			view = set.view;
+			this.trigger( 'render', view );
+			if ( view )
+				this.set( view );
+			return this;
+		},
+
+		get: function() {
+			return this.view.views.first( this.selector );
+		},
+
+		set: function( views, options ) {
+			if ( options )
+				options.add = false;
+			return this.view.views.set( this.selector, views, options );
+		},
+
+		trigger: function( event ) {
+			var base;
+			if ( ! this._mode )
 				return;
 
-			// Add classes to the new view.
-			if ( id )
-				view.$el.addClass( 'region-' + id );
+			var args = _.toArray( arguments );
+			base = this.id + ':' + event;
 
-			if ( mode )
-				view.$el.addClass( 'mode-' + mode );
+			// Trigger `region:action:mode` event.
+			args[0] = base + ':' + this._mode;
+			this.view.trigger.apply( this.view, args );
 
-			this.controller.views.set( this.selector, view );
-			this._view = view;
-		},
-
-		empty: function() {
-			this.view( new media.View() );
+			// Trigger `region:action` event.
+			args[0] = base;
+			this.view.trigger.apply( this.view, args );
+			return this;
 		}
 	});
 
@@ -208,31 +214,86 @@
 	// wp.media.controller.State
 	// ---------------------------
 	media.controller.State = Backbone.Model.extend({
-		initialize: function() {
-			this.on( 'activate', this._activate, this );
+		constructor: function() {
+			this.on( 'activate', this._preActivate, this );
 			this.on( 'activate', this.activate, this );
+			this.on( 'activate', this._postActivate, this );
 			this.on( 'deactivate', this._deactivate, this );
 			this.on( 'deactivate', this.deactivate, this );
 			this.on( 'reset', this.reset, this );
+			this.on( 'ready', this._ready, this );
+			this.on( 'ready', this.ready, this );
+
+			this.on( 'change:menu', this._updateMenu, this );
+
+			Backbone.Model.apply( this, arguments );
 		},
 
+		ready: function() {},
 		activate: function() {},
-		_activate: function() {
+		deactivate: function() {},
+		reset: function() {},
+
+		_ready: function() {
+			this._updateMenu();
+		},
+
+		_preActivate: function() {
 			this.active = true;
+		},
 
-			this.menu();
-			this.toolbar();
-			this.content();
+		_postActivate: function() {
+			this.on( 'change:menu', this._menu, this );
+			this.on( 'change:titleMode', this._title, this );
+			this.on( 'change:content', this._content, this );
+			this.on( 'change:toolbar', this._toolbar, this );
+
+			this.frame.on( 'title:render:default', this._renderTitle, this );
+
+			this._title();
+			this._menu();
+			this._toolbar();
+			this._content();
+			this._router();
 		},
 
-		deactivate: function() {},
+
 		_deactivate: function() {
 			this.active = false;
+
+			this.frame.off( 'title:render:default', this._renderTitle, this );
+
+			this.off( 'change:menu', this._menu, this );
+			this.off( 'change:titleMode', this._title, this );
+			this.off( 'change:content', this._content, this );
+			this.off( 'change:toolbar', this._toolbar, this );
 		},
 
-		reset: function() {},
+		_title: function() {
+			this.frame.title.render( this.get('titleMode') || 'default' );
+		},
 
-		menu: function() {
+		_renderTitle: function( view ) {
+			view.$el.text( this.get('title') || '' );
+		},
+
+		_router: function() {
+			var router = this.frame.router,
+				mode = this.get('router'),
+				view;
+
+			this.frame.$el.toggleClass( 'hide-router', ! mode );
+			if ( ! mode )
+				return;
+
+			this.frame.router.render( mode );
+
+			view = router.get();
+			if ( view.select )
+				view.select( this.frame.content.mode() );
+		},
+
+		_menu: function() {
 			var menu = this.frame.menu,
 				mode = this.get('menu'),
 				view;
@@ -240,20 +301,48 @@
 			if ( ! mode )
 				return;
 
-			if ( menu.mode() !== mode )
-				menu.mode( mode );
+			menu.mode( mode );
 
-			view = menu.view();
+			view = menu.get();
 			if ( view.select )
 				view.select( this.id );
+		},
+
+		_updateMenu: function() {
+			var previous = this.previous('menu'),
+				menu = this.get('menu');
+
+			if ( previous )
+				this.frame.off( 'menu:render:' + previous, this._renderMenu, this );
+
+			if ( menu )
+				this.frame.on( 'menu:render:' + menu, this._renderMenu, this );
+		},
+
+		_renderMenu: function( view ) {
+			var menuItem = this.get('menuItem'),
+				title = this.get('title'),
+				priority = this.get('priority');
+
+			if ( ! menuItem && title ) {
+				menuItem = { text: title };
+
+				if ( priority )
+					menuItem.priority = priority;
+			}
+
+			if ( ! menuItem )
+				return;
+
+			view.set( this.id, menuItem );
 		}
 	});
 
 	_.each(['toolbar','content'], function( region ) {
-		media.controller.State.prototype[ region ] = function() {
+		media.controller.State.prototype[ '_' + region ] = function() {
 			var mode = this.get( region );
 			if ( mode )
-				this.frame[ region ].mode( mode );
+				this.frame[ region ].render( mode );
 		};
 	});
 
@@ -262,15 +351,22 @@
 	media.controller.Library = media.controller.State.extend({
 		defaults: {
 			id:         'library',
-			multiple:   false,
+			multiple:   false, // false, 'add', 'reset'
 			describe:   false,
-			toolbar:    'main-attachments',
+			toolbar:    'select',
 			sidebar:    'settings',
-			content:    'browse',
+			content:    'upload',
+			router:     'browse',
 			searchable: true,
 			filterable: false,
-			uploads:    true,
-			sortable:   true
+			sortable:   true,
+			title:      l10n.mediaLibraryTitle,
+
+			// Uses a user setting to override the content mode.
+			contentUserSetting: true,
+
+			// Sync the selection from the last state when 'multiple' matches.
+			syncLastSelection: true
 		},
 
 		initialize: function() {
@@ -290,31 +386,36 @@
 				this.set( 'gutter', 8 );
 
 			this.resetDisplays();
-
-			media.controller.State.prototype.initialize.apply( this, arguments );
 		},
 
 		activate: function() {
 			var library = this.get('library'),
 				selection = this.get('selection');
 
+			if ( this.get('syncLastSelection') ) {
+				this.getLastSelection();
+			}
+
 			this._excludeStateLibrary();
 			this.buildComposite();
 			this.on( 'change:library change:exclude', this.buildComposite, this );
 			this.on( 'change:excludeState', this._excludeState, this );
 
-			// If we're in a workflow that supports multiple attachments,
-			// automatically select any uploading attachments.
-			if ( this.get('multiple') )
-				wp.Uploader.queue.on( 'add', this.selectUpload, this );
+			wp.Uploader.queue.on( 'add', this.uploading, this );
 
 			selection.on( 'add remove reset', this.refreshSelection, this );
 
-			this.refresh();
 			this.on( 'insert', this._insertDisplaySettings, this );
+
+			if ( this.get('contentUserSetting') ) {
+				this.frame.on( 'content:activate', this.saveContentMode, this );
+				this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) );
+			}
 		},
 
 		deactivate: function() {
+			this.frame.off( 'content:activate', this.saveContentMode, this );
+
 			// Unbind all event handlers that use this state as the context
 			// from the selection.
 			this.get('selection').off( null, null, this );
@@ -332,11 +433,6 @@
 			this.resetDisplays();
 		},
 
-		refresh: function() {
-			this.content();
-			this.refreshSelection();
-		},
-
 		resetDisplays: function() {
 			this._displays = [];
 			this._defaultDisplaySettings = {
@@ -371,21 +467,59 @@
 			setUserSetting( 'urlbutton', display.link );
 		},
 
+		getLastSelection: function() {
+			var selection = this.get('selection'),
+				lastState = this.frame.lastState(),
+				lastSelection = lastState && lastState.get('selection'),
+				lastMultiple, thisMultiple;
+
+			if ( ! lastSelection )
+				return;
+
+			// We don't care about the method of multiple selection the
+			// selections use, just that they both support (or don't support)
+			// multiple selection.
+			lastMultiple = !! lastSelection.multiple;
+			thisMultiple = !! selection.multiple;
+
+			if ( lastMultiple !== thisMultiple )
+				return;
+
+			selection.reset( lastSelection.toArray() ).single( lastSelection.single() );
+		},
+
 		refreshSelection: function() {
 			var selection = this.get('selection'),
 				mode = this.frame.content.mode();
 
-			this.frame.toolbar.view().refresh();
+			this.frame.toolbar.get().refresh();
 			this.trigger( 'refresh:selection', this, selection );
 
 			if ( ! selection.length && 'browse' !== mode && 'upload' !== mode )
-				this.content();
+				this.frame.content.render();
 		},
 
-		selectUpload: function( attachment ) {
-			this.get('selection').add( attachment );
+		uploading: function( attachment ) {
+			var content = this.frame.content;
+
+			// If the uploader was selected, navigate to the browser.
+			if ( 'upload' === content.mode() )
+				this.frame.content.mode('browse');
+
+			// If we're in a workflow that supports multiple attachments,
+			// automatically select any uploading attachments.
+			if ( this.get('multiple') )
+				this.get('selection').add( attachment );
 		},
 
+		saveContentMode: function() {
+			// Only track the browse router on library states.
+			if ( 'browse' !== this.get('router') )
+				return;
+
+			setUserSetting( 'libraryContent', this.frame.content.mode() );
+		},
+
 		buildComposite: function() {
 			var original = this.get('_library'),
 				exclude = this.get('exclude'),
@@ -448,45 +582,9 @@
 		}
 	});
 
-
-	// wp.media.controller.Upload
-	// ---------------------------
-	media.controller.Upload = media.controller.State.extend({
-		defaults: _.defaults({
-			id:      'upload',
-			content: 'upload',
-			toolbar: 'empty',
-			uploads: true,
-
-			// The state to navigate to when files are uploading.
-			libraryState: 'library'
-		}, media.controller.State.prototype.defaults ),
-
-		initialize: function() {
-			media.controller.State.prototype.initialize.apply( this, arguments );
-		},
-
-		activate: function() {
-			wp.Uploader.queue.on( 'add', this.uploading, this );
-			media.controller.State.prototype.activate.apply( this, arguments );
-		},
-
-		deactivate: function() {
-			wp.Uploader.queue.off( null, null, this );
-			media.controller.State.prototype.deactivate.apply( this, arguments );
-		},
-
-		uploading: function( attachment ) {
-			var library = this.get('libraryState');
-
-			this.frame.state( library ).get('selection').add( attachment );
-			this.frame.setState( library );
-		}
-	});
-
-	// wp.media.controller.Gallery
-	// ---------------------------
-	media.controller.Gallery = media.controller.Library.extend({
+	// wp.media.controller.GalleryEdit
+	// -------------------------------
+	media.controller.GalleryEdit = media.controller.Library.extend({
 		defaults: {
 			id:         'gallery-edit',
 			multiple:   false,
@@ -496,7 +594,9 @@
 			sortable:   true,
 			searchable: false,
 			toolbar:    'gallery-edit',
-			content:    'browse'
+			content:    'browse',
+			title:      l10n.editGalleryTitle,
+			priority:   60
 		},
 
 		initialize: function() {
@@ -519,7 +619,7 @@
 			// Watch for uploaded attachments.
 			this.get('library').observe( wp.Uploader.queue );
 
-			this.frame.content.on( 'activate:browse', this.gallerySettings, this );
+			this.frame.on( 'content:render:browse', this.gallerySettings, this );
 
 			media.controller.Library.prototype.activate.apply( this, arguments );
 		},
@@ -528,21 +628,19 @@
 			// Stop watching for uploaded attachments.
 			this.get('library').unobserve( wp.Uploader.queue );
 
-			this.frame.content.off( null, null, this );
+			this.frame.off( 'content:render:browse', this.gallerySettings, this );
+
 			media.controller.Library.prototype.deactivate.apply( this, arguments );
 		},
 
-		gallerySettings: function() {
-			var library = this.get('library'),
-				browser;
+		gallerySettings: function( browser ) {
+			var library = this.get('library');
 
-			if ( ! library )
+			if ( ! library || ! browser )
 				return;
 
 			library.gallery = library.gallery || new Backbone.Model();
 
-			browser = this.frame.content.view();
-
 			browser.sidebar.set({
 				gallery: new media.view.Settings.Gallery({
 					controller: this,
@@ -570,7 +668,9 @@
 			filterable: 'uploaded',
 			multiple:   false,
 			menu:       'main',
-			toolbar:    'featured-image'
+			toolbar:    'featured-image',
+			title:      l10n.featuredImageTitle,
+			priority:   60
 		}, media.controller.Library.prototype.defaults ),
 
 		initialize: function() {
@@ -629,7 +729,10 @@
 			menu:    'main',
 			content: 'embed',
 			toolbar: 'main-embed',
-			type:    'link'
+			type:    'link',
+
+			title:    l10n.fromUrlTitle,
+			priority: 120
 		},
 
 		// The amount of time used when debouncing the scan.
@@ -637,9 +740,9 @@
 
 		initialize: function() {
 			this.debouncedScan = _.debounce( _.bind( this.scan, this ), this.sensitivity );
-			this.on( 'change:url', this.debouncedScan, this );
+			this.props = new Backbone.Model({ url: '' });
+			this.props.on( 'change:url', this.debouncedScan, this );
 			this.on( 'scan', this.scanImage, this );
-			media.controller.State.prototype.initialize.apply( this, arguments );
 		},
 
 		scan: function() {
@@ -652,11 +755,11 @@
 		scanImage: function( attributes ) {
 			var frame = this.frame,
 				state = this,
-				url = this.get('url'),
+				url = this.props.get('url'),
 				image = new Image();
 
 			image.onload = function() {
-				if ( state !== frame.state() || url !== state.get('url') )
+				if ( state !== frame.state() || url !== state.props.get('url') )
 					return;
 
 				state.set({
@@ -670,14 +773,10 @@
 		},
 
 		reset: function() {
-			_.each( _.difference( _.keys( this.attributes ), _.keys( this.defaults ) ), function( key ) {
-				this.unset( key );
-			}, this );
+			this.props = new Backbone.Model({ url: '' });
 
-			this.set( 'url', '' );
-
 			if ( this.id === this.frame.state().id )
-				this.frame.toolbar.view().refresh();
+				this.frame.toolbar.get().refresh();
 		}
 	});
 
@@ -1022,9 +1121,13 @@
 		// The constructor for the `Views` manager.
 		Views: media.Views,
 
-		constructor: function() {
+		constructor: function( options ) {
 			this.views = new this.Views( this, this.views );
 			this.on( 'ready', this.ready, this );
+
+			if ( options && options.controller )
+				this.controller = options.controller;
+
 			Backbone.View.apply( this, arguments );
 		},
 
@@ -1097,9 +1200,9 @@
 			// Initialize regions.
 			_.each( this.regions, function( region ) {
 				this[ region ] = new media.controller.Region({
-					controller: this,
-					id:         region,
-					selector:   '.media-frame-' + region
+					view:     this,
+					id:       region,
+					selector: '.media-frame-' + region
 				});
 			}, this );
 		},
@@ -1113,6 +1216,7 @@
 			// Ensure states have a reference to the frame.
 			this.states.on( 'add', function( model ) {
 				model.frame = this;
+				model.trigger('ready');
 			}, this );
 		},
 
@@ -1131,7 +1235,7 @@
 	media.view.MediaFrame = media.view.Frame.extend({
 		className: 'media-frame',
 		template:  media.template('media-frame'),
-		regions:   ['menu','content','toolbar'],
+		regions:   ['menu','title','content','toolbar','router'],
 
 		initialize: function() {
 			media.view.Frame.prototype.initialize.apply( this, arguments );
@@ -1173,6 +1277,10 @@
 			}
 
 			this.on( 'attach', _.bind( this.views.ready, this.views ), this );
+
+			// Bind default title creation.
+			this.on( 'title:create:default', this.createTitle, this );
+			this.title.mode('default');
 		},
 
 		render: function() {
@@ -1183,6 +1291,31 @@
 			return media.view.Frame.prototype.render.apply( this, arguments );
 		},
 
+		createTitle: function( title ) {
+			title.view = new media.View({
+				controller: this,
+				tagName: 'h1'
+			});
+		},
+
+		createMenu: function( menu ) {
+			menu.view = new media.view.Menu({
+				controller: this
+			});
+		},
+
+		createToolbar: function( toolbar ) {
+			menu.view = new media.view.Toolbar({
+				controller: this
+			});
+		},
+
+		createRouter: function( router ) {
+			router.view = new media.view.Router({
+				controller: this
+			});
+		},
+
 		createIframeStates: function( options ) {
 			var settings = media.view.settings,
 				tabs = settings.tabs,
@@ -1208,22 +1341,25 @@
 				}, options ) );
 			}, this );
 
-			this.content.on( 'activate:iframe', this.iframeContent, this );
-			this.menu.on( 'activate:main', this.iframeMenu, this );
+			this.on( 'content:create:iframe', this.iframeContent, this );
+			this.on( 'menu:render:main', this.iframeMenu, this );
 			this.on( 'open', this.hijackThickbox, this );
 			this.on( 'close', this.restoreThickbox, this );
 		},
 
-		iframeContent: function() {
+		iframeContent: function( content ) {
 			this.$el.addClass('hide-toolbar');
-			this.content.view( new media.view.Iframe({
+			content.view = new media.view.Iframe({
 				controller: this
-			}).render() );
+			});
 		},
 
-		iframeMenu: function() {
+		iframeMenu: function( view ) {
 			var views = {};
 
+			if ( ! view )
+				return;
+
 			_.each( media.view.settings.tabs, function( title, id ) {
 				views[ 'iframe:' + id ] = {
 					text: this.state( 'iframe:' + id ).get('title'),
@@ -1231,7 +1367,7 @@
 				};
 			}, this );
 
-			this.menu.view().set( views );
+			view.set( views );
 		},
 
 		hijackThickbox: function() {
@@ -1305,83 +1441,76 @@
 				new media.controller.Library({
 					selection: options.selection,
 					library:   media.query( options.library ),
-					multiple:  this.options.multiple,
+					multiple:  options.multiple,
 					menu:      'main',
-					toolbar:   'select'
-				}),
-
-				new media.controller.Upload({
-					menu: 'main'
+					title:     options.title,
+					priority:  20
 				})
 			]);
 		},
 
 		bindHandlers: function() {
-			this.menu.on( 'activate:main', this.mainMenu, this );
-			this.content.on( 'activate:browse', this.browseContent, this );
-			this.content.on( 'activate:upload', this.uploadContent, this );
-			this.toolbar.on( 'activate:select', this.selectToolbar, this );
+			this.on( 'menu:create:main', this.createMenu, this );
+			this.on( 'router:create:browse', this.createRouter, this );
+			this.on( 'router:render:browse', this.browseRouter, this );
+			this.on( 'content:create:browse', this.browseContent, this );
+			this.on( 'content:render:upload', this.uploadContent, this );
+			this.on( 'toolbar:create:select', this.createSelectToolbar, this );
 
 			this.on( 'refresh:selection', this.refreshSelectToolbar, this );
 		},
 
-		mainMenu: function( options ) {
-			this.menu.view( new media.view.Menu({
-				controller: this,
-				silent:     options && options.silent,
-
-				views: {
-					upload: {
-						text: l10n.uploadFilesTitle,
-						priority: 20
-					},
-					library: {
-						text: l10n.mediaLibraryTitle,
-						priority: 40
-					}
+		// Routers
+		browseRouter: function( view ) {
+			view.set({
+				upload: {
+					text:     l10n.uploadFilesTitle,
+					priority: 20
+				},
+				browse: {
+					text:     l10n.mediaLibraryTitle,
+					priority: 40
 				}
-			}) );
+			});
 		},
 
 		// Content
-		browseContent: function() {
+		browseContent: function( content ) {
 			var state = this.state();
 
 			this.$el.removeClass('hide-toolbar');
 
 			// Browse our library of attachments.
-			this.content.view( new media.view.AttachmentsBrowser({
+			content.view = new media.view.AttachmentsBrowser({
 				controller: this,
 				collection: state.get('library'),
 				selection:  state.get('selection'),
 				model:      state,
 				sortable:   state.get('sortable'),
 				search:     state.get('searchable'),
-				uploads:    state.get('uploads'),
 				filters:    state.get('filterable'),
 				display:    state.get('displaySettings'),
 
 				AttachmentView: state.get('AttachmentView')
-			}) );
+			});
 		},
 
 		uploadContent: function() {
-			this.$el.addClass('hide-toolbar');
-
-			this.content.view( new media.view.UploaderInline({
+			this.$el.removeClass('hide-toolbar');
+			this.content.set( new media.view.UploaderInline({
 				controller: this
 			}) );
 		},
 
 		// Toolbars
-		selectToolbar: function( options ) {
+		createSelectToolbar: function( toolbar, options ) {
 			options = _.defaults( options || {}, {
 				event:  'select',
 				silent: false,
 				state:  false
 			});
 
-			this.toolbar.view( new media.view.Toolbar({
+			toolbar.view = new media.view.Toolbar({
 				controller: this,
 				silent:     options.silent,
 
@@ -1402,7 +1531,7 @@
 						}
 					}
 				}
-			}) );
+			});
 		},
 
 		refreshSelectToolbar: function() {
@@ -1411,7 +1540,7 @@
 			if ( ! selection || 'select' !== this.toolbar.mode() )
 				return;
 
-			this.toolbar.view().get('select').model.set( 'disabled', ! selection.length );
+			this.toolbar.get().get('select').model.set( 'disabled', ! selection.length );
 		}
 	});
 
@@ -1430,35 +1559,55 @@
 		},
 
 		createStates: function() {
-			var options = this.options;
+			var options = this.options,
+				selection = options.selection,
+				library = {
+					editable: true,
+					menu:     'main',
 
-			// Add the default states.
-			this.states.add([
-				// Main states.
-				new media.controller.Library({
-					selection:  options.selection,
-					library:    media.query( options.library ),
-					editable:   true,
-					filterable: 'all',
-					multiple:   this.options.multiple,
-					menu:       'main',
-
 					// Show the attachment display settings.
 					displaySettings: true,
 					// Update user settings when users adjust the
 					// attachment display settings.
 					displayUserSettings: true
-				}),
+				};
 
-				new media.controller.Upload({
-					menu: 'main'
-				}),
+			// Add the default states.
+			this.states.add([
+				// Main states.
+				new media.controller.Library( _.defaults({
+					id:         'insert',
+					title:      l10n.insertMediaTitle,
+					priority:   20,
+					toolbar:    'main-insert',
+					filterable: 'all',
+					library:    media.query( options.library ),
+					selection:  selection,
+					multiple:   options.multiple ? 'reset' : false
+				}, library ) ),
 
+				new media.controller.Library( _.defaults({
+					id:         'gallery',
+					title:      l10n.createGalleryTitle,
+					priority:   40,
+					toolbar:    'main-gallery',
+					filterable: 'uploaded',
+					multiple:   'add',
+
+					library:  media.query( _.defaults({
+						type: 'image'
+					}, options.library ) ),
+
+					selection: new media.model.Selection( selection.models, {
+						multiple: 'add'
+					})
+				}, library ) ),
+
 				// Embed states.
 				new media.controller.Embed(),
 
 				// Gallery states.
-				new media.controller.Gallery({
+				new media.controller.GalleryEdit({
 					library: options.selection,
 					editing: options.editing,
 					menu:    'gallery'
@@ -1468,16 +1617,12 @@
 					id:           'gallery-library',
 					library:      media.query({ type: 'image' }),
 					filterable:   'uploaded',
-					multiple:     true,
+					multiple:     'add',
 					menu:         'gallery',
 					toolbar:      'gallery-add',
-					excludeState: 'gallery-edit'
-				}),
-
-				new media.controller.Upload({
-					id:           'gallery-upload',
-					menu:         'gallery',
-					libraryState: 'gallery-edit'
+					excludeState: 'gallery-edit',
+					title:        l10n.addToGalleryTitle,
+					priority:     100
 				})
 			]);
 
@@ -1492,9 +1637,13 @@
 
 		bindHandlers: function() {
 			media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
+			this.on( 'menu:create:gallery', this.createMenu, this );
+			this.on( 'toolbar:create:main-insert', this.createSelectionToolbar, this );
+			this.on( 'toolbar:create:main-gallery', this.createSelectionToolbar, this );
 
 			var handlers = {
 					menu: {
+						'main':    'mainMenu',
 						'gallery': 'galleryMenu'
 					},
 
@@ -1504,7 +1653,8 @@
 					},
 
 					toolbar: {
-						'main-attachments': 'mainAttachmentsToolbar',
+						'main-insert':      'mainInsertToolbar',
+						'main-gallery':     'mainGalleryToolbar',
 						'main-embed':       'mainEmbedToolbar',
 						'featured-image':   'featuredImageToolbar',
 						'gallery-edit':     'galleryEditToolbar',
@@ -1514,70 +1664,42 @@
 
 			_.each( handlers, function( regionHandlers, region ) {
 				_.each( regionHandlers, function( callback, handler ) {
-					this[ region ].on( 'activate:' + handler, this[ callback ], this );
+					this.on( region + ':render:' + handler, this[ callback ], this );
 				}, this );
 			}, this );
 		},
 
 		// Menus
-		mainMenu: function() {
-			media.view.MediaFrame.Select.prototype.mainMenu.call( this, { silent: true });
-
-			this.menu.view().set({
+		mainMenu: function( view ) {
+			view.set({
 				'library-separator': new media.View({
 					className: 'separator',
-					priority: 60
-				}),
-				'embed': {
-					text: l10n.fromUrlTitle,
-					priority: 80
-				}
+					priority: 100
+				})
 			});
-
-			if ( media.view.settings.post.featuredImageId ) {
-				this.menu.view().set( 'featured-image', {
-					text: l10n.featuredImageTitle,
-					priority: 100
-				});
-			}
 		},
 
-		galleryMenu: function() {
+		galleryMenu: function( view ) {
 			var lastState = this.lastState(),
 				previous = lastState && lastState.id,
 				frame = this;
 
-			this.menu.view( new media.view.Menu({
-				controller: this,
-				views: {
-					cancel: {
-						text:     l10n.cancelGalleryTitle,
-						priority: 20,
-						click:    function() {
-							if ( previous )
-								frame.setState( previous );
-							else
-								frame.close();
-						}
-					},
-					separateCancel: new media.View({
-						className: 'separator',
-						priority: 40
-					}),
-					'gallery-edit': {
-						text: l10n.editGalleryTitle,
-						priority: 60
-					},
-					'gallery-upload': {
-						text: l10n.uploadImagesTitle,
-						priority: 80
-					},
-					'gallery-library': {
-						text: l10n.mediaLibraryTitle,
-						priority: 100
+			view.set({
+				cancel: {
+					text:     l10n.cancelGalleryTitle,
+					priority: 20,
+					click:    function() {
+						if ( previous )
+							frame.setState( previous );
+						else
+							frame.close();
 					}
-				}
-			}) );
+				},
+				separateCancel: new media.View({
+					className: 'separator',
+					priority: 40
+				})
+			});
 		},
 
 		// Content
@@ -1587,7 +1709,7 @@
 				model:      this.state()
 			}).render();
 
-			this.content.view( view );
+			this.content.set( view );
 			view.url.focus();
 		},
 
@@ -1617,37 +1739,62 @@
 			});
 
 			// Browse our library of attachments.
-			this.content.view( view );
+			this.content.set( view );
 		},
 
-		// Sidebars
-		onSidebarGallerySettings: function( options ) {
-			var library = this.state().get('library');
+		// Toolbars
+		createSelectionToolbar: function( toolbar ) {
+			toolbar.view = new media.view.Toolbar.Selection({
+				controller: this,
+				editable:   this.state().get('editable')
+			});
+		},
 
-			if ( ! library )
-				return;
+		mainInsertToolbar: function( view ) {
+			var controller = this;
 
-			library.gallery = library.gallery || new Backbone.Model();
+			view.button = 'insert';
+			view.set( 'insert', {
+				style:    'primary',
+				priority: 80,
+				text:     l10n.insertIntoPost,
 
-			this.sidebar.view().set({
-				gallery: new media.view.Settings.Gallery({
-					controller: this,
-					model:      library.gallery,
-					priority:   40
-				}).render()
-			}, options );
+				click: function() {
+					var state = controller.state(),
+						selection = state.get('selection');
+
+					controller.close();
+					state.trigger( 'insert', selection ).reset();
+				}
+			});
 		},
 
-		// Toolbars
-		mainAttachmentsToolbar: function() {
-			this.toolbar.view( new media.view.Toolbar.Insert({
-				controller: this,
-				editable:   this.state().get('editable')
-			}) );
+		mainGalleryToolbar: function( view ) {
+			var controller = this;
+
+			view.button = 'gallery';
+			view.set( 'gallery', {
+				style:    'primary',
+				text:     l10n.createNewGallery,
+				priority: 60,
+
+				click: function() {
+					var selection = controller.state().get('selection'),
+						edit = controller.state('gallery-edit'),
+						models = selection.where({ type: 'image' });
+
+					edit.set( 'library', new media.model.Selection( models, {
+						props:    selection.props.toJSON(),
+						multiple: true
+					}) );
+
+					this.controller.setState('gallery-edit');
+				}
+			});
 		},
 
 		featuredImageToolbar: function() {
-			this.toolbar.view( new media.view.Toolbar.Select({
+			this.toolbar.set( new media.view.Toolbar.Select({
 				controller: this,
 				text:       l10n.setFeaturedImage,
 				state:      this.options.state || 'upload'
@@ -1655,7 +1802,7 @@
 		},
 
 		mainEmbedToolbar: function() {
-			this.toolbar.view( new media.view.Toolbar.Embed({
+			this.toolbar.set( new media.view.Toolbar.Embed({
 				controller: this
 			}) );
 
@@ -1664,7 +1811,7 @@
 
 		galleryEditToolbar: function() {
 			var editing = this.state().get('editing');
-			this.toolbar.view( new media.view.Toolbar({
+			this.toolbar.set( new media.view.Toolbar({
 				controller: this,
 				items: {
 					insert: {
@@ -1689,7 +1836,7 @@
 		},
 
 		galleryAddToolbar: function() {
-			this.toolbar.view( new media.view.Toolbar({
+			this.toolbar.set( new media.view.Toolbar({
 				controller: this,
 				items: {
 					insert: {
@@ -1704,7 +1851,7 @@
 
 							edit.get('library').add( state.get('selection').models );
 							state.trigger('reset');
-							controller.state('gallery-edit');
+							controller.setState('gallery-edit');
 						}
 					}
 				}
@@ -1729,8 +1876,6 @@
 		},
 
 		initialize: function() {
-			this.controller = this.options.controller;
-
 			_.defaults( this.options, {
 				container: document.body,
 				title:     '',
@@ -1838,8 +1983,6 @@
 		initialize: function() {
 			var uploader;
 
-			this.controller = this.options.controller;
-
 			this.$browser = $('<a href="#" class="browser" />').hide().appendTo('body');
 
 			uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
@@ -1906,7 +2049,10 @@
 		template:  media.template('uploader-inline'),
 
 		initialize: function() {
-			this.controller = this.options.controller;
+			_.defaults( this.options, {
+				message: '',
+				status:  true
+			});
 
 			if ( ! this.options.$browser && this.controller.uploader )
 				this.options.$browser = this.controller.uploader.$browser;
@@ -1914,9 +2060,11 @@
 			if ( _.isUndefined( this.options.postId ) )
 				this.options.postId = media.view.settings.post.id;
 
-			this.views.set( '.upload-inline-status', new media.view.UploaderStatus({
-				controller: this.controller
-			}) );
+			if ( this.options.status ) {
+				this.views.set( '.upload-inline-status', new media.view.UploaderStatus({
+					controller: this.controller
+				}) );
+			}
 		},
 
 		ready: function() {
@@ -1951,8 +2099,6 @@
 		},
 
 		initialize: function() {
-			this.controller = this.options.controller;
-
 			this.queue = wp.Uploader.queue;
 			this.queue.on( 'add remove reset', this.visibility, this );
 			this.queue.on( 'add remove reset change:percent', this.progress, this );
@@ -2060,8 +2206,6 @@
 		className: 'media-toolbar',
 
 		initialize: function() {
-			this.controller = this.options.controller;
-
 			this._views     = {};
 			this.$primary   = $('<div class="media-toolbar-primary" />').prependTo( this.$el );
 			this.$secondary = $('<div class="media-toolbar-secondary" />').prependTo( this.$el );
@@ -2199,50 +2343,32 @@
 	// ---------------------------
 	media.view.Toolbar.Embed = media.view.Toolbar.Select.extend({
 		initialize: function() {
-			var controller = this.options.controller;
-
 			_.defaults( this.options, {
 				text: l10n.insertIntoPost
 			});
 
 			media.view.Toolbar.Select.prototype.initialize.apply( this, arguments );
-			controller.on( 'change:url', this.refresh, this );
+			this.controller.state().props.on( 'change:url', this.refresh, this );
 		},
 
 		refresh: function() {
-			var url = this.controller.state().get('url');
+			var url = this.controller.state().props.get('url');
 			this.get('select').model.set( 'disabled', ! url || /^https?:\/\/$/.test(url) );
 		}
 	});
 
-	// wp.media.view.Toolbar.Insert
-	// ----------------------------
-	media.view.Toolbar.Insert = media.view.Toolbar.extend({
+	// wp.media.view.Toolbar.Selection
+	// -------------------------------
+	media.view.Toolbar.Selection = media.view.Toolbar.extend({
+		button: 'insert',
+
 		initialize: function() {
-			var controller = this.options.controller,
-				selection = controller.state().get('selection'),
-				selectionToLibrary;
+			var controller = this.controller;
 
-			selectionToLibrary = function( state, filter ) {
-				return function() {
-					var controller = this.controller,
-						selection = controller.state().get('selection'),
-						edit = controller.state( state ),
-						models = filter ? filter( selection ) : selection.models;
-
-					edit.set( 'library', new media.model.Selection( models, {
-						props:    selection.props.toJSON(),
-						multiple: true
-					}) );
-
-					this.controller.setState( state );
-				};
-			};
-
 			this.options.items = _.defaults( this.options.items || {}, {
 				selection: new media.view.Selection({
 					controller: controller,
-					collection: selection,
+					collection: controller.state().get('selection'),
 					priority:   -40,
 
 					// If the selection is editable, pass the callback to
@@ -2250,26 +2376,7 @@
 					editable: this.options.editable && function() {
 						this.controller.content.mode('edit-selection');
 					}
-				}).render(),
-
-				insert: {
-					style:    'primary',
-					priority: 80,
-					text:     l10n.insertIntoPost,
-
-					click: function() {
-						controller.close();
-						controller.state().trigger( 'insert', selection ).reset();
-					}
-				},
-
-				gallery: {
-					text:     l10n.createNewGallery,
-					priority: 40,
-					click:    selectionToLibrary('gallery-edit', function( selection ) {
-						return selection.where({ type: 'image' });
-					})
-				}
+				}).render()
 			});
 
 			media.view.Toolbar.prototype.initialize.apply( this, arguments );
@@ -2277,14 +2384,12 @@
 
 		refresh: function() {
 			var selection = this.controller.state().get('selection'),
-				count = selection.length;
+				button = this.get( this.button );
 
-			this.get('insert').model.set( 'disabled', ! selection.length );
+			if ( ! button )
+				return;
 
-			// Check if any attachment in the selection is an image.
-			this.get('gallery').$el.toggle( count > 1 && selection.any( function( attachment ) {
-				return 'image' === attachment.get('type');
-			}) );
+			button.model.set( 'disabled', ! selection.length );
 		}
 	});
 
@@ -2388,8 +2493,7 @@
 		tagName:   'div',
 
 		initialize: function() {
-			this.controller = this.options.controller;
-			this._views     = {};
+			this._views = {};
 
 			this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
 			delete this.options.views;
@@ -2457,23 +2561,94 @@
 		}
 	});
 
+	/**
+	 * wp.media.view.MenuItem
+	 */
+	media.view.MenuItem = media.View.extend({
+		tagName:   'a',
+		className: 'media-menu-item',
 
+		attributes: {
+			href: '#'
+		},
+
+		events: {
+			'click': '_click'
+		},
+
+		_click: function( event ) {
+			var clickOverride = this.options.click;
+
+			event.preventDefault();
+
+			if ( clickOverride )
+				clickOverride.call( this );
+			else
+				this.click();
+		},
+
+		click: function() {
+			var state = this.options.state;
+			if ( state )
+				this.controller.setState( state );
+		},
+
+		render: function() {
+			var options = this.options;
+
+			if ( options.text )
+				this.$el.text( options.text );
+			else if ( options.html )
+				this.$el.html( options.html );
+
+			return this;
+		}
+	});
+
 	/**
 	 * wp.media.view.Menu
 	 */
 	media.view.Menu = media.view.PriorityList.extend({
-		tagName:   'ul',
+		tagName:   'div',
 		className: 'media-menu',
+		property:  'state',
+		ItemView:  media.view.MenuItem,
+		region:    'menu',
 
-		toView: function( options, state ) {
+		toView: function( options, id ) {
 			options = options || {};
-			options.state = options.state || state;
-			return new media.view.MenuItem( options ).render();
+			options[ this.property ] = options[ this.property ] || id;
+			return new this.ItemView( options ).render();
 		},
 
-		select: function( state ) {
-			var view = this.get( state );
+		ready: function() {
+			media.view.PriorityList.prototype.ready.apply( this, arguments );
+			this.visibility();
+		},
 
+		set: function() {
+			media.view.PriorityList.prototype.set.apply( this, arguments );
+			this.visibility();
+		},
+
+		unset: function() {
+			media.view.PriorityList.prototype.unset.apply( this, arguments );
+			this.visibility();
+		},
+
+		visibility: function() {
+			var region = this.region,
+				view = this.controller[ region ].get(),
+				views = this.views.get(),
+				hide = ! views || views.length < 2;
+
+			if ( this === view )
+				this.controller.$el.toggleClass( 'hide-' + region, hide );
+		},
+
+		select: function( id ) {
+			var view = this.get( id );
+
 			if ( ! view )
 				return;
 
@@ -2486,35 +2661,40 @@
 		}
 	});
 
-	media.view.MenuItem = media.View.extend({
-		tagName:   'li',
-		className: 'media-menu-item',
+	/**
+	 * wp.media.view.RouterItem
+	 */
+	media.view.RouterItem = media.view.MenuItem.extend({
+		click: function() {
+			var contentMode = this.options.contentMode;
+			if ( contentMode )
+				this.controller.content.mode( contentMode );
+		}
+	});
 
-		events: {
-			'click': 'click'
-		},
+	/**
+	 * wp.media.view.Router
+	 */
+	media.view.Router = media.view.Menu.extend({
+		tagName:   'div',
+		className: 'media-router',
+		property:  'contentMode',
+		ItemView:  media.view.RouterItem,
+		region:    'router',
 
-		click: function() {
-			var options = this.options;
-
-			if ( options.click )
-				options.click.call( this );
-			else if ( options.state )
-				this.controller.setState( options.state );
+		initialize: function() {
+			this.controller.on( 'content:render', this.update, this );
+			media.view.Menu.prototype.initialize.apply( this, arguments );
 		},
 
-		render: function() {
-			var options = this.options;
-
-			if ( options.text )
-				this.$el.text( options.text );
-			else if ( options.html )
-				this.$el.html( options.html );
-
-			return this;
+		update: function() {
+			var mode = this.controller.content.mode();
+			if ( mode )
+				this.select( mode );
 		}
 	});
 
+
 	/**
 	 * wp.media.view.Sidebar
 	 */
@@ -2531,7 +2711,7 @@
 		template:  media.template('attachment'),
 
 		events: {
-			'click .attachment-preview':      'toggleSelection',
+			'click .attachment-preview':      'toggleSelectionHandler',
 			'change [data-setting]':          'updateSetting',
 			'change [data-setting] input':    'updateSetting',
 			'change [data-setting] select':   'updateSetting',
@@ -2546,8 +2726,6 @@
 		initialize: function() {
 			var selection = this.options.selection;
 
-			this.controller = this.options.controller;
-
 			this.model.on( 'change:sizes change:uploading change:caption change:title', this.render, this );
 			this.model.on( 'change:percent', this.progress, this );
 
@@ -2623,20 +2801,70 @@
 				this.$bar.width( this.model.get('percent') + '%' );
 		},
 
-		toggleSelection: function( event ) {
-			var selection = this.options.selection,
-				model = this.model;
+		toggleSelectionHandler: function( event ) {
+			var method;
 
+			if ( event.shiftKey )
+				method = 'between';
+			else if ( event.ctrlKey || event.metaKey )
+				method = 'toggle';
+
+			this.toggleSelection({
+				method: method
+			});
+		},
+
+		toggleSelection: function( options ) {
+			var collection = this.collection,
+				selection = this.options.selection,
+				model = this.model,
+				method = options && options.method,
+				single, between, models, singleIndex, modelIndex;
+
 			if ( ! selection )
 				return;
 
+			single = selection.single();
+			method = _.isUndefined( method ) ? selection.multiple : method;
+
+			// If the `method` is set to `between`, select all models that
+			// exist between the current and the selected model.
+			if ( 'between' === method && single && selection.multiple ) {
+				// If the models are the same, short-circuit.
+				if ( single === model )
+					return;
+
+				singleIndex = collection.indexOf( single );
+				modelIndex  = collection.indexOf( this.model );
+
+				if ( singleIndex < modelIndex )
+					models = collection.models.slice( singleIndex, modelIndex + 1 );
+				else
+					models = collection.models.slice( modelIndex, singleIndex + 1 );
+
+				selection.add( models ).single( model );
+				return;
+
+			// If the `method` is set to `toggle`, just flip the selection
+			// status, regardless of whether the model is the single model.
+			} else if ( 'toggle' === method ) {
+				selection[ this.selected() ? 'remove' : 'add' ]( model ).single( model );
+				return;
+			}
+
+			if ( method !== 'add' )
+				method = 'reset';
+
 			if ( this.selected() ) {
 				// If the model is the single model, remove it.
 				// If it is not the same as the single model,
 				// it now becomes the single model.
-				selection[ selection.single() === model ? 'remove' : 'single' ]( model );
+				selection[ single === model ? 'remove' : 'single' ]( model );
 			} else {
-				selection.add( model ).single( model );
+				// If the model is not selected, run the `method` on the
+				// selection. By default, we `reset` the selection, but the
+				// `method` can be set to `add` the model to the selection.
+				selection[ method ]( model ).single( model );
 			}
 		},
 
@@ -2838,7 +3066,6 @@
 		},
 
 		initialize: function() {
-			this.controller = this.options.controller;
 			this.el.id = _.uniqueId('__attachments-view-');
 
 			_.defaults( this.options, {
@@ -3200,12 +3427,9 @@
 		className: 'attachments-browser',
 
 		initialize: function() {
-			this.controller = this.options.controller;
-
 			_.defaults( this.options, {
 				filters: false,
 				search:  true,
-				uploads: false,
 				display: false,
 
 				AttachmentView: media.view.Attachment.Library
@@ -3290,7 +3514,9 @@
 			this.removeContent();
 
 			this.uploader = new media.view.UploaderInline({
-				controller: this.controller
+				controller: this.controller,
+				status:     false,
+				message:    l10n.noItemsFound
 			});
 
 			this.views.add( this.uploader );
@@ -3322,7 +3548,7 @@
 
 			this.views.add( sidebar );
 
-			if ( options.uploads && this.controller.uploader ) {
+			if ( this.controller.uploader ) {
 				sidebar.set( 'uploads', new media.view.UploaderStatus({
 					controller: this.controller,
 					priority:   40
@@ -3373,57 +3599,6 @@
 	});
 
 	/**
-	 * wp.media.view.SelectionPreview
-	 */
-	media.view.SelectionPreview = media.View.extend({
-		tagName:   'div',
-		className: 'selection-preview',
-		template:  media.template('media-selection-preview'),
-
-		events: {
-			'click .clear-selection': 'clear'
-		},
-
-		initialize: function() {
-			_.defaults( this.options, {
-				clearable: true
-			});
-
-			this.controller = this.options.controller;
-			this.collection.on( 'add change:url remove', this.render, this );
-			this.render();
-		},
-
-		render: function() {
-			var options = _.clone( this.options ),
-				last, sizes, amount;
-
-			// If nothing is selected, display nothing.
-			if ( ! this.collection.length ) {
-				this.$el.empty();
-				return this;
-			}
-
-			options.count = this.collection.length;
-			last  = this.collection.last();
-			sizes = last.get('sizes');
-
-			if ( 'image' === last.get('type') )
-				options.thumbnail = ( sizes && sizes.thumbnail ) ? sizes.thumbnail.url : last.get('url');
-			else
-				options.thumbnail =  last.get('icon');
-
-			this.$el.html( this.template( options ) );
-			return this;
-		},
-
-		clear: function( event ) {
-			event.preventDefault();
-			this.collection.reset();
-		}
-	});
-
-	/**
 	 * wp.media.view.Selection
 	 */
 	media.view.Selection = media.View.extend({
@@ -3442,7 +3617,6 @@
 				clearable: true
 			});
 
-			this.controller = this.options.controller;
 			this.attachments = new media.view.Attachments({
 				controller: this.controller,
 				collection: this.collection,
@@ -3768,12 +3942,10 @@
 	media.view.Iframe = media.View.extend({
 		className: 'media-iframe',
 
-		initialize: function() {
-			this.controller = this.options.controller;
-		},
-
 		render: function() {
+			this.views.detach();
 			this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
+			this.views.render();
 			return this;
 		}
 	});
@@ -3785,11 +3957,9 @@
 		className: 'media-embed',
 
 		initialize: function() {
-			this.controller = this.options.controller;
-
 			this.url = new media.view.EmbedUrl({
 				controller: this.controller,
-				model:      this.model
+				model:      this.model.props
 			}).render();
 
 			this._settings = new media.View();
@@ -3826,7 +3996,7 @@
 
 			this.settings( new constructor({
 				controller: this.controller,
-				model:      this.model,
+				model:      this.model.props,
 				priority:   40
 			}) );
 		}
@@ -3846,15 +4016,13 @@
 		},
 
 		initialize: function() {
-			this.label = this.make( 'span', null, this.options.label || l10n.url );
 			this.input = this.make( 'input', {
 				type:  'text',
 				value: this.model.get('url') || ''
 			});
 
-			this.$label = $( this.label );
 			this.$input = $( this.input );
-			this.$el.append([ this.label, this.input ]);
+			this.$el.append( this.input );
 
 			this.model.on( 'change:url', this.render, this );
 		},
Index: wp-includes/media.php
===================================================================
--- wp-includes/media.php	(revision 23000)
+++ wp-includes/media.php	(working copy)
@@ -1467,9 +1467,11 @@
 
 		// Library
 		'mediaLibraryTitle'  => __( 'Media Library' ),
+		'insertMediaTitle'   => __( 'Insert Media' ),
 		'createNewGallery'   => __( 'Create a new gallery' ),
 		'returnToLibrary'    => __( '&#8592; Return to library' ),
 		'allMediaItems'      => __( 'All media items' ),
+		'noItemsFound'       => __( 'No items found.' ),
 		'insertIntoPost'     => $hier ? __( 'Insert into page' ) : __( 'Insert into post' ),
 		'uploadedToThisPost' => $hier ? __( 'Uploaded to this page' ) : __( 'Uploaded to this post' ),
 		'warnDelete' =>      __( "You are about to permanently delete this item.\n  'Cancel' to stop, 'OK' to delete." ),
@@ -1489,6 +1491,7 @@
 		'updateGallery'      => __( 'Update gallery' ),
 		'continueEditing'    => __( 'Continue editing' ),
 		'addToGallery'       => __( 'Add to gallery' ),
+		'addToGalleryTitle'  => __( 'Add to Gallery' ),
 		'reverseOrder'       => __( 'Reverse order' ),
 	);
 
@@ -1517,6 +1520,8 @@
 	?>
 	<script type="text/html" id="tmpl-media-frame">
 		<div class="media-frame-menu"></div>
+		<div class="media-frame-title"></div>
+		<div class="media-frame-router"></div>
 		<div class="media-frame-content"></div>
 		<div class="media-frame-toolbar"></div>
 		<div class="media-frame-uploader"></div>
@@ -1524,13 +1529,10 @@
 
 	<script type="text/html" id="tmpl-media-modal">
 		<div class="media-modal wp-core-ui">
-			<h3 class="media-modal-title">{{ data.title }}</h3>
-			<a class="media-modal-close media-modal-icon" href="#" title="<?php esc_attr_e('Close'); ?>"></a>
+			<a class="media-modal-close" href="#" title="<?php esc_attr_e('Close'); ?>"><span class="media-modal-icon"></span></a>
 			<div class="media-modal-content"></div>
 		</div>
-		<div class="media-modal-backdrop">
-			<div></div>
-		</div>
+		<div class="media-modal-backdrop"></div>
 	</script>
 
 	<script type="text/html" id="tmpl-uploader-window">
@@ -1540,16 +1542,20 @@
 	</script>
 
 	<script type="text/html" id="tmpl-uploader-inline">
-		<div class="uploader-inline-content">
+		<# var messageClass = data.message ? 'has-upload-message' : 'no-upload-message'; #>
+		<div class="uploader-inline-content {{ messageClass }}">
+		<# if ( data.message ) { #>
+			<h3 class="upload-message">{{ data.message }}</h3>
+		<# } #>
 		<?php if ( ! _device_can_upload() ) : ?>
-			<h3><?php _e('The web browser on your device cannot be used to upload files. You may be able to use the <a href="http://wordpress.org/extend/mobile/">native app for your device</a> instead.'); ?></h3>
+			<h3 class="upload-instructions"><?php _e('The web browser on your device cannot be used to upload files. You may be able to use the <a href="http://wordpress.org/extend/mobile/">native app for your device</a> instead.'); ?></h3>
 		<?php elseif ( is_multisite() && ! is_upload_space_available() ) : ?>
-			<h3><?php _e( 'Upload Limit Exceeded' ); ?></h3>
+			<h3 class="upload-instructions"><?php _e( 'Upload Limit Exceeded' ); ?></h3>
 			<?php do_action( 'upload_ui_over_quota' ); ?>
 
 		<?php else : ?>
 			<div class="upload-ui">
-				<h3 class="drop-instructions"><?php _e( 'Drop files anywhere to upload' ); ?></h3>
+				<h3 class="upload-instructions drop-instructions"><?php _e( 'Drop files anywhere to upload' ); ?></h3>
 				<a href="#" class="browser button button-hero"><?php _e( 'Select Files' ); ?></a>
 			</div>
 
@@ -1744,19 +1750,6 @@
 		<div class="selection-view"></div>
 	</script>
 
-	<script type="text/html" id="tmpl-media-selection-preview">
-		<div class="selected-img selected-count-{{ data.count }}">
-			<# if ( data.thumbnail ) { #>
-				<img src="{{ data.thumbnail }}" draggable="false" />
-			<# } #>
-
-			<span class="count">{{ data.count }}</span>
-		</div>
-		<# if ( data.clearable ) { #>
-			<a class="clear-selection" href="#"><?php _e('Clear selection'); ?></a>
-		<# } #>
-	</script>
-
 	<script type="text/html" id="tmpl-attachment-display-settings">
 		<h3><?php _e('Attachment Display Settings'); ?></h3>
 
