Index: src/wp-admin/css/customize-controls.css
===================================================================
--- src/wp-admin/css/customize-controls.css	(revision 28749)
+++ src/wp-admin/css/customize-controls.css	(working copy)
@@ -143,6 +143,49 @@
 	margin: 0;
 }
 
+.control-section.control-page .accordion-section-title:after {
+	content: "\f139";
+}
+
+#customize-theme-controls .control-subsection {
+	display: none;
+}
+
+#customize-theme-controls .control-section.current-page {
+	background-color: #fff;
+	color: #666666;
+	border-left: none;
+	border-right: none;
+	border-bottom: 1px solid #eee;
+	padding: 12px 15px 15px;
+}
+
+#customize-theme-controls .control-section.current-page h3.accordion-section-title {
+	font-size: 20px;
+	font-weight: 200;
+	line-height: 24px;
+	display: block;
+	border: none;
+	background: transparent;
+	padding: 0;
+}
+
+.control-section.control-page.current-page .accordion-section-title:after {
+	content: "\f141";
+	top: -6px;
+	right: -5px;
+}
+
+.control-section .preview-notice {
+	font-size: 13px;
+	line-height: 24px;
+	display: none;
+}
+
+.control-section.current-page .preview-notice {
+	display: block;
+}
+
 .customize-control {
 	width: 100%;
 	float: left;
Index: src/wp-admin/customize.php
===================================================================
--- src/wp-admin/customize.php	(revision 28749)
+++ src/wp-admin/customize.php	(working copy)
@@ -142,8 +142,12 @@
 
 			<div id="customize-theme-controls"><ul>
 				<?php
-				foreach ( $wp_customize->sections() as $section )
+				foreach ( $wp_customize->pages() as $page ) {
+					$page->maybe_render();
+				}
+				foreach ( $wp_customize->sections() as $section ) {
 					$section->maybe_render();
+				}
 				?>
 			</ul></div>
 		</div>
Index: src/wp-admin/js/accordion.js
===================================================================
--- src/wp-admin/js/accordion.js	(revision 28749)
+++ src/wp-admin/js/accordion.js	(working copy)
@@ -36,6 +36,11 @@
 		if ( section.hasClass( 'cannot-expand' ) )
 			return;
 
+		if ( section.hasClass( 'control-page' ) ) {
+			pageSwitch( section );
+			return;
+		}
+
 		if ( section.hasClass( 'open' ) ) {
 			section.toggleClass( 'open' );
 			content.toggle( true ).slideToggle( 150 );
@@ -49,6 +54,30 @@
 		accordionInit();
 	}
 
+	function pageSwitch( page ) {
+		var section = page.closest( '.accordion-section' ),
+			container = section.closest( '.accordion-container' );
+			pageId = $(page).attr('id').replace( 'accordion-section-', '' ),
+			subsections = container.find( '.control-subsection' ),
+			children = container.find( '.in-page-' + pageId ),
+			siblings = container.find( '.accordion-section' );
+
+		if ( section.hasClass( 'current-page' ) ) {
+			// Go back to the top-level.
+			section.toggleClass( 'current-page' );
+			siblings.show();
+			subsections.hide();
+			section.show();
+		} else {
+			// Enter the page.
+			siblings.removeClass( 'open' );
+			siblings.hide();
+			section.toggleClass( 'current-page' );
+			section.show();
+			children.show();
+		}
+	}
+
 	// Initialize the accordion (currently just corner fixes)
 	accordionInit();
 
Index: src/wp-admin/js/customize-widgets.js
===================================================================
--- src/wp-admin/js/customize-widgets.js	(revision 28749)
+++ src/wp-admin/js/customize-widgets.js	(working copy)
@@ -1423,27 +1423,6 @@
 
 				registeredSidebar.set( 'is_rendered', isRendered );
 			} );
-
-			// Show the sidebar section when it becomes visible
-			registeredSidebar.on( 'change:is_rendered', function( ) {
-				var sectionSelector = '#accordion-section-sidebar-widgets-' + this.get( 'id' ), $section;
-
-				$section = $( sectionSelector );
-				if ( this.get( 'is_rendered' ) ) {
-					$section.stop().slideDown( function() {
-						$( this ).css( 'height', 'auto' ); // so that the .accordion-section-content won't overflow
-					} );
-
-				} else {
-					// Make sure that hidden sections get closed first
-					if ( $section.hasClass( 'open' ) ) {
-						// it would be nice if accordionSwitch() in accordion.js was public
-						$section.find( '.accordion-section-title' ).trigger( 'click' );
-					}
-
-					$section.stop().slideUp();
-				}
-			} );
 		},
 
 		/**
Index: src/wp-includes/class-wp-customize-manager.php
===================================================================
--- src/wp-includes/class-wp-customize-manager.php	(revision 28749)
+++ src/wp-includes/class-wp-customize-manager.php	(working copy)
@@ -45,6 +45,7 @@
 	public $widgets;
 
 	protected $settings = array();
+	protected $pages    = array();
 	protected $sections = array();
 	protected $controls = array();
 
@@ -315,6 +316,17 @@
 	}
 
 	/**
+	 * Get the registered pages.
+	 *
+	 * @since 4.0.0
+	 *
+	 * @return array
+	 */
+	public function pages() {
+		return $this->pages;
+	}
+
+	/**
 	 * Checks if the current theme is active.
 	 *
 	 * @since 3.4.0
@@ -648,6 +660,50 @@
 	}
 
 	/**
+	 * Add a customize page.
+	 *
+	 * @since 4.0.0
+	 *
+	 * @param WP_Customize_Page|string $id   Customize Page object, or Page ID.
+	 * @param array                    $args Page arguments.
+	 */
+	public function add_page( $id, $args = array() ) {
+		if ( is_a( $id, 'WP_Customize_Page' ) ) {
+			$page = $id;
+		}
+		else {
+			$page = new WP_Customize_Page( $this, $id, $args );
+		}
+
+		$this->pages[ $page->id ] = $page;
+	}
+
+	/**
+	 * Retrieve a customize page.
+	 *
+	 * @since 4.0.0
+	 *
+	 * @param string $id Page ID.
+	 * @return WP_Customize_Page
+	 */
+	public function get_page( $id ) {
+		if ( isset( $this->pages[ $id ] ) ) {
+			return $this->pages[ $id ];
+		}
+	}
+
+	/**
+	 * Remove a customize page.
+	 *
+	 * @since 4.0.0
+	 *
+	 * @param string $id Page ID.
+	 */
+	public function remove_page( $id ) {
+		unset( $this->pages[ $id ] );
+	}
+
+	/**
 	 * Add a customize section.
 	 *
 	 * @since 3.4.0
@@ -749,7 +805,7 @@
 	}
 
 	/**
-	 * Prepare settings and sections.
+	 * Prepare pages, sections, and controls.
 	 *
 	 * For each, check if required related components exist,
 	 * whether the user has the necessary capabilities,
@@ -763,8 +819,9 @@
 		$controls = array();
 
 		foreach ( $this->controls as $id => $control ) {
-			if ( ! isset( $this->sections[ $control->section ] ) || ! $control->check_capabilities() )
+			if ( ! isset( $this->sections[ $control->section ] ) || ! $control->check_capabilities() ) {
 				continue;
+			}
 
 			$this->sections[ $control->section ]->controls[] = $control;
 			$controls[ $id ] = $control;
@@ -778,13 +835,38 @@
 		$sections = array();
 
 		foreach ( $this->sections as $section ) {
-			if ( ! $section->check_capabilities() || ! $section->controls )
+			if ( ! $section->check_capabilities() || ! $section->controls ) {
 				continue;
+			}
 
 			usort( $section->controls, array( $this, '_cmp_priority' ) );
-			$sections[] = $section;
+
+			if ( ! $section->page ) {
+				// Top-level section.
+				$sections[] = $section;
+			} else {
+				// This section belongs to a page.
+				$this->pages[ $section->page ]->sections[] = $section;
+			}
 		}
 		$this->sections = $sections;
+		//var_dump($this->pages);
+
+		// Prepare pages.
+		// Reversing makes uasort sort by time added when conflicts occur.
+		$this->pages = array_reverse( $this->pages );
+		uasort( $this->pages, array( $this, '_cmp_priority' ) );
+		$pages = array();
+
+		foreach ( $this->pages as $page ) {
+			if ( ! $page->check_capabilities() || ! $page->sections ) {
+				continue;
+			}
+
+			usort( $page->sections, array( $this, '_cmp_priority' ) );
+			$pages[] = $page;
+		}
+		$this->pages = $pages;
 	}
 
 	/**
Index: src/wp-includes/class-wp-customize-section.php
===================================================================
--- src/wp-includes/class-wp-customize-section.php	(revision 28749)
+++ src/wp-includes/class-wp-customize-section.php	(working copy)
@@ -38,6 +38,15 @@
 	public $priority = 10;
 
 	/**
+	 * Page in which to show the section, making it a sub-section.
+	 *
+	 * @since 4.0.0
+	 * @access public
+	 * @var string
+	 */
+	public $page = '';
+
+	/**
 	 * Capability required for the section.
 	 *
 	 * @since 3.4.0
@@ -162,8 +171,12 @@
 	 * @since 3.4.0
 	 */
 	protected function render() {
+		$classes = 'control-section accordion-section';
+		if ( $this->page ) {
+			$classes .= ' control-subsection in-page-' . $this->page;
+		}
 		?>
-		<li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="control-section accordion-section">
+		<li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="<?php echo esc_attr( $classes ); ?>">
 			<h3 class="accordion-section-title" tabindex="0"><?php echo esc_html( $this->title ); ?></h3>
 			<ul class="accordion-section-content">
 				<?php if ( ! empty( $this->description ) ) : ?>
@@ -178,3 +191,65 @@
 		<?php
 	}
 }
+
+/**
+ * Customize Page Class.
+ *
+ * A UI container for sections, managed by the WP_Customize_Manager.
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 4.0.0
+ */
+class WP_Customize_Page extends WP_Customize_Section {
+
+	/**
+	 * Customizer sections for this page.
+	 *
+	 * @since 4.0.0
+	 * @access public
+	 * @var array
+	 */
+	public $sections;
+
+	/**
+	 * Constructor.
+	 *
+	 * Any supplied $args override class property defaults.
+	 *
+	 * @since 4.0.0
+	 *
+	 * @param WP_Customize_Manager $manager Customizer bootstrap instance.
+	 * @param string               $id      An specific ID of the section.
+	 * @param array                $args    Section arguments.
+	 */
+	public function __construct( $manager, $id, $args = array() ) {
+		parent::__construct( $manager, $id, $args );
+
+		$this->sections = array(); // Users cannot customize the $sections array.
+
+		return $this;
+	}
+
+	/**
+	 * Render the page, and the sections that have been added to it.
+	 *
+	 * @since 3.4.0
+	 */
+	protected function render() {
+		?>
+		<li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="control-section control-page accordion-section">
+			<span class="preview-notice"><?php _e( 'You are editing your site&#8217;s' ); ?></span>
+			<h3 class="accordion-section-title" tabindex="0"><?php echo esc_html( $this->title ); ?></h3>
+			<ul class="accordion-section-content">
+				<?php if ( ! empty( $this->description ) ) : ?>
+				<li><p class="description"><?php echo $this->description; ?></p></li>
+				<?php endif; ?>
+			</ul>
+		</li>
+		<?php
+		foreach ( $this->sections as $section ) {
+			$section->maybe_render();
+		}
+	}
+}
Index: src/wp-includes/class-wp-customize-widgets.php
===================================================================
--- src/wp-includes/class-wp-customize-widgets.php	(revision 28749)
+++ src/wp-includes/class-wp-customize-widgets.php	(working copy)
@@ -433,6 +433,10 @@
 			$this->manager->add_setting( $setting_id, $setting_args );
 		}
 
+		$this->manager->add_page( 'widgets', array(
+			'title' => 'Widgets',
+		) );
+
 		foreach ( $sidebars_widgets as $sidebar_id => $sidebar_widget_ids ) {
 			if ( empty( $sidebar_widget_ids ) ) {
 				$sidebar_widget_ids = array();
@@ -462,6 +466,7 @@
 						'title' => sprintf( __( 'Widgets: %s' ), $GLOBALS['wp_registered_sidebars'][$sidebar_id]['name'] ),
 						'description' => $GLOBALS['wp_registered_sidebars'][$sidebar_id]['description'],
 						'priority' => 1000 + array_search( $sidebar_id, array_keys( $wp_registered_sidebars ) ),
+						'page' => 'widgets',
 					);
 
 					/**
