From 21273f97bb893e32c232681f717e6d6c12737cbe Mon Sep 17 00:00:00 2001
From: Piotr Delawski <piotr.delawski@xwp.co>
Date: Sat, 6 Feb 2016 16:02:02 +0100
Subject: [PATCH 1/9] Tac-34391 - Under development, so far a dirty solution

---
 src/wp-admin/css/customize-controls.css | 109 +++++++++++--
 src/wp-admin/customize.php              |   2 +-
 src/wp-admin/js/customize-controls.js   | 263 ++++++++++++++++++++++----------
 3 files changed, 277 insertions(+), 97 deletions(-)

diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css
index ced9735..db7e561 100644
--- a/src/wp-admin/css/customize-controls.css
+++ b/src/wp-admin/css/customize-controls.css
@@ -217,6 +217,87 @@ body {
 	box-sizing: border-box;
 }
 
+
+
+
+#customize-info,
+#customize-theme-controls .customize-pane-parent,
+#customize-theme-controls .customize-pane-child {
+	width: 100%;
+	margin: 0;
+	padding: 0;
+	-webkit-box-sizing: border-box;
+	-moz-box-sizing: border-box;
+	box-sizing: border-box;
+
+	transition: 0.36s transform cubic-bezier(0.19, 1, 0.22, 1);
+	/*visibility: visible !important;*/
+	overflow: visible !important;
+}
+
+#customize-info,
+#customize-theme-controls .customize-pane-parent {
+	position: relative;
+	visibility: visible;
+	transform: translateX(0);
+}
+
+.section-open #customize-theme-controls .customize-pane-parent,
+.in-sub-panel #customize-theme-controls .customize-pane-parent,
+.section-open #customize-info,
+.in-sub-panel #customize-info,
+.in-sub-panel.section-open #customize-theme-controls .customize-pane-child.current-panel {
+	transform: translateX(-100%);
+	/*visibility: hidden;*/
+}
+
+.section-open #customize-theme-controls .customize-pane-parent,
+.in-sub-panel #customize-theme-controls .customize-pane-parent,
+.section-open #customize-info,
+.in-sub-panel #customize-info,
+.animating.section-open.in-sub-panel #customize-theme-controls .customize-pane-parent,
+.animating.section-open.in-sub-panel #customize-info, {
+	visibility: hidden;
+}
+
+.animating.section-open #customize-theme-controls .customize-pane-parent,
+.animating.in-sub-panel #customize-theme-controls .customize-pane-parent,
+.animating.section-open #customize-info,
+.animating.in-sub-panel #customize-info {
+	visibility: visible;
+}
+
+#customize-theme-controls .customize-pane-child {
+	position: absolute;
+	top: 0;
+	left: 0;
+	transform: translateX(100%);
+	visibility: hidden;
+}
+
+#customize-theme-controls .customize-pane-child.accordion-section-content,
+#customize-theme-controls .customize-pane-child.accordion-sub-container {
+	display: block;
+}
+
+#customize-theme-controls .customize-pane-child.accordion-section-content {
+	padding: 12px;
+}
+
+#customize-theme-controls .customize-pane-child.open,
+#customize-theme-controls .customize-pane-child.current-panel {
+	transform: translateX(0);
+}
+
+#customize-theme-controls .customize-pane-child.open,
+#customize-theme-controls .customize-pane-child.current-panel,
+#customize-theme-controls .customize-pane-child.animating {
+	visibility: visible;
+}
+
+
+
+
 .customize-section-description-container {
 	margin-bottom: 15px;
 }
@@ -256,22 +337,22 @@ h3.customize-section-title {
 	color: #555;
 }
 
-#customize-theme-controls {
+/*#customize-theme-controls {
 	position: relative;
 	left: 0;
 	-webkit-transition: .18s left ease-in-out;
 	transition: .18s left ease-in-out;
-}
+}*/
 
-.ios #customize-theme-controls {
+/*.ios #customize-theme-controls {
 	-webkit-transition: left 0s;
 	transition: left 0s;
-}
+}*/
 
-.section-open #customize-info,
+/*.section-open #customize-info,
 .section-open #customize-theme-controls {
 	left: -100%;
-}
+}*/
 
 .accordion-sub-container.control-panel-content {
 	display: none;
@@ -410,7 +491,7 @@ h3.customize-section-title {
 	padding-left: 62px;
 }
 
-#customize-info,
+/*#customize-info,
 #customize-theme-controls > ul > .accordion-section {
 	position: relative;
 	left: 0;
@@ -423,17 +504,17 @@ h3.customize-section-title {
 	-webkit-transition: left 0s;
 	transition: left 0s;
 }
-
-.in-sub-panel #customize-info,
+*/
+/*.in-sub-panel #customize-info,
 .in-sub-panel #customize-theme-controls > ul > .accordion-section {
 	left: -300px;
 	width: 300px;
-}
+}*/
 
-.in-sub-panel #customize-theme-controls .accordion-section.current-panel {
+/*.in-sub-panel #customize-theme-controls .accordion-section.current-panel {
 	width: 100%;
 }
-
+*/
 #customize-theme-controls .control-section.current-panel {
 	padding: 0;
 }
@@ -459,13 +540,13 @@ h3.customize-section-title {
 	overflow-y: hidden;
 }
 
-.wp-full-overlay.section-open .wp-full-overlay-sidebar-content .accordion-section.open {
+/*.wp-full-overlay.section-open .wp-full-overlay-sidebar-content .accordion-section.open {
 	visibility: visible;
 }
 
 .wp-full-overlay.section-open .wp-full-overlay-sidebar-content .accordion-section.open .accordion-section-content {
 	overflow-y: auto;
-}
+}*/
 
 p.customize-section-description {
 	font-style: normal;
diff --git a/src/wp-admin/customize.php b/src/wp-admin/customize.php
index aa949e5..39b35f3 100644
--- a/src/wp-admin/customize.php
+++ b/src/wp-admin/customize.php
@@ -142,7 +142,7 @@
 			</div>
 
 			<div id="customize-theme-controls">
-				<ul><?php // Panels and sections are managed here via JavaScript ?></ul>
+				<ul class="customize-pane-parent"><?php // Panels and sections are managed here via JavaScript ?></ul>
 			</div>
 		</div>
 		</div>
diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
index e78d2c9..19f508d 100644
--- a/src/wp-admin/js/customize-controls.js
+++ b/src/wp-admin/js/customize-controls.js
@@ -163,6 +163,31 @@
 	};
 
 	/**
+	 * Return browser supported `transitionend` event name
+	 *
+	 * @since 
+	 *
+	 * @returns {String}
+	 */
+	api.utils.getNormalizedTransitionendEvent = function () {
+		var t,
+			undefined,
+			el = document.createElement( 'div' ),
+			transitions = {
+				'transition'      : 'transitionend',
+				'OTransition'     : 'oTransitionEnd',
+				'MozTransition'   : 'transitionend',
+				'WebkitTransition': 'webkitTransitionEnd'
+			};
+
+		for ( t in transitions ) {
+			if ( transitions.hasOwnProperty( t ) && undefined !== el.style[ t ] ) {
+				return transitions[t];
+			}
+		}
+	};
+
+	/**
 	 * Base class for Panel and Section.
 	 *
 	 * @since 4.1.0
@@ -214,6 +239,8 @@
 				container.container = $( container.getContainer() );
 			}
 
+			container.content = container.getContent();
+
 			container.deferred = {
 				embedded: new $.Deferred()
 			};
@@ -481,6 +508,34 @@
 			}
 
 			return '<li></li>';
+		},
+
+		getContent: function () {
+			var container = this,
+				list = container.container.find( 'ul:first' ),
+				contentId = 'sub-accordion-list-' + container.id;
+
+			container.setOwnership( contentId );
+
+			return list.detach().attr( {
+				id: contentId,
+				class: 'customize-pane-child ' + list.attr( 'class' )
+			} );
+		},
+
+		setOwnership: function ( elementId ) {
+			var container = this.container,
+				ownedElements = container.attr( 'aria-owns' );
+
+			if ( _.isUndefined( ownedElements ) ) {
+				container.attr( {
+					'aria-owns': elementId
+				} );
+			} else {
+				container.attr( {
+					'aria-owns': ownedElements + ' ' + elementId
+				} );
+			}
 		}
 	});
 
@@ -543,7 +598,9 @@
 		 * @since 4.1.0
 		 */
 		embed: function () {
-			var section = this, inject;
+			var inject,
+				section = this,
+				container = $( '#customize-theme-controls' );
 
 			// Watch for changes to the panel state
 			inject = function ( panelId ) {
@@ -553,18 +610,21 @@
 					api.panel( panelId, function ( panel ) {
 						// The panel has been registered, wait for it to become ready/initialized
 						panel.deferred.embedded.done( function () {
-							parentContainer = panel.container.find( 'ul:first' );
+							parentContainer = panel.content; // panel.container.find( 'ul:first' );
 							if ( ! section.container.parent().is( parentContainer ) ) {
 								parentContainer.append( section.container );
+								//section.setOwnership( section.content.attr( 'id' ) );
+								container.append( section.content );
 							}
 							section.deferred.embedded.resolve();
 						});
 					} );
 				} else {
 					// There is no panel, so embed the section in the root of the customizer
-					parentContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable
+					parentContainer = $( '.customize-pane-parent' ); // @todo This should be defined elsewhere, and to be configurable
 					if ( ! section.container.parent().is( parentContainer ) ) {
 						parentContainer.append( section.container );
+						container.append( section.content );
 					}
 					section.deferred.embedded.resolve();
 				}
@@ -586,10 +646,14 @@
 		 * @since 4.1.0
 		 */
 		attachEvents: function () {
-			var section = this;
+			var section = this,
+				expandCollapseEventTypes = 'click keydown',
+				expandCollapseEventHandler,
+				overlay = section.content.closest( '.wp-full-overlay' ),
+				normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
 
 			// Expand/Collapse accordion sections on click.
-			section.container.find( '.accordion-section-title, .customize-section-back' ).on( 'click keydown', function( event ) {
+			expandCollapseEventHandler = function ( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
 				}
@@ -600,6 +664,14 @@
 				} else {
 					section.expand();
 				}
+			};
+
+			section.container.find( '.accordion-section-title' ).on( expandCollapseEventTypes, expandCollapseEventHandler );
+			section.content.find( '.customize-section-back' ).on( expandCollapseEventTypes, expandCollapseEventHandler );
+
+			section.content.on( normalizedTransitionendEventName, function() {
+				section.content.removeClass( 'animating' );
+				overlay.removeClass( 'animating' );
 			});
 		},
 
@@ -644,46 +716,51 @@
 		onChangeExpanded: function ( expanded, args ) {
 			var section = this,
 				container = section.container.closest( '.wp-full-overlay-sidebar-content' ),
-				content = section.container.find( '.accordion-section-content' ),
+				content = section.content, //section.container.find( '.accordion-section-content' ),
 				overlay = section.container.closest( '.wp-full-overlay' ),
-				backBtn = section.container.find( '.customize-section-back' ),
-				sectionTitle = section.container.find( '.accordion-section-title' ).first(),
-				headerActionsHeight = $( '#customize-header-actions' ).height(),
-				resizeContentHeight, expand, position, scroll;
+				backBtn = content.find( '.customize-section-back' ), //section.container.find( '.customize-section-back' ),
+				sectionTitle = content.find( '.accordion-section-title' ).first(), // section.container.find( '.accordion-section-title' ).first(),
+				// headerActionsHeight = $( '#customize-header-actions' ).height(),
+				// resizeContentHeight,
+				expand, position, scroll;
 
-			if ( expanded && ! section.container.hasClass( 'open' ) ) {
+			// if ( expanded && ! section.container.hasClass( 'open' ) ) {
+			if ( expanded && ! content.hasClass( 'open' ) ) {
 
 				if ( args.unchanged ) {
 					expand = args.completeCallback;
 				} else {
 					container.scrollTop( 0 );
-					resizeContentHeight = function() {
-						var matchMedia, offset;
-						matchMedia = window.matchMedia || window.msMatchMedia;
-						offset = 90; // 45px for customize header actions + 45px for footer actions.
-
-						// No footer on small screens.
-						if ( matchMedia && matchMedia( '(max-width: 640px)' ).matches ) {
-							offset = 45;
-						}
-						content.css( 'height', ( window.innerHeight - offset ) );
-					};
+					// resizeContentHeight = function() {
+					// 	var matchMedia, offset;
+					// 	matchMedia = window.matchMedia || window.msMatchMedia;
+					// 	offset = 90; // 45px for customize header actions + 45px for footer actions.
+
+					// 	// No footer on small screens.
+					// 	if ( matchMedia && matchMedia( '(max-width: 640px)' ).matches ) {
+					// 		offset = 45;
+					// 	}
+					// 	content.css( 'height', ( window.innerHeight - offset ) );
+					// };
 					expand = function() {
-						section.container.addClass( 'open' );
+						// section.container.addClass( 'open' );
+						content.addClass( 'open' );
+						content.addClass( 'animating' );
 						overlay.addClass( 'section-open' );
-						position = content.offset().top;
-						scroll = container.scrollTop();
-						content.css( 'margin-top', ( headerActionsHeight - position - scroll ) );
-						resizeContentHeight();
+						overlay.addClass( 'animating' );
+						// position = content.offset().top;
+						// scroll = container.scrollTop();
+						// content.css( 'margin-top', ( headerActionsHeight - position - scroll ) );
+						// resizeContentHeight();
 						sectionTitle.attr( 'tabindex', '-1' );
 						backBtn.attr( 'tabindex', '0' );
-						backBtn.focus();
+						// backBtn.focus();
 						if ( args.completeCallback ) {
 							args.completeCallback();
 						}
 
 						// Fix the height after browser resize.
-						$( window ).on( 'resize.customizer-section', _.debounce( resizeContentHeight, 100 ) );
+						// $( window ).on( 'resize.customizer-section', _.debounce( resizeContentHeight, 100 ) );
 
 						section._recalculateTopMargin();
 					};
@@ -709,18 +786,22 @@
 					expand();
 				}
 
-			} else if ( ! expanded && section.container.hasClass( 'open' ) ) {
-				section.container.removeClass( 'open' );
+			// } else if ( ! expanded && section.container.hasClass( 'open' ) ) {
+			} else if ( ! expanded && content.hasClass( 'open' ) ) {
+				// section.container.removeClass( 'open' );
+				content.removeClass( 'open' );
+				content.addClass( 'animating' );
 				overlay.removeClass( 'section-open' );
-				content.css( 'margin-top', '' );
-				container.scrollTop( 0 );
+				overlay.addClass( 'animating' );
+				// content.css( 'margin-top', '' );
+				// container.scrollTop( 0 );
 				backBtn.attr( 'tabindex', '-1' );
 				sectionTitle.attr( 'tabindex', '0' );
-				sectionTitle.focus();
+				// sectionTitle.focus();
 				if ( args.completeCallback ) {
 					args.completeCallback();
 				}
-				$( window ).off( 'resize.customizer-section' );
+				// $( window ).off( 'resize.customizer-section' );
 			} else {
 				if ( args.completeCallback ) {
 					args.completeCallback();
@@ -735,16 +816,17 @@
 		 * @private
 		 */
 		_recalculateTopMargin: function() {
-			var section = this, content, offset, headerActionsHeight;
-			content = section.container.find( '.accordion-section-content' );
-			if ( 0 === content.length ) {
-				return;
-			}
-			headerActionsHeight = $( '#customize-header-actions' ).height();
-			offset = ( content.offset().top - headerActionsHeight );
-			if ( 0 < offset ) {
-				content.css( 'margin-top', ( parseInt( content.css( 'margin-top' ), 10 ) - offset ) );
-			}
+			return;
+			// var section = this, content, offset, headerActionsHeight;
+			// content = section.container.find( '.accordion-section-content' );
+			// if ( 0 === content.length ) {
+			// 	return;
+			// }
+			// headerActionsHeight = $( '#customize-header-actions' ).height();
+			// offset = ( content.offset().top - headerActionsHeight );
+			// if ( 0 < offset ) {
+			// 	content.css( 'margin-top', ( parseInt( content.css( 'margin-top' ), 10 ) - offset ) );
+			// }
 		}
 	});
 
@@ -982,7 +1064,8 @@
 		 * @private
 		 */
 		_recalculateTopMargin: function() {
-			api.Panel.prototype._recalculateTopMargin.call( this );
+			return;
+			// api.Panel.prototype._recalculateTopMargin.call( this );
 		},
 
 		/**
@@ -1211,16 +1294,18 @@
 		 */
 		embed: function () {
 			var panel = this,
-				parentContainer = $( '#customize-theme-controls > ul' ); // @todo This should be defined elsewhere, and to be configurable
+				container = $( '#customize-theme-controls' ),
+				parentContainer = $( '.customize-pane-parent' ); // @todo This should be defined elsewhere, and to be configurable
 
 			if ( ! panel.container.parent().is( parentContainer ) ) {
 				parentContainer.append( panel.container );
+				container.append( panel.content );
 				panel.renderContent();
 			}
 
-			api.bind( 'pane-contents-reflowed', _.debounce( function() {
-				panel._recalculateTopMargin();
-			}, 100 ) );
+			// api.bind( 'pane-contents-reflowed', _.debounce( function() {
+			// 	panel._recalculateTopMargin();
+			// }, 100 ) );
 
 			panel.deferred.embedded.resolve();
 		},
@@ -1229,7 +1314,9 @@
 		 * @since 4.1.0
 		 */
 		attachEvents: function () {
-			var meta, panel = this;
+			var meta, panel = this,
+				overlay = panel.content.closest( '.wp-full-overlay' ),
+				normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
 
 			// Expand/Collapse accordion sections on click.
 			panel.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
@@ -1244,7 +1331,8 @@
 			});
 
 			// Close panel.
-			panel.container.find( '.customize-panel-back' ).on( 'click keydown', function( event ) {
+			// panel.container.find( '.customize-panel-back' ).on( 'click keydown', function( event ) {
+			panel.content.find( '.customize-panel-back' ).on( 'click keydown', function( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
 				}
@@ -1255,7 +1343,7 @@
 				}
 			});
 
-			meta = panel.container.find( '.panel-meta:first' );
+			meta = panel.content.find( '.panel-meta:first' );
 
 			meta.find( '> .accordion-section-title .customize-help-toggle' ).on( 'click keydown', function( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
@@ -1263,7 +1351,7 @@
 				}
 				event.preventDefault(); // Keep this AFTER the key filter above
 
-				meta = panel.container.find( '.panel-meta' );
+				// meta = panel.container.find( '.panel-meta' );
 				if ( meta.hasClass( 'cannot-expand' ) ) {
 					return;
 				}
@@ -1280,6 +1368,11 @@
 				}
 			});
 
+			panel.content.on( normalizedTransitionendEventName, function() {
+				panel.content.removeClass( 'animating' );
+				overlay.removeClass( 'animating' );
+			});
+
 		},
 
 		/**
@@ -1335,15 +1428,16 @@
 			// Note: there is a second argument 'args' passed
 			var position, scroll,
 				panel = this,
-				accordionSection = panel.container.closest( '.accordion-section' ),
+				accordionSection = panel.content; // .closest( '.accordion-section' ),
 				overlay = accordionSection.closest( '.wp-full-overlay' ),
 				container = accordionSection.closest( '.wp-full-overlay-sidebar-content' ),
 				siblings = container.find( '.open' ),
-				topPanel = overlay.find( '#customize-theme-controls > ul > .accordion-section > .accordion-section-title' ),
+				// topPanel = overlay.find( '#customize-theme-controls > ul > .accordion-section > .accordion-section-title' ),
+				topPanel = accordionSection.find( '.accordion-section-title' ),
 				backBtn = accordionSection.find( '.customize-panel-back' ),
-				panelTitle = accordionSection.find( '.accordion-section-title' ).first(),
-				content = accordionSection.find( '.control-panel-content' ),
-				headerActionsHeight = $( '#customize-header-actions' ).height();
+				panelTitle = accordionSection.find( '.accordion-section-title' ).first();
+				// content = panel.content, // accordionSection.find( '.control-panel-content' ),
+				// headerActionsHeight = $( '#customize-header-actions' ).height();
 
 			if ( expanded ) {
 
@@ -1359,35 +1453,39 @@
 					}
 				});
 
-				content.show( 0, function() {
-					content.parent().show();
-					position = content.offset().top;
-					scroll = container.scrollTop();
-					content.css( 'margin-top', ( headerActionsHeight - position - scroll ) );
+				// content.show( 0, function() {
+					// content.parent().show();
+					// position = content.offset().top;
+					// scroll = container.scrollTop();
+					// content.css( 'margin-top', ( headerActionsHeight - position - scroll ) );
 					accordionSection.addClass( 'current-panel' );
 					overlay.addClass( 'in-sub-panel' );
-					container.scrollTop( 0 );
+					accordionSection.addClass( 'animating' );
+					overlay.addClass( 'animating' );
+					// container.scrollTop( 0 );
 					if ( args.completeCallback ) {
 						args.completeCallback();
 					}
-				} );
+				// } );
 				topPanel.attr( 'tabindex', '-1' );
 				backBtn.attr( 'tabindex', '0' );
-				backBtn.focus();
-				panel._recalculateTopMargin();
+				// backBtn.focus();
+				// panel._recalculateTopMargin();
 			} else {
 				siblings.removeClass( 'open' );
 				accordionSection.removeClass( 'current-panel' );
 				overlay.removeClass( 'in-sub-panel' );
-				content.delay( 180 ).hide( 0, function() {
-					content.css( 'margin-top', 'inherit' ); // Reset
+				accordionSection.addClass( 'animating' );
+				overlay.addClass( 'animating' );
+				// content.delay( 180 ).hide( 0, function() {
+				// 	content.css( 'margin-top', 'inherit' ); // Reset
 					if ( args.completeCallback ) {
 						args.completeCallback();
 					}
-				} );
+				// } );
 				topPanel.attr( 'tabindex', '0' );
 				backBtn.attr( 'tabindex', '-1' );
-				panelTitle.focus();
+				// panelTitle.focus();
 				container.scrollTop( 0 );
 			}
 		},
@@ -1399,11 +1497,12 @@
 		 * @private
 		 */
 		_recalculateTopMargin: function() {
-			var panel = this, headerActionsHeight, content, accordionSection;
-			headerActionsHeight = $( '#customize-header-actions' ).height();
-			accordionSection = panel.container.closest( '.accordion-section' );
-			content = accordionSection.find( '.control-panel-content' );
-			content.css( 'margin-top', ( parseInt( content.css( 'margin-top' ), 10 ) - ( content.offset().top - headerActionsHeight ) ) );
+			return;
+			// var panel = this, headerActionsHeight, content, accordionSection;
+			// headerActionsHeight = $( '#customize-header-actions' ).height();
+			// accordionSection = panel.container.closest( '.accordion-section' );
+			// content = accordionSection.find( '.control-panel-content' );
+			// content.css( 'margin-top', ( parseInt( content.css( 'margin-top' ), 10 ) - ( content.offset().top - headerActionsHeight ) ) );
 		},
 
 		/**
@@ -1424,7 +1523,7 @@
 				template = wp.template( 'customize-panel-default-content' );
 			}
 			if ( template && panel.container ) {
-				panel.container.find( '.accordion-sub-container' ).html( template( panel.params ) );
+				panel.content.html( template( panel.params ) );
 			}
 		}
 	});
@@ -1557,7 +1656,7 @@
 				api.section( sectionId, function ( section ) {
 					// Wait for the section to be ready/initialized
 					section.deferred.embedded.done( function () {
-						parentContainer = section.container.find( 'ul:first' );
+						parentContainer = section.content; // section.container.find( 'ul:first' );
 						if ( ! control.container.parent().is( parentContainer ) ) {
 							parentContainer.append( control.container );
 							control.renderContent();
@@ -3451,7 +3550,7 @@
 				var sections = panel.sections(),
 					sectionContainers = _.pluck( sections, 'container' );
 				rootNodes.push( panel );
-				appendContainer = panel.container.find( 'ul:first' );
+				appendContainer = panel.content; // panel.container.find( 'ul:first' );
 				if ( ! api.utils.areElementListsEqual( sectionContainers, appendContainer.children( '[id]' ) ) ) {
 					_( sections ).each( function ( section ) {
 						appendContainer.append( section.container );
@@ -3467,7 +3566,7 @@
 				if ( ! section.panel() ) {
 					rootNodes.push( section );
 				}
-				appendContainer = section.container.find( 'ul:first' );
+				appendContainer = section.content; // section.container.find( 'ul:first' );
 				if ( ! api.utils.areElementListsEqual( controlContainers, appendContainer.children( '[id]' ) ) ) {
 					_( controls ).each( function ( control ) {
 						appendContainer.append( control.container );
@@ -3479,7 +3578,7 @@
 			// Sort the root panels and sections
 			rootNodes.sort( api.utils.prioritySort );
 			rootContainers = _.pluck( rootNodes, 'container' );
-			appendContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable
+			appendContainer = $( '.customize-pane-parent' ); //$( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable
 			if ( ! api.utils.areElementListsEqual( rootContainers, appendContainer.children() ) ) {
 				_( rootNodes ).each( function ( rootNode ) {
 					appendContainer.append( rootNode.container );

From 5d422a665c05721fb6b66f8c23230807e4d1ec43 Mon Sep 17 00:00:00 2001
From: Piotr Delawski <piotr.delawski@xwp.co>
Date: Fri, 12 Feb 2016 21:49:47 +0100
Subject: [PATCH 2/9] WIP: Harden panel/section UI code by removing contents
 from being logically nested

---
 src/wp-admin/js/customize-controls.js | 48 ++++++++++++++++++++++++-----------
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
index 19f508d..695771d 100644
--- a/src/wp-admin/js/customize-controls.js
+++ b/src/wp-admin/js/customize-controls.js
@@ -649,8 +649,8 @@
 			var section = this,
 				expandCollapseEventTypes = 'click keydown',
 				expandCollapseEventHandler,
-				overlay = section.content.closest( '.wp-full-overlay' ),
-				normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
+				overlay = section.content.closest( '.wp-full-overlay' );
+				//normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
 
 			// Expand/Collapse accordion sections on click.
 			expandCollapseEventHandler = function ( event ) {
@@ -669,10 +669,10 @@
 			section.container.find( '.accordion-section-title' ).on( expandCollapseEventTypes, expandCollapseEventHandler );
 			section.content.find( '.customize-section-back' ).on( expandCollapseEventTypes, expandCollapseEventHandler );
 
-			section.content.on( normalizedTransitionendEventName, function() {
-				section.content.removeClass( 'animating' );
-				overlay.removeClass( 'animating' );
-			});
+			// section.content.on( normalizedTransitionendEventName, function() {
+			// 	section.content.removeClass( 'animating' );
+			// 	overlay.removeClass( 'animating' );
+			// });
 		},
 
 		/**
@@ -722,6 +722,7 @@
 				sectionTitle = content.find( '.accordion-section-title' ).first(), // section.container.find( '.accordion-section-title' ).first(),
 				// headerActionsHeight = $( '#customize-header-actions' ).height(),
 				// resizeContentHeight,
+				normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent(),
 				expand, position, scroll;
 
 			// if ( expanded && ! section.container.hasClass( 'open' ) ) {
@@ -745,9 +746,13 @@
 					expand = function() {
 						// section.container.addClass( 'open' );
 						content.addClass( 'open' );
-						content.addClass( 'animating' );
 						overlay.addClass( 'section-open' );
+						content.addClass( 'animating' );
 						overlay.addClass( 'animating' );
+						content.one( normalizedTransitionendEventName, function() {
+							content.removeClass( 'animating' );
+							overlay.removeClass( 'animating' );
+						});
 						// position = content.offset().top;
 						// scroll = container.scrollTop();
 						// content.css( 'margin-top', ( headerActionsHeight - position - scroll ) );
@@ -790,9 +795,13 @@
 			} else if ( ! expanded && content.hasClass( 'open' ) ) {
 				// section.container.removeClass( 'open' );
 				content.removeClass( 'open' );
-				content.addClass( 'animating' );
 				overlay.removeClass( 'section-open' );
+				content.addClass( 'animating' );
 				overlay.addClass( 'animating' );
+				content.one( normalizedTransitionendEventName, function() {
+					content.removeClass( 'animating' );
+					overlay.removeClass( 'animating' );
+				});
 				// content.css( 'margin-top', '' );
 				// container.scrollTop( 0 );
 				backBtn.attr( 'tabindex', '-1' );
@@ -1315,8 +1324,8 @@
 		 */
 		attachEvents: function () {
 			var meta, panel = this,
-				overlay = panel.content.closest( '.wp-full-overlay' ),
-				normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
+				overlay = panel.content.closest( '.wp-full-overlay' );
+				//normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
 
 			// Expand/Collapse accordion sections on click.
 			panel.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
@@ -1368,10 +1377,10 @@
 				}
 			});
 
-			panel.content.on( normalizedTransitionendEventName, function() {
-				panel.content.removeClass( 'animating' );
-				overlay.removeClass( 'animating' );
-			});
+			// panel.content.on( normalizedTransitionendEventName, function() {
+			// 	panel.content.removeClass( 'animating' );
+			// 	overlay.removeClass( 'animating' );
+			// });
 
 		},
 
@@ -1435,7 +1444,8 @@
 				// topPanel = overlay.find( '#customize-theme-controls > ul > .accordion-section > .accordion-section-title' ),
 				topPanel = accordionSection.find( '.accordion-section-title' ),
 				backBtn = accordionSection.find( '.customize-panel-back' ),
-				panelTitle = accordionSection.find( '.accordion-section-title' ).first();
+				panelTitle = accordionSection.find( '.accordion-section-title' ).first(),
+				normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
 				// content = panel.content, // accordionSection.find( '.control-panel-content' ),
 				// headerActionsHeight = $( '#customize-header-actions' ).height();
 
@@ -1462,6 +1472,10 @@
 					overlay.addClass( 'in-sub-panel' );
 					accordionSection.addClass( 'animating' );
 					overlay.addClass( 'animating' );
+					accordionSection.one( normalizedTransitionendEventName, function() {
+						accordionSection.removeClass( 'animating' );
+						overlay.removeClass( 'animating' );
+					});
 					// container.scrollTop( 0 );
 					if ( args.completeCallback ) {
 						args.completeCallback();
@@ -1477,6 +1491,10 @@
 				overlay.removeClass( 'in-sub-panel' );
 				accordionSection.addClass( 'animating' );
 				overlay.addClass( 'animating' );
+				accordionSection.one( normalizedTransitionendEventName, function() {
+					accordionSection.removeClass( 'animating' );
+					overlay.removeClass( 'animating' );
+				});
 				// content.delay( 180 ).hide( 0, function() {
 				// 	content.css( 'margin-top', 'inherit' ); // Reset
 					if ( args.completeCallback ) {

From 6055301c7fbfbee0387d5e92cc9108399d62501d Mon Sep 17 00:00:00 2001
From: Piotr Delawski <piotr.delawski@xwp.co>
Date: Sat, 20 Feb 2016 23:52:02 +0100
Subject: [PATCH 3/9] Fix transitioning and class handling. Add focus()
 support. Not browser tested yet.

---
 src/wp-admin/css/common.css             |   6 +-
 src/wp-admin/css/customize-controls.css |  48 +++---
 src/wp-admin/js/customize-controls.js   | 261 ++++++++++++--------------------
 3 files changed, 120 insertions(+), 195 deletions(-)

diff --git a/src/wp-admin/css/common.css b/src/wp-admin/css/common.css
index 679b0b9..3886902 100644
--- a/src/wp-admin/css/common.css
+++ b/src/wp-admin/css/common.css
@@ -3213,7 +3213,8 @@ img {
 	display: none;
 }
 
-.control-section .accordion-section-title {
+.control-section .accordion-section-title,
+.customize-pane-child .accordion-section-title {
 	border-left: none;
 	border-right: none;
 	padding: 10px 10px 11px 14px;
@@ -3221,7 +3222,8 @@ img {
 	background: #fff;
 }
 
-.control-section .accordion-section-title:after {
+.control-section .accordion-section-title:after,
+.customize-pane-child .accordion-section-title:after {
 	top: 11px;
 }
 
diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css
index 70f4f13..a45c228 100644
--- a/src/wp-admin/css/customize-controls.css
+++ b/src/wp-admin/css/customize-controls.css
@@ -77,8 +77,8 @@ body {
 	line-height: 24px;
 }
 
-#customize-controls .control-section .customize-section-title h3,
-#customize-controls .control-section h3.customize-section-title,
+#customize-controls .customize-pane-child .customize-section-title h3,
+#customize-controls .customize-pane-child h3.customize-section-title,
 #customize-controls .customize-info .panel-title {
 	font-size: 20px;
 	font-weight: 200;
@@ -217,22 +217,17 @@ body {
 	box-sizing: border-box;
 }
 
-
-
-
 #customize-info,
 #customize-theme-controls .customize-pane-parent,
 #customize-theme-controls .customize-pane-child {
+	overflow: visible;
 	width: 100%;
 	margin: 0;
 	padding: 0;
 	-webkit-box-sizing: border-box;
 	-moz-box-sizing: border-box;
 	box-sizing: border-box;
-
-	transition: 0.36s transform cubic-bezier(0.19, 1, 0.22, 1);
-	/*visibility: visible !important;*/
-	overflow: visible !important;
+	transition: 0.36s transform cubic-bezier(0.19, 1, 0.22, 1); /* http://easings.net/#easeOutExpo */
 }
 
 #customize-info,
@@ -248,22 +243,29 @@ body {
 .in-sub-panel #customize-info,
 .in-sub-panel.section-open #customize-theme-controls .customize-pane-child.current-panel {
 	transform: translateX(-100%);
-	/*visibility: hidden;*/
+}
+
+#customize-theme-controls .customize-pane-child.open,
+#customize-theme-controls .customize-pane-child.current-panel {
+	transform: translateX(0);
 }
 
 .section-open #customize-theme-controls .customize-pane-parent,
 .in-sub-panel #customize-theme-controls .customize-pane-parent,
 .section-open #customize-info,
 .in-sub-panel #customize-info,
-.animating.section-open.in-sub-panel #customize-theme-controls .customize-pane-parent,
-.animating.section-open.in-sub-panel #customize-info, {
+.section-open.in-sub-panel #customize-theme-controls .customize-pane-child.current-panel {
 	visibility: hidden;
 }
 
-.animating.section-open #customize-theme-controls .customize-pane-parent,
-.animating.in-sub-panel #customize-theme-controls .customize-pane-parent,
-.animating.section-open #customize-info,
-.animating.in-sub-panel #customize-info {
+.section-open #customize-theme-controls .customize-pane-parent.closing,
+.in-sub-panel #customize-theme-controls .customize-pane-parent.closing,
+.section-open #customize-info.closing,
+.in-sub-panel #customize-info.closing,
+.transitioning.section-open.in-sub-panel #customize-theme-controls .customize-pane-child.current-panel,
+#customize-theme-controls .customize-pane-child.open,
+#customize-theme-controls .customize-pane-child.current-panel,
+#customize-theme-controls .customize-pane-child.closing {
 	visibility: visible;
 }
 
@@ -284,20 +286,6 @@ body {
 	padding: 12px;
 }
 
-#customize-theme-controls .customize-pane-child.open,
-#customize-theme-controls .customize-pane-child.current-panel {
-	transform: translateX(0);
-}
-
-#customize-theme-controls .customize-pane-child.open,
-#customize-theme-controls .customize-pane-child.current-panel,
-#customize-theme-controls .customize-pane-child.animating {
-	visibility: visible;
-}
-
-
-
-
 .customize-section-description-container {
 	margin-bottom: 15px;
 }
diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
index ce4e83c..1c1ec8e 100644
--- a/src/wp-admin/js/customize-controls.js
+++ b/src/wp-admin/js/customize-controls.js
@@ -1,6 +1,25 @@
 /* global _wpCustomizeHeader, _wpCustomizeBackground, _wpMediaViewsL10n, MediaElementPlayer */
 (function( exports, $ ){
-	var Container, focus, api = wp.customize;
+	var Container, focus, normalizedTransitionendEventName, api = wp.customize;
+
+	normalizedTransitionendEventName = (function () {
+		var el, transitions, prop;
+		el = document.createElement( 'div' );
+		transitions = {
+			'transition'      : 'transitionend',
+			'OTransition'     : 'oTransitionEnd',
+			'MozTransition'   : 'transitionend',
+			'WebkitTransition': 'webkitTransitionEnd'
+		};
+		prop = _.find( _.keys( transitions ), function( prop ) {
+			return ! _.isUndefined( el.style[ prop ] );
+		} );
+		if ( prop ) {
+			return transitions[ prop ];
+		} else {
+			return null;
+		}
+	})();
 
 	/**
 	 * A Customizer Setting.
@@ -610,10 +629,9 @@
 					api.panel( panelId, function ( panel ) {
 						// The panel has been registered, wait for it to become ready/initialized
 						panel.deferred.embedded.done( function () {
-							parentContainer = panel.content; // panel.container.find( 'ul:first' );
+							parentContainer = panel.content;
 							if ( ! section.container.parent().is( parentContainer ) ) {
 								parentContainer.append( section.container );
-								//section.setOwnership( section.content.attr( 'id' ) );
 								container.append( section.content );
 							}
 							section.deferred.embedded.resolve();
@@ -631,13 +649,6 @@
 			};
 			section.panel.bind( inject );
 			inject( section.panel.get() ); // Since a section may never get a panel, assume that it won't ever get one
-
-			section.deferred.embedded.done(function() {
-				// Fix the top margin after reflow.
-				api.bind( 'pane-contents-reflowed', _.debounce( function() {
-					section._recalculateTopMargin();
-				}, 100 ) );
-			});
 		},
 
 		/**
@@ -650,7 +661,6 @@
 				expandCollapseEventTypes = 'click keydown',
 				expandCollapseEventHandler,
 				overlay = section.content.closest( '.wp-full-overlay' );
-				//normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
 
 			// Expand/Collapse accordion sections on click.
 			expandCollapseEventHandler = function ( event ) {
@@ -668,11 +678,6 @@
 
 			section.container.find( '.accordion-section-title' ).on( expandCollapseEventTypes, expandCollapseEventHandler );
 			section.content.find( '.customize-section-back' ).on( expandCollapseEventTypes, expandCollapseEventHandler );
-
-			// section.content.on( normalizedTransitionendEventName, function() {
-			// 	section.content.removeClass( 'animating' );
-			// 	overlay.removeClass( 'animating' );
-			// });
 		},
 
 		/**
@@ -716,58 +721,39 @@
 		onChangeExpanded: function ( expanded, args ) {
 			var section = this,
 				container = section.container.closest( '.wp-full-overlay-sidebar-content' ),
-				content = section.content, //section.container.find( '.accordion-section-content' ),
+				content = section.content,
 				overlay = section.container.closest( '.wp-full-overlay' ),
-				backBtn = content.find( '.customize-section-back' ), //section.container.find( '.customize-section-back' ),
-				sectionTitle = content.find( '.accordion-section-title' ).first(), // section.container.find( '.accordion-section-title' ).first(),
-				// headerActionsHeight = $( '#customize-header-actions' ).height(),
-				// resizeContentHeight,
-				normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent(),
-				expand, position, scroll;
-
-			// if ( expanded && ! section.container.hasClass( 'open' ) ) {
+				info = overlay.find( '#customize-info' ),
+				parent = overlay.find( '.customize-pane-parent' ),
+				backBtn = content.find( '.customize-section-back' ),
+				sectionTitle = content.find( '.accordion-section-title' ).first(),
+				expand;
+
 			if ( expanded && ! content.hasClass( 'open' ) ) {
 
 				if ( args.unchanged ) {
 					expand = args.completeCallback;
 				} else {
 					container.scrollTop( 0 );
-					// resizeContentHeight = function() {
-					// 	var matchMedia, offset;
-					// 	matchMedia = window.matchMedia || window.msMatchMedia;
-					// 	offset = 90; // 45px for customize header actions + 45px for footer actions.
-
-					// 	// No footer on small screens.
-					// 	if ( matchMedia && matchMedia( '(max-width: 640px)' ).matches ) {
-					// 		offset = 45;
-					// 	}
-					// 	content.css( 'height', ( window.innerHeight - offset ) );
-					// };
 					expand = function() {
-						// section.container.addClass( 'open' );
+						content.one( normalizedTransitionendEventName, function () {
+							info.removeClass( 'closing' );
+							parent.removeClass( 'closing' );
+							overlay.removeClass( 'transitioning' );
+							backBtn.focus();
+						} );
+
 						content.addClass( 'open' );
-						overlay.addClass( 'section-open' );
-						content.addClass( 'animating' );
-						overlay.addClass( 'animating' );
-						content.one( normalizedTransitionendEventName, function() {
-							content.removeClass( 'animating' );
-							overlay.removeClass( 'animating' );
-						});
-						// position = content.offset().top;
-						// scroll = container.scrollTop();
-						// content.css( 'margin-top', ( headerActionsHeight - position - scroll ) );
-						// resizeContentHeight();
+						info.addClass( 'closing' );
+						parent.addClass( 'closing' );
+						overlay.addClass( 'section-open transitioning' );
+
 						sectionTitle.attr( 'tabindex', '-1' );
 						backBtn.attr( 'tabindex', '0' );
-						// backBtn.focus();
+
 						if ( args.completeCallback ) {
 							args.completeCallback();
 						}
-
-						// Fix the height after browser resize.
-						// $( window ).on( 'resize.customizer-section', _.debounce( resizeContentHeight, 100 ) );
-
-						section._recalculateTopMargin();
 					};
 				}
 
@@ -791,51 +777,32 @@
 					expand();
 				}
 
-			// } else if ( ! expanded && section.container.hasClass( 'open' ) ) {
 			} else if ( ! expanded && content.hasClass( 'open' ) ) {
-				// section.container.removeClass( 'open' );
-				content.removeClass( 'open' );
-				overlay.removeClass( 'section-open' );
-				content.addClass( 'animating' );
-				overlay.addClass( 'animating' );
-				content.one( normalizedTransitionendEventName, function() {
-					content.removeClass( 'animating' );
-					overlay.removeClass( 'animating' );
-				});
-				// content.css( 'margin-top', '' );
-				// container.scrollTop( 0 );
+
+				content.one( normalizedTransitionendEventName, function () {
+					content.removeClass( 'closing' );
+					info.removeClass( 'closing' );
+					parent.removeClass( 'closing' );
+					overlay.removeClass( 'transitioning' );
+					sectionTitle.focus();
+				} );
+
+				content.removeClass( 'open' ).addClass( 'closing' );
+				info.addClass( 'closing' );
+				parent.addClass( 'closing' );
+				overlay.removeClass( 'section-open transitioning' );
+
 				backBtn.attr( 'tabindex', '-1' );
 				sectionTitle.attr( 'tabindex', '0' );
-				// sectionTitle.focus();
+
 				if ( args.completeCallback ) {
 					args.completeCallback();
 				}
-				// $( window ).off( 'resize.customizer-section' );
 			} else {
 				if ( args.completeCallback ) {
 					args.completeCallback();
 				}
 			}
-		},
-
-		/**
-		 * Recalculate the top margin.
-		 *
-		 * @since 4.4.0
-		 * @private
-		 */
-		_recalculateTopMargin: function() {
-			return;
-			// var section = this, content, offset, headerActionsHeight;
-			// content = section.container.find( '.accordion-section-content' );
-			// if ( 0 === content.length ) {
-			// 	return;
-			// }
-			// headerActionsHeight = $( '#customize-header-actions' ).height();
-			// offset = ( content.offset().top - headerActionsHeight );
-			// if ( 0 < offset ) {
-			// 	content.css( 'margin-top', ( parseInt( content.css( 'margin-top' ), 10 ) - offset ) );
-			// }
 		}
 	});
 
@@ -1312,10 +1279,6 @@
 				panel.renderContent();
 			}
 
-			// api.bind( 'pane-contents-reflowed', _.debounce( function() {
-			// 	panel._recalculateTopMargin();
-			// }, 100 ) );
-
 			panel.deferred.embedded.resolve();
 		},
 
@@ -1325,7 +1288,6 @@
 		attachEvents: function () {
 			var meta, panel = this,
 				overlay = panel.content.closest( '.wp-full-overlay' );
-				//normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
 
 			// Expand/Collapse accordion sections on click.
 			panel.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
@@ -1340,7 +1302,6 @@
 			});
 
 			// Close panel.
-			// panel.container.find( '.customize-panel-back' ).on( 'click keydown', function( event ) {
 			panel.content.find( '.customize-panel-back' ).on( 'click keydown', function( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
@@ -1360,7 +1321,6 @@
 				}
 				event.preventDefault(); // Keep this AFTER the key filter above
 
-				// meta = panel.container.find( '.panel-meta' );
 				if ( meta.hasClass( 'cannot-expand' ) ) {
 					return;
 				}
@@ -1376,12 +1336,6 @@
 					$( this ).attr( 'aria-expanded', true );
 				}
 			});
-
-			// panel.content.on( normalizedTransitionendEventName, function() {
-			// 	panel.content.removeClass( 'animating' );
-			// 	overlay.removeClass( 'animating' );
-			// });
-
 		},
 
 		/**
@@ -1435,21 +1389,17 @@
 			}
 
 			// Note: there is a second argument 'args' passed
-			var position, scroll,
-				panel = this,
-				accordionSection = panel.content; // .closest( '.accordion-section' ),
+			var panel = this,
+				accordionSection = panel.content,
 				overlay = accordionSection.closest( '.wp-full-overlay' ),
 				container = accordionSection.closest( '.wp-full-overlay-sidebar-content' ),
-				siblings = container.find( '.open' ),
-				// topPanel = overlay.find( '#customize-theme-controls > ul > .accordion-section > .accordion-section-title' ),
+				info = overlay.find( '#customize-info' ),
+				parent = overlay.find( '.customize-pane-parent' ),
 				topPanel = accordionSection.find( '.accordion-section-title' ),
 				backBtn = accordionSection.find( '.customize-panel-back' ),
-				panelTitle = accordionSection.find( '.accordion-section-title' ).first(),
-				normalizedTransitionendEventName = api.utils.getNormalizedTransitionendEvent();
-				// content = panel.content, // accordionSection.find( '.control-panel-content' ),
-				// headerActionsHeight = $( '#customize-header-actions' ).height();
+				panelTitle = accordionSection.find( '.accordion-section-title' ).first();
 
-			if ( expanded ) {
+			if ( expanded && ! accordionSection.hasClass( 'current-panel' ) ) {
 
 				// Collapse any sibling sections/panels
 				api.section.each( function ( section ) {
@@ -1463,67 +1413,52 @@
 					}
 				});
 
-				// content.show( 0, function() {
-					// content.parent().show();
-					// position = content.offset().top;
-					// scroll = container.scrollTop();
-					// content.css( 'margin-top', ( headerActionsHeight - position - scroll ) );
-					accordionSection.addClass( 'current-panel' );
-					overlay.addClass( 'in-sub-panel' );
-					accordionSection.addClass( 'animating' );
-					overlay.addClass( 'animating' );
-					accordionSection.one( normalizedTransitionendEventName, function() {
-						accordionSection.removeClass( 'animating' );
-						overlay.removeClass( 'animating' );
-					});
-					// container.scrollTop( 0 );
-					if ( args.completeCallback ) {
-						args.completeCallback();
-					}
-				// } );
+				accordionSection.one( normalizedTransitionendEventName, function () {
+					info.removeClass( 'closing' );
+					parent.removeClass( 'closing' );
+					overlay.removeClass( 'transitioning' );
+					backBtn.focus();
+				} );
+
+				accordionSection.addClass( 'current-panel' );
+				info.addClass( 'closing' );
+				parent.addClass( 'closing' );
+				overlay.addClass( 'in-sub-panel transitioning' );
+
+				container.scrollTop( 0 );
+				if ( args.completeCallback ) {
+					args.completeCallback();
+				}
+
 				topPanel.attr( 'tabindex', '-1' );
 				backBtn.attr( 'tabindex', '0' );
-				// backBtn.focus();
-				// panel._recalculateTopMargin();
-			} else {
-				siblings.removeClass( 'open' );
-				accordionSection.removeClass( 'current-panel' );
-				overlay.removeClass( 'in-sub-panel' );
-				accordionSection.addClass( 'animating' );
-				overlay.addClass( 'animating' );
-				accordionSection.one( normalizedTransitionendEventName, function() {
-					accordionSection.removeClass( 'animating' );
-					overlay.removeClass( 'animating' );
-				});
-				// content.delay( 180 ).hide( 0, function() {
-				// 	content.css( 'margin-top', 'inherit' ); // Reset
-					if ( args.completeCallback ) {
-						args.completeCallback();
-					}
-				// } );
+
+			} else if ( ! expanded && accordionSection.hasClass( 'current-panel' ) ) {
+				accordionSection.one( normalizedTransitionendEventName, function () {
+					accordionSection.removeClass( 'closing' );
+					info.removeClass( 'closing' );
+					parent.removeClass( 'closing' );
+					overlay.removeClass( 'transitioning' );
+					panelTitle.focus();
+				} );
+
+				accordionSection.removeClass( 'current-panel' ).addClass( 'closing' );
+				info.addClass( 'closing' );
+				parent.addClass( 'closing' );
+				overlay.removeClass( 'in-sub-panel' ).addClass( 'transitioning' );
+
+				if ( args.completeCallback ) {
+					args.completeCallback();
+				}
+
 				topPanel.attr( 'tabindex', '0' );
 				backBtn.attr( 'tabindex', '-1' );
-				// panelTitle.focus();
+
 				container.scrollTop( 0 );
 			}
 		},
 
 		/**
-		 * Recalculate the top margin.
-		 *
-		 * @since 4.4.0
-		 * @private
-		 */
-		_recalculateTopMargin: function() {
-			return;
-			// var panel = this, headerActionsHeight, content, accordionSection;
-			// headerActionsHeight = $( '#customize-header-actions' ).height();
-			// accordionSection = panel.container.closest( '.accordion-section' );
-			// content = accordionSection.find( '.control-panel-content' );
-			// content.css( 'margin-top', ( parseInt( content.css( 'margin-top' ), 10 ) - ( content.offset().top - headerActionsHeight ) ) );
-		},
-
-		/**
 		 * Render the panel from its JS template, if it exists.
 		 *
 		 * The panel's container must already exist in the DOM.

From 04662b902d6db816876c7b5a4568a6f66268087d Mon Sep 17 00:00:00 2001
From: Piotr Delawski <piotr.delawski@xwp.co>
Date: Sun, 28 Feb 2016 20:45:17 +0100
Subject: [PATCH 4/9] WIP. Make themes panel work. Fix minor issues with scroll
 bar. Still pending code cleanup and cross-browser testing.

---
 src/wp-admin/css/customize-controls.css | 121 +++++++++++++++-------------
 src/wp-admin/js/customize-controls.js   | 135 +++++++++++++++++---------------
 2 files changed, 140 insertions(+), 116 deletions(-)

diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css
index 1ae1aa2..60b4000 100644
--- a/src/wp-admin/css/customize-controls.css
+++ b/src/wp-admin/css/customize-controls.css
@@ -227,13 +227,16 @@ body {
 	-webkit-box-sizing: border-box;
 	-moz-box-sizing: border-box;
 	box-sizing: border-box;
-	transition: 0.36s transform cubic-bezier(0.19, 1, 0.22, 1); /* http://easings.net/#easeOutExpo */
+	transition: 0.48s transform cubic-bezier(0.19, 1, 0.22, 1); /* easeOutExpo */
 }
 
 #customize-info,
 #customize-theme-controls .customize-pane-parent {
 	position: relative;
 	visibility: visible;
+	height: auto;
+	max-height: none;
+	overflow: auto;
 	transform: translateX(0);
 }
 
@@ -245,9 +248,9 @@ body {
 	transform: translateX(-100%);
 }
 
-#customize-theme-controls .customize-pane-child.open,
-#customize-theme-controls .customize-pane-child.current-panel {
-	transform: translateX(0);
+.in-themes-panel #customize-theme-controls .customize-pane-parent,
+.in-themes-panel #customize-info {
+	transform: translateX(100%);
 }
 
 .section-open #customize-theme-controls .customize-pane-parent,
@@ -256,6 +259,8 @@ body {
 .in-sub-panel #customize-info,
 .section-open.in-sub-panel #customize-theme-controls .customize-pane-child.current-panel {
 	visibility: hidden;
+	height: 0;
+	overflow: hidden;
 }
 
 .section-open #customize-theme-controls .customize-pane-parent.closing,
@@ -267,6 +272,8 @@ body {
 #customize-theme-controls .customize-pane-child.current-panel,
 #customize-theme-controls .customize-pane-child.closing {
 	visibility: visible;
+	height: auto;
+	overflow: auto;
 }
 
 #customize-theme-controls .customize-pane-child {
@@ -275,6 +282,28 @@ body {
 	left: 0;
 	transform: translateX(100%);
 	visibility: hidden;
+	height: 0;
+	max-height: none;
+	overflow: hidden;
+}
+
+#customize-theme-controls .customize-pane-parent.closing,
+#customize-info.closing,
+#customize-theme-controls .customize-pane-child.closing {
+	max-height: 100%;
+}
+
+#customize-theme-controls .customize-pane-child.open,
+#customize-theme-controls .customize-pane-child.current-panel {
+	transform: translateX(0);
+}
+
+#customize-theme-controls .customize-themes-panel.customize-pane-child {
+	transform: translateX(-100%);
+}
+
+#customize-theme-controls .customize-themes-panel.customize-pane-child.current-panel {
+	transform: translateX(0);
 }
 
 #customize-theme-controls .customize-pane-child.accordion-section-content,
@@ -286,6 +315,11 @@ body {
 	padding: 12px;
 }
 
+.wp-full-overlay #customize-controls .wp-full-overlay-sidebar-content {
+	/* Promote to separate layer to avoid full-screen repaints */
+	transform: translate3d(0,0,0);
+}
+
 .customize-section-description-container {
 	margin-bottom: 15px;
 }
@@ -357,7 +391,7 @@ h3.customize-section-title {
 	transition: left 0s;
 }
 
-.accordion-sub-container.control-panel-content.animating {
+.accordion-sub-container.control-panel-content.closing {
 	display: block;
 }
 
@@ -479,30 +513,6 @@ h3.customize-section-title {
 	padding-left: 62px;
 }
 
-/*#customize-info,
-#customize-theme-controls > ul > .accordion-section {
-	position: relative;
-	left: 0;
-	-webkit-transition: left ease-in-out .18s;
-	transition: left ease-in-out .18s;
-}
-
-.ios #customize-info,
-.ios #customize-theme-controls > ul > .accordion-section {
-	-webkit-transition: left 0s;
-	transition: left 0s;
-}
-*/
-/*.in-sub-panel #customize-info,
-.in-sub-panel #customize-theme-controls > ul > .accordion-section {
-	left: -300px;
-	width: 300px;
-}*/
-
-/*.in-sub-panel #customize-theme-controls .accordion-section.current-panel {
-	width: 100%;
-}
-*/
 #customize-theme-controls .control-section.current-panel {
 	padding: 0;
 }
@@ -523,11 +533,11 @@ h3.customize-section-title {
 	transition: left 0s;
 }
 
-.wp-full-overlay.section-open #customize-controls .wp-full-overlay-sidebar-content {
+/*.wp-full-overlay.section-open #customize-controls .wp-full-overlay-sidebar-content {
 	visibility: hidden;
 	overflow-y: hidden;
 }
-
+*/
 /*.wp-full-overlay.section-open .wp-full-overlay-sidebar-content .accordion-section.open {
 	visibility: visible;
 }
@@ -1089,7 +1099,7 @@ p.customize-section-description {
 	animation: customize-reload .75s;
 }
 
-.control-section-themes .accordion-section-title {
+#customize-controls .control-section-themes .accordion-section-title {
 	cursor: default;
 }
 
@@ -1099,27 +1109,28 @@ p.customize-section-description {
 	background-color: #fff;
 }
 
-.control-section-themes .accordion-section-title {
+#customize-controls .control-section-themes .accordion-section-title {
 	margin: 15px 0;
 }
 
-.customize-themes-panel .accordion-section-title {
+#customize-controls .customize-themes-panel .accordion-section-title {
 	margin: 15px -8px;
 }
 
-.control-section-themes .accordion-section-title {
+#customize-controls .control-section-themes .accordion-section-title,
+#customize-controls .customize-themes-panel .accordion-section-title {
 	padding-right: 100px; /* Space for the button */
 }
 
-.control-section-themes .accordion-section-title span.customize-action,
+#customize-controls .control-section-themes .accordion-section-title span.customize-action,
 #customize-controls .customize-section-title span.customize-action {
 	font-size: 13px;
 	display: block;
 	font-weight: 400;
 }
 
-.control-section-themes .accordion-section-title .change-theme,
-.control-section-themes .accordion-section-title .customize-theme {
+#customize-controls .control-section-themes .accordion-section-title .change-theme,
+#customize-controls .customize-themes-panel .accordion-section-title .customize-theme {
 	position: absolute;
 	right: 10px;
 	top: 50%;
@@ -1127,12 +1138,11 @@ p.customize-section-description {
 	font-weight: normal;
 }
 
-.control-section-themes .accordion-section-title:before {
+#customize-controls .control-section-themes .accordion-section-title:before {
 	display: none;
 }
 
-.customize-themes-panel {
-	display: none;
+#customize-controls .customize-themes-panel {
 	padding: 0 8px;
 	background: #f1f1f1;
 	-webkit-box-sizing: border-box;
@@ -1140,7 +1150,7 @@ p.customize-section-description {
 	box-sizing: border-box;
 }
 
-.customize-themes-panel .accordion-section-title:first-child {
+#customize-controls .customize-themes-panel .accordion-section-title:first-child {
 	margin-top: 0;
 }
 
@@ -1149,13 +1159,13 @@ p.customize-section-description {
 	font-weight: 600;
 }
 
-.customize-themes-panel > h2 {
+#customize-controls .customize-themes-panel > h2 {
 	padding: 15px 8px 0 8px;
 }
 
-.control-section.open .customize-themes-panel {
+/*.control-section.open .customize-themes-panel {
 	display: block;
-}
+}*/
 
 #customize-theme-controls .customize-themes-panel .accordion-section-content {
 	background: transparent;
@@ -1202,26 +1212,28 @@ p.customize-section-description {
 	width: 100%;
 }
 
-#accordion-section-themes .accordion-section-title:after {
+/*#accordion-section-themes .accordion-section-title:after {*/
+.control-section-themes .accordion-section-title:after,
+.customize-themes-panel .accordion-section-title:after {
 	display: none;
 }
 
-#customize-theme-controls .control-section-themes.current-panel > h3.accordion-section-title {
+/*#customize-theme-controls .control-section-themes.current-panel > h3.accordion-section-title {
 	left: 0;
-}
+}*/
 
 .customize-themes-panel.control-panel-content {
-	position: absolute;
+/*	position: absolute;
 	left: -100%;
 	top: 0;
-	width: 100%;
+	width: 100%;*/
 	border-top: 1px solid #ddd;
 }
 
-.in-themes-panel #customize-info,
+/*.in-themes-panel #customize-info,
 .in-themes-panel #customize-theme-controls > ul > .accordion-section {
 	left: 100%;
-}
+}*/
 
 /* Details View */
 .wp-customizer .theme-overlay {
@@ -1256,8 +1268,9 @@ p.customize-section-description {
 	text-align: right; /* Because there's only one action, match the pattern of media modals and right-align the action. */
 }
 
-.modal-open .in-themes-panel #customize-controls .wp-full-overlay-sidebar-content {
-	overflow: visible; /* Prevent the top-level Customizer controls from becoming visible when elements on the right of the details modal are focused. */
+.in-themes-panel #customize-controls .wp-full-overlay-sidebar-content,
+.in-themes-panel #customize-controls #customize-theme-controls .control-panel-content {
+	transform: none; /* Prevent creating new stacking contexts and containing blocks for themes modal. */
 }
 
 .ie8 .wp-customizer .theme-overlay .theme-header,
diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
index 2b5a7a3..249114b 100644
--- a/src/wp-admin/js/customize-controls.js
+++ b/src/wp-admin/js/customize-controls.js
@@ -257,7 +257,6 @@
 			if ( 0 === container.container.length ) {
 				container.container = $( container.getContainer() );
 			}
-
 			container.content = container.getContent();
 
 			container.deferred = {
@@ -529,9 +528,14 @@
 			return '<li></li>';
 		},
 
+		/**
+		 * Detach and return the content html, extracted from the container html, if it exists.
+		 *
+		 * @since 
+		 */
 		getContent: function () {
 			var container = this,
-				list = container.container.find( 'ul:first' ),
+				list = container.container.find( '.accordion-section-content, .control-panel-content' ).first(), // container.container.find( 'ul:first' ),
 				contentId = 'sub-accordion-list-' + container.id;
 
 			container.setOwnership( contentId );
@@ -542,6 +546,11 @@
 			} );
 		},
 
+		/**
+		 * Add new element to `aria-owned` property of the container. 
+		 *
+		 * @since 
+		 */
 		setOwnership: function ( elementId ) {
 			var container = this.container,
 				ownedElements = container.attr( 'aria-owns' );
@@ -658,12 +667,10 @@
 		 */
 		attachEvents: function () {
 			var section = this,
-				expandCollapseEventTypes = 'click keydown',
-				expandCollapseEventHandler,
-				overlay = section.content.closest( '.wp-full-overlay' );
+				toggleHandler;
 
 			// Expand/Collapse accordion sections on click.
-			expandCollapseEventHandler = function ( event ) {
+			toggleHandler = function ( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
 				}
@@ -676,8 +683,8 @@
 				}
 			};
 
-			section.container.find( '.accordion-section-title' ).on( expandCollapseEventTypes, expandCollapseEventHandler );
-			section.content.find( '.customize-section-back' ).on( expandCollapseEventTypes, expandCollapseEventHandler );
+			section.container.find( '.accordion-section-title' ).on( 'click keydown', toggleHandler );
+			section.content.find( '.customize-section-back' ).on( 'click keydown', toggleHandler );
 		},
 
 		/**
@@ -836,7 +843,7 @@
 		 */
 		ready: function () {
 			var section = this;
-			section.overlay = section.container.find( '.theme-overlay' );
+			section.overlay = section.content.find( '.theme-overlay' );
 			section.template = wp.template( 'customize-themes-details-view' );
 
 			// Bind global keyboard events.
@@ -883,10 +890,12 @@
 		 * @since 4.2.0
 		 */
 		attachEvents: function () {
-			var section = this;
+			var section = this,
+				content = section.content,
+				toggleHandler;
 
 			// Expand/Collapse section/panel.
-			section.container.find( '.change-theme, .customize-theme' ).on( 'click keydown', function( event ) {
+			toggleHandler = function ( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
 				}
@@ -897,10 +906,13 @@
 				} else {
 					section.expand();
 				}
-			});
+			};
+
+			section.container.find( '.change-theme' ).on( 'click keydown', toggleHandler );
+			content.find( '.customize-theme' ).on( 'click keydown', toggleHandler );
 
 			// Theme navigation in details view.
-			section.container.on( 'click keydown', '.left', function( event ) {
+			content.on( 'click keydown', '.left', function( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
 				}
@@ -910,7 +922,7 @@
 				section.previousTheme();
 			});
 
-			section.container.on( 'click keydown', '.right', function( event ) {
+			content.on( 'click keydown', '.right', function( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
 				}
@@ -920,7 +932,7 @@
 				section.nextTheme();
 			});
 
-			section.container.on( 'click keydown', '.theme-backdrop, .close', function( event ) {
+			content.on( 'click keydown', '.theme-backdrop, .close', function( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
 				}
@@ -931,7 +943,7 @@
 			});
 
 			var renderScreenshots = _.throttle( _.bind( section.renderScreenshots, this ), 100 );
-			section.container.on( 'input', '#themes-filter', function( event ) {
+			content.on( 'input', '#themes-filter', function( event ) {
 				var count,
 					term = event.currentTarget.value.toLowerCase().trim().replace( '-', ' ' ),
 					controls = section.controls();
@@ -943,8 +955,8 @@
 				renderScreenshots();
 
 				// Update theme count.
-				count = section.container.find( 'li.customize-control:visible' ).length;
-				section.container.find( '.theme-count' ).text( count );
+				count = content.find( 'li.customize-control:visible' ).length;
+				content.find( '.theme-count' ).text( count );
 			});
 
 			// Pre-load the first 3 theme screenshots.
@@ -980,18 +992,16 @@
 			}
 
 			// Note: there is a second argument 'args' passed
-			var position, scroll,
-				panel = this,
-				section = panel.container.closest( '.accordion-section' ),
+			var panel = this,
+				section = panel.content,
 				overlay = section.closest( '.wp-full-overlay' ),
 				container = section.closest( '.wp-full-overlay-sidebar-content' ),
-				siblings = container.find( '.open' ),
+				info = overlay.find( '#customize-info' ),
+				parent = overlay.find( '.customize-pane-parent' ),
 				customizeBtn = section.find( '.customize-theme' ),
-				changeBtn = section.find( '.change-theme' ),
-				content = section.find( '.control-panel-content' );
+				changeBtn = section.find( '.change-theme' );
 
 			if ( expanded ) {
-
 				// Collapse any sibling sections/panels
 				api.section.each( function ( otherSection ) {
 					if ( otherSection !== panel ) {
@@ -1002,49 +1012,50 @@
 					otherPanel.collapse( { duration: 0 } );
 				});
 
-				content.show( 0, function() {
-					position = content.offset().top;
-					scroll = container.scrollTop();
-					content.css( 'margin-top', ( $( '#customize-header-actions' ).height() - position - scroll ) );
-					section.addClass( 'current-panel' );
-					overlay.addClass( 'in-themes-panel' );
-					container.scrollTop( 0 );
-					_.delay( panel.renderScreenshots, 10 ); // Wait for the controls
-					panel.$customizeSidebar.on( 'scroll.customize-themes-section', _.throttle( panel.renderScreenshots, 300 ) );
-					if ( args.completeCallback ) {
-						args.completeCallback();
-					}
+				section.one( normalizedTransitionendEventName, function () {
+					info.removeClass( 'closing' );
+					parent.removeClass( 'closing' );
+					overlay.removeClass( 'transitioning' );
+					customizeBtn.focus();
+					_.delay( panel.renderScreenshots, 10 );
 				} );
-				customizeBtn.focus();
+
+				section.addClass( 'current-panel' );
+				info.addClass( 'closing' );
+				parent.addClass( 'closing' );
+				overlay.addClass( 'in-themes-panel transitioning' );
+
+				container.scrollTop( 0 );
+				panel.$customizeSidebar.on( 'scroll.customize-themes-section', _.throttle( panel.renderScreenshots, 300 ) );
+
+				if ( args.completeCallback ) {
+					args.completeCallback();
+				}
 			} else {
-				siblings.removeClass( 'open' );
-				section.removeClass( 'current-panel' );
-				overlay.removeClass( 'in-themes-panel' );
-				panel.$customizeSidebar.off( 'scroll.customize-themes-section' );
-				content.delay( 180 ).hide( 0, function() {
-					content.css( 'margin-top', 'inherit' ); // Reset
-					if ( args.completeCallback ) {
-						args.completeCallback();
-					}
+				section.one( normalizedTransitionendEventName, function () {
+					section.removeClass( 'closing' );
+					info.removeClass( 'closing' );
+					parent.removeClass( 'closing' );
+					overlay.removeClass( 'transitioning' );
+					changeBtn.focus();
 				} );
+
+				section.removeClass( 'current-panel' ).addClass( 'closing' );
+				info.addClass( 'closing' );
+				parent.addClass( 'closing' );
+				overlay.removeClass( 'in-themes-panel' ).addClass( 'transitioning' );
+				panel.$customizeSidebar.off( 'scroll.customize-themes-section' );
+
 				customizeBtn.attr( 'tabindex', '0' );
-				changeBtn.focus();
 				container.scrollTop( 0 );
+				
+				if ( args.completeCallback ) {
+					args.completeCallback();
+				}
 			}
 		},
 
 		/**
-		 * Recalculate the top margin.
-		 *
-		 * @since 4.4.0
-		 * @private
-		 */
-		_recalculateTopMargin: function() {
-			return;
-			// api.Panel.prototype._recalculateTopMargin.call( this );
-		},
-
-		/**
 		 * Render control's screenshot if the control comes into view.
 		 *
 		 * @since 4.2.0
@@ -1609,7 +1620,7 @@
 				api.section( sectionId, function ( section ) {
 					// Wait for the section to be ready/initialized
 					section.deferred.embedded.done( function () {
-						parentContainer = section.content; // section.container.find( 'ul:first' );
+						parentContainer = ( section.content.is( 'ul' ) ) ? section.content : section.content.find( 'ul:first' );
 						if ( ! control.container.parent().is( parentContainer ) ) {
 							parentContainer.append( control.container );
 							control.renderContent();
@@ -3507,7 +3518,7 @@
 				var sections = panel.sections(),
 					sectionContainers = _.pluck( sections, 'container' );
 				rootNodes.push( panel );
-				appendContainer = panel.content; // panel.container.find( 'ul:first' );
+				appendContainer = ( panel.content.is( 'ul' ) ) ? panel.content : panel.content.find( 'ul:first' );
 				if ( ! api.utils.areElementListsEqual( sectionContainers, appendContainer.children( '[id]' ) ) ) {
 					_( sections ).each( function ( section ) {
 						appendContainer.append( section.container );
@@ -3523,7 +3534,7 @@
 				if ( ! section.panel() ) {
 					rootNodes.push( section );
 				}
-				appendContainer = section.content; // section.container.find( 'ul:first' );
+				appendContainer = ( section.content.is( 'ul' ) ) ? section.content : section.content.find( 'ul:first' );
 				if ( ! api.utils.areElementListsEqual( controlContainers, appendContainer.children( '[id]' ) ) ) {
 					_( controls ).each( function ( control ) {
 						appendContainer.append( control.container );

From 667947a73e80266d8ea7d1605e1a3bf31e21d613 Mon Sep 17 00:00:00 2001
From: Piotr Delawski <piotr.delawski@xwp.co>
Date: Sat, 5 Mar 2016 21:24:21 +0100
Subject: [PATCH 5/9] Fix 'Menus' panel to work with new sliding panes
 implementation. Fix `tabindex` and `focus` implementation.

---
 src/wp-admin/css/customize-controls.css  |  1 +
 src/wp-admin/css/customize-nav-menus.css |  8 +++---
 src/wp-admin/js/customize-controls.js    | 19 +++++++-------
 src/wp-admin/js/customize-nav-menus.js   | 43 ++++++++++++++++++++------------
 4 files changed, 42 insertions(+), 29 deletions(-)

diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css
index b1b6ef5..8a92ba2 100644
--- a/src/wp-admin/css/customize-controls.css
+++ b/src/wp-admin/css/customize-controls.css
@@ -309,6 +309,7 @@ body {
 #customize-theme-controls .customize-pane-child.accordion-section-content,
 #customize-theme-controls .customize-pane-child.accordion-sub-container {
 	display: block;
+	overflow-x: hidden;
 }
 
 #customize-theme-controls .customize-pane-child.accordion-section-content {
diff --git a/src/wp-admin/css/customize-nav-menus.css b/src/wp-admin/css/customize-nav-menus.css
index 16480e9..5f07560 100644
--- a/src/wp-admin/css/customize-nav-menus.css
+++ b/src/wp-admin/css/customize-nav-menus.css
@@ -355,15 +355,15 @@
 .reordering .menu-item-depth-10 > .menu-item-bar { margin-right: 150px; }
 .reordering .menu-item-depth-11 > .menu-item-bar { margin-right: 165px; }
 
-.control-section-nav_menu .menu .menu-item-edit-active {
+.accordion-section-content.menu .menu-item-edit-active {
 	margin-left: 0;
 }
 
-.control-section-nav_menu .menu .menu-item-edit-active .menu-item-bar {
+.accordion-section-content.menu .menu-item-edit-active .menu-item-bar {
 	margin-right: 0;
 }
 
-.control-section-nav_menu .menu .sortable-placeholder {
+.accordion-section-content.menu .sortable-placeholder {
 	margin-top: 0;
 	margin-bottom: 1px;
 	max-width: -webkit-calc(100% - 2px);
@@ -377,7 +377,7 @@
 	float: none;
 }
 
-.control-section-nav_menu .menu ul.menu-item-transport .menu-item-bar {
+.accordion-section-content.menu ul.menu-item-transport .menu-item-bar {
 	margin-top: 0;
 }
 
diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
index 045cc57..09571a7 100644
--- a/src/wp-admin/js/customize-controls.js
+++ b/src/wp-admin/js/customize-controls.js
@@ -392,11 +392,6 @@
 					construct.container.stop( true, true ).slideUp( duration, args.completeCallback );
 				}
 			}
-
-			// Recalculate the margin-top immediately, not waiting for debounced reflow, to prevent momentary (100ms) vertical jiggle.
-			if ( expandedOtherPanel ) {
-				expandedOtherPanel._recalculateTopMargin();
-			}
 		},
 
 		/**
@@ -641,6 +636,8 @@
 							parentContainer = panel.content;
 							if ( ! section.container.parent().is( parentContainer ) ) {
 								parentContainer.append( section.container );
+							}
+							if ( ! section.content.parent().is( section.container ) ) {
 								container.append( section.content );
 							}
 							section.deferred.embedded.resolve();
@@ -651,6 +648,8 @@
 					parentContainer = $( '.customize-pane-parent' ); // @todo This should be defined elsewhere, and to be configurable
 					if ( ! section.container.parent().is( parentContainer ) ) {
 						parentContainer.append( section.container );
+					}
+					if ( ! section.content.parent().is( section.container ) ) {
 						container.append( section.content );
 					}
 					section.deferred.embedded.resolve();
@@ -733,7 +732,7 @@
 				info = overlay.find( '#customize-info' ),
 				parent = overlay.find( '.customize-pane-parent' ),
 				backBtn = content.find( '.customize-section-back' ),
-				sectionTitle = content.find( '.accordion-section-title' ).first(),
+				sectionTitle = section.container.find( '.accordion-section-title' ).first(),
 				expand;
 
 			if ( expanded && ! content.hasClass( 'open' ) ) {
@@ -999,7 +998,7 @@
 				info = overlay.find( '#customize-info' ),
 				parent = overlay.find( '.customize-pane-parent' ),
 				customizeBtn = section.find( '.customize-theme' ),
-				changeBtn = section.find( '.change-theme' );
+				changeBtn = panel.container.find( '.change-theme' );
 
 			if ( expanded ) {
 				// Collapse any sibling sections/panels
@@ -1286,6 +1285,8 @@
 
 			if ( ! panel.container.parent().is( parentContainer ) ) {
 				parentContainer.append( panel.container );
+			}
+			if ( ! panel.content.parent().is( panel.container ) ) {
 				container.append( panel.content );
 				panel.renderContent();
 			}
@@ -1406,7 +1407,7 @@
 				container = accordionSection.closest( '.wp-full-overlay-sidebar-content' ),
 				info = overlay.find( '#customize-info' ),
 				parent = overlay.find( '.customize-pane-parent' ),
-				topPanel = accordionSection.find( '.accordion-section-title' ),
+				topPanel = panel.container.find( '.accordion-section-title' ),
 				backBtn = accordionSection.find( '.customize-panel-back' ),
 				panelTitle = accordionSection.find( '.accordion-section-title' ).first();
 
@@ -1450,7 +1451,7 @@
 					info.removeClass( 'closing' );
 					parent.removeClass( 'closing' );
 					overlay.removeClass( 'transitioning' );
-					panelTitle.focus();
+					topPanel.focus();
 				} );
 
 				accordionSection.removeClass( 'current-panel' ).addClass( 'closing' );
diff --git a/src/wp-admin/js/customize-nav-menus.js b/src/wp-admin/js/customize-nav-menus.js
index cad39c6..cdeeac4 100644
--- a/src/wp-admin/js/customize-nav-menus.js
+++ b/src/wp-admin/js/customize-nav-menus.js
@@ -539,7 +539,7 @@
 			api.Panel.prototype.attachEvents.call( this );
 
 			var panel = this,
-				panelMeta = panel.container.find( '.panel-meta' ),
+				panelMeta = panel.content.find( '.panel-meta' ),
 				help = panelMeta.find( '.customize-help-toggle' ),
 				content = panelMeta.find( '.customize-panel-description' ),
 				options = $( '#screen-options-wrap' ),
@@ -712,14 +712,14 @@
 
 			api.bind( 'pane-contents-reflowed', function() {
 				// Skip menus that have been removed.
-				if ( ! section.container.parent().length ) {
+				if ( ! section.content.parent().length ) {
 					return;
 				}
-				section.container.find( '.menu-item .menu-item-reorder-nav button' ).attr({ 'tabindex': '0', 'aria-hidden': 'false' });
-				section.container.find( '.menu-item.move-up-disabled .menus-move-up' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
-				section.container.find( '.menu-item.move-down-disabled .menus-move-down' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
-				section.container.find( '.menu-item.move-left-disabled .menus-move-left' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
-				section.container.find( '.menu-item.move-right-disabled .menus-move-right' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
+				section.content.find( '.menu-item .menu-item-reorder-nav button' ).attr({ 'tabindex': '0', 'aria-hidden': 'false' });
+				section.content.find( '.menu-item.move-up-disabled .menus-move-up' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
+				section.content.find( '.menu-item.move-down-disabled .menus-move-down' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
+				section.content.find( '.menu-item.move-left-disabled .menus-move-left' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
+				section.content.find( '.menu-item.move-right-disabled .menus-move-right' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
 			} );
 		},
 
@@ -830,7 +830,7 @@
 			var section = this;
 
 			if ( expanded ) {
-				wpNavMenu.menuList = section.container.find( '.accordion-section-content:first' );
+				wpNavMenu.menuList = section.content;
 				wpNavMenu.targetList = wpNavMenu.menuList;
 
 				// Add attributes needed by wpNavMenu
@@ -892,7 +892,7 @@
 		onChangeExpanded: function( expanded ) {
 			var section = this,
 				button = section.container.find( '.add-menu-toggle' ),
-				content = section.container.find( '.new-menu-section-content' ),
+				content = section.content,
 				customizer = section.container.closest( '.wp-full-overlay-sidebar-content' );
 			if ( expanded ) {
 				button.addClass( 'open' );
@@ -906,6 +906,15 @@
 				content.slideUp( 'fast' );
 				content.find( '.menu-name-field' ).removeClass( 'invalid' );
 			}
+		},
+
+		/**
+		 * Detach and return the content html, extracted from the container html, if it exists.
+		 *
+		 * @since 
+		 */
+		getContent: function () {
+			return this.container.find( 'ul:first' );
 		}
 	});
 
@@ -1797,6 +1806,7 @@
 		 */
 		ready: function() {
 			var control = this,
+				section = api.section( control.section() ),
 				menuId = control.params.menu_id,
 				menu = control.setting(),
 				name,
@@ -1813,7 +1823,7 @@
 			 * being deactivated.
 			 */
 			control.active.validate = function() {
-				var value, section = api.section( control.section() );
+				var value;
 				if ( section ) {
 					value = section.active();
 				} else {
@@ -1822,7 +1832,7 @@
 				return value;
 			};
 
-			control.$controlSection = control.container.closest( '.control-section' );
+			control.$controlSection = section.container;
 			control.$sectionContent = control.container.closest( '.accordion-section-content' );
 
 			this._setupModel();
@@ -2005,6 +2015,7 @@
 			section = api.section( control.section() );
 			removeSection = function() {
 				section.container.remove();
+				section.content.remove();
 				api.section.remove( section.id );
 			};
 
@@ -2096,11 +2107,11 @@
 					return;
 				}
 
-				var section = control.container.closest( '.accordion-section' ),
+				var section = api.section( control.section() ),
 					menuId = control.params.menu_id,
-					controlTitle = section.find( '.accordion-section-title' ),
-					sectionTitle = section.find( '.customize-section-title h3' ),
-					location = section.find( '.menu-in-location' ),
+					controlTitle = section.container.find( '.accordion-section-title' ),
+					sectionTitle = section.content.find( '.customize-section-title h3' ),
+					location = section.container.find( '.menu-in-location' ),
 					action = sectionTitle.find( '.customize-action' ),
 					name = displayNavMenuName( menu.name );
 
@@ -2124,7 +2135,7 @@
 				} );
 
 				// Update the nav menu name in all location checkboxes.
-				section.find( '.customize-control-checkbox input' ).each( function() {
+				section.content.find( '.customize-control-checkbox input' ).each( function() {
 					if ( $( this ).prop( 'checked' ) ) {
 						$( '.current-menu-location-name-' + $( this ).data( 'location-id' ) ).text( name );
 					}

From 0b64cfd4194259786eab51dc5fe9c20adf360c7e Mon Sep 17 00:00:00 2001
From: Piotr Delawski <piotr.delawski@xwp.co>
Date: Fri, 22 Apr 2016 18:57:56 +0200
Subject: [PATCH 6/9] Fix expanding/collapsing of Themes panel. Remove unused
 `getNormalizedTransitionendEvent` function.

---
 src/wp-admin/js/customize-controls.js | 56 ++++++++++++-----------------------
 1 file changed, 19 insertions(+), 37 deletions(-)

diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
index 74e8191..8e9fdad 100644
--- a/src/wp-admin/js/customize-controls.js
+++ b/src/wp-admin/js/customize-controls.js
@@ -2,25 +2,6 @@
 (function( exports, $ ){
 	var Container, focus, normalizedTransitionendEventName, api = wp.customize;
 
-	normalizedTransitionendEventName = (function () {
-		var el, transitions, prop;
-		el = document.createElement( 'div' );
-		transitions = {
-			'transition'      : 'transitionend',
-			'OTransition'     : 'oTransitionEnd',
-			'MozTransition'   : 'transitionend',
-			'WebkitTransition': 'webkitTransitionEnd'
-		};
-		prop = _.find( _.keys( transitions ), function( prop ) {
-			return ! _.isUndefined( el.style[ prop ] );
-		} );
-		if ( prop ) {
-			return transitions[ prop ];
-		} else {
-			return null;
-		}
-	})();
-
 	/**
 	 * A Customizer Setting.
 	 *
@@ -192,23 +173,24 @@
 	 *
 	 * @returns {String}
 	 */
-	api.utils.getNormalizedTransitionendEvent = function () {
-		var t,
-			undefined,
-			el = document.createElement( 'div' ),
-			transitions = {
-				'transition'      : 'transitionend',
-				'OTransition'     : 'oTransitionEnd',
-				'MozTransition'   : 'transitionend',
-				'WebkitTransition': 'webkitTransitionEnd'
-			};
-
-		for ( t in transitions ) {
-			if ( transitions.hasOwnProperty( t ) && undefined !== el.style[ t ] ) {
-				return transitions[t];
-			}
+	normalizedTransitionendEventName = (function () {
+		var el, transitions, prop;
+		el = document.createElement( 'div' );
+		transitions = {
+			'transition'      : 'transitionend',
+			'OTransition'     : 'oTransitionEnd',
+			'MozTransition'   : 'transitionend',
+			'WebkitTransition': 'webkitTransitionEnd'
+		};
+		prop = _.find( _.keys( transitions ), function( prop ) {
+			return ! _.isUndefined( el.style[ prop ] );
+		} );
+		if ( prop ) {
+			return transitions[ prop ];
+		} else {
+			return null;
 		}
-	};
+	})();
 
 	/**
 	 * Base class for Panel and Section.
@@ -1004,7 +986,7 @@
 				customizeBtn = section.find( '.customize-theme' ),
 				changeBtn = panel.container.find( '.change-theme' );
 
-			if ( expanded ) {
+			if ( expanded && ! section.hasClass( 'current-panel' ) ) {
 				// Collapse any sibling sections/panels
 				api.section.each( function ( otherSection ) {
 					if ( otherSection !== panel ) {
@@ -1034,7 +1016,7 @@
 				if ( args.completeCallback ) {
 					args.completeCallback();
 				}
-			} else {
+			} else if ( ! expanded && section.hasClass( 'current-panel' ) ) {
 				section.one( normalizedTransitionendEventName, function () {
 					section.removeClass( 'closing' );
 					info.removeClass( 'closing' );

From 128aeac27023e957db781cb6295679c059adec35 Mon Sep 17 00:00:00 2001
From: Piotr Delawski <piotr.delawski@xwp.co>
Date: Fri, 22 Apr 2016 20:36:12 +0200
Subject: [PATCH 7/9] Fix bugs related to focusing on control (particularly on
 shift+click).

---
 src/wp-admin/js/customize-controls.js | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
index 8e9fdad..3a6464b 100644
--- a/src/wp-admin/js/customize-controls.js
+++ b/src/wp-admin/js/customize-controls.js
@@ -77,26 +77,25 @@
 	 * @param {Function} [params.completeCallback]
 	 */
 	focus = function ( params ) {
-		var construct, completeCallback, focus, focusElement;
-		construct = this;
+		var construct = this,
+			completeCallback, focus;
+
 		params = params || {};
 		focus = function () {
-			var focusContainer;
-			if ( construct.extended( api.Panel ) && construct.expanded && construct.expanded() ) {
-				focusContainer = construct.container.find( 'ul.control-panel-content' );
-			} else if ( construct.extended( api.Section ) && construct.expanded && construct.expanded() ) {
-				focusContainer = construct.container.find( 'ul.accordion-section-content' );
-			} else {
-				focusContainer = construct.container;
-			}
+			var focusContainer = construct.container,
+				focusElement;
 
-			focusElement = focusContainer.find( '.control-focus:first' );
+			if ( ( construct.extended( api.Panel ) || construct.extended( api.Section ) ) && construct.expanded && construct.expanded() ) {
+				focusContainer = ( construct.content.is( 'ul' ) ) ? construct.content : construct.content.find( 'ul:first' );
+			}
+			focusElement = focusContainer.find( '.control-focus, input, select, textarea, button' ).filter( ':visible' ).first();
 			if ( 0 === focusElement.length ) {
 				// Note that we can't use :focusable due to a jQuery UI issue. See: https://github.com/jquery/jquery-ui/pull/1583
-				focusElement = focusContainer.find( 'input, select, textarea, button, object, a[href], [tabindex]' ).filter( ':visible' ).first();
+				focusElement = focusContainer.find( 'object, a[href], [tabindex]' ).filter( ':visible' ).first();
 			}
 			focusElement.focus();
 		};
+
 		if ( params.completeCallback ) {
 			completeCallback = params.completeCallback;
 			params.completeCallback = function () {
@@ -516,7 +515,7 @@
 		 */
 		getContent: function () {
 			var container = this,
-				list = container.container.find( '.accordion-section-content, .control-panel-content' ).first(), // container.container.find( 'ul:first' ),
+				list = container.container.find( '.accordion-section-content, .control-panel-content' ).first(),
 				contentId = 'sub-accordion-list-' + container.id;
 
 			container.setOwnership( contentId );
@@ -790,6 +789,7 @@
 				if ( args.completeCallback ) {
 					args.completeCallback();
 				}
+
 			} else {
 				if ( args.completeCallback ) {
 					args.completeCallback();

From 540e939472de426abbc4c9640c565c1086449132 Mon Sep 17 00:00:00 2001
From: Piotr Delawski <piotr.delawski@xwp.co>
Date: Wed, 4 May 2016 22:33:49 +0200
Subject: [PATCH 8/9] Clear jshint errors.

---
 src/wp-admin/js/customize-controls.js | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
index 245bf06..39de2d2 100644
--- a/src/wp-admin/js/customize-controls.js
+++ b/src/wp-admin/js/customize-controls.js
@@ -521,8 +521,8 @@
 			container.setOwnership( contentId );
 
 			return list.detach().attr( {
-				id: contentId,
-				class: 'customize-pane-child ' + list.attr( 'class' )
+				'id': contentId,
+				'class': 'customize-pane-child ' + list.attr( 'class' )
 			} );
 		},
 
@@ -1284,8 +1284,7 @@
 		 * @since 4.1.0
 		 */
 		attachEvents: function () {
-			var meta, panel = this,
-				overlay = panel.content.closest( '.wp-full-overlay' );
+			var meta, panel = this;
 
 			// Expand/Collapse accordion sections on click.
 			panel.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
@@ -1394,8 +1393,7 @@
 				info = overlay.find( '#customize-info' ),
 				parent = overlay.find( '.customize-pane-parent' ),
 				topPanel = panel.container.find( '.accordion-section-title' ),
-				backBtn = accordionSection.find( '.customize-panel-back' ),
-				panelTitle = accordionSection.find( '.accordion-section-title' ).first();
+				backBtn = accordionSection.find( '.customize-panel-back' );
 
 			if ( expanded && ! accordionSection.hasClass( 'current-panel' ) ) {
 

From a8e46e18b3676314afd7c7e61b63fd3e21186536 Mon Sep 17 00:00:00 2001
From: Piotr Delawski <piotr.delawski@xwp.co>
Date: Sat, 7 May 2016 22:09:48 +0200
Subject: [PATCH 9/9] Refine transitions handling in new panel/section
 structure. Clean JS and CSS code.

---
 src/wp-admin/css/customize-controls.css | 163 +++++-----------------
 src/wp-admin/js/customize-controls.js   | 238 +++++++++++++++++++++-----------
 2 files changed, 195 insertions(+), 206 deletions(-)

diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css
index d38e02a..9b9e001 100644
--- a/src/wp-admin/css/customize-controls.css
+++ b/src/wp-admin/css/customize-controls.css
@@ -218,6 +218,11 @@ body {
 	box-sizing: border-box;
 }
 
+.wp-full-overlay #customize-controls .wp-full-overlay-sidebar-content {
+	/* Promote to separate layer to avoid full-screen repaints */
+	transform: translate3d(0,0,0);
+}
+
 #customize-info,
 #customize-theme-controls .customize-pane-parent,
 #customize-theme-controls .customize-pane-child {
@@ -228,7 +233,7 @@ body {
 	-webkit-box-sizing: border-box;
 	-moz-box-sizing: border-box;
 	box-sizing: border-box;
-	transition: 0.48s transform cubic-bezier(0.19, 1, 0.22, 1); /* easeOutExpo */
+	transition: 0.6s transform cubic-bezier(0.19, 1, 0.22, 1); /* easeOutExpo */
 }
 
 #customize-info,
@@ -238,73 +243,58 @@ body {
 	height: auto;
 	max-height: none;
 	overflow: auto;
-	transform: translateX(0);
+	transform: none;
 }
 
-.section-open #customize-theme-controls .customize-pane-parent,
-.in-sub-panel #customize-theme-controls .customize-pane-parent,
-.section-open #customize-info,
-.in-sub-panel #customize-info,
-.in-sub-panel.section-open #customize-theme-controls .customize-pane-child.current-panel {
-	transform: translateX(-100%);
+#customize-theme-controls .customize-pane-child {
+	position: absolute;
+	top: 0;
+	left: 0;
+	transform: translateX(100%);
+	visibility: hidden;
+	height: 0;
+	max-height: none;
+	overflow: hidden;
 }
 
-.in-themes-panel #customize-theme-controls .customize-pane-parent,
-.in-themes-panel #customize-info {
-	transform: translateX(100%);
+#customize-theme-controls .customize-pane-child.open,
+#customize-theme-controls .customize-pane-child.current-panel,
+#customize-theme-controls .customize-themes-panel.customize-pane-child.current-panel {
+	transform: none;
 }
 
+#customize-theme-controls .customize-themes-panel.customize-pane-child,
 .section-open #customize-theme-controls .customize-pane-parent,
 .in-sub-panel #customize-theme-controls .customize-pane-parent,
 .section-open #customize-info,
 .in-sub-panel #customize-info,
-.section-open.in-sub-panel #customize-theme-controls .customize-pane-child.current-panel {
+.in-sub-panel.section-open #customize-theme-controls .customize-pane-child.current-panel,
+.in-themes-panel #customize-theme-controls .customize-pane-parent,
+.in-themes-panel #customize-info {
 	visibility: hidden;
 	height: 0;
 	overflow: hidden;
+	transform: translateX(-100%);
 }
 
-.section-open #customize-theme-controls .customize-pane-parent.closing,
-.in-sub-panel #customize-theme-controls .customize-pane-parent.closing,
-.section-open #customize-info.closing,
-.in-sub-panel #customize-info.closing,
+.section-open #customize-theme-controls .customize-pane-parent.transitioning,
+.in-sub-panel #customize-theme-controls .customize-pane-parent.transitioning,
+.in-themes-panel #customize-theme-controls .customize-pane-parent.transitioning,
+.section-open #customize-info.transitioning,
+.in-sub-panel #customize-info.transitioning,
+.in-themes-panel #customize-info.transitioning,
 .transitioning.section-open.in-sub-panel #customize-theme-controls .customize-pane-child.current-panel,
 #customize-theme-controls .customize-pane-child.open,
 #customize-theme-controls .customize-pane-child.current-panel,
-#customize-theme-controls .customize-pane-child.closing {
+#customize-theme-controls .customize-pane-child.transitioning {
 	visibility: visible;
 	height: auto;
 	overflow: auto;
 }
 
-#customize-theme-controls .customize-pane-child {
-	position: absolute;
-	top: 0;
-	left: 0;
+.in-themes-panel #customize-theme-controls .customize-pane-parent,
+.in-themes-panel #customize-info {
 	transform: translateX(100%);
-	visibility: hidden;
-	height: 0;
-	max-height: none;
-	overflow: hidden;
-}
-
-#customize-theme-controls .customize-pane-parent.closing,
-#customize-info.closing,
-#customize-theme-controls .customize-pane-child.closing {
-	max-height: 100%;
-}
-
-#customize-theme-controls .customize-pane-child.open,
-#customize-theme-controls .customize-pane-child.current-panel {
-	transform: translateX(0);
-}
-
-#customize-theme-controls .customize-themes-panel.customize-pane-child {
-	transform: translateX(-100%);
-}
-
-#customize-theme-controls .customize-themes-panel.customize-pane-child.current-panel {
-	transform: translateX(0);
 }
 
 #customize-theme-controls .customize-pane-child.accordion-section-content,
@@ -317,11 +307,6 @@ body {
 	padding: 12px;
 }
 
-.wp-full-overlay #customize-controls .wp-full-overlay-sidebar-content {
-	/* Promote to separate layer to avoid full-screen repaints */
-	transform: translate3d(0,0,0);
-}
-
 .customize-section-description-container {
 	margin-bottom: 15px;
 }
@@ -361,23 +346,6 @@ h3.customize-section-title {
 	color: #555;
 }
 
-/*#customize-theme-controls {
-	position: relative;
-	left: 0;
-	-webkit-transition: .18s left ease-in-out;
-	transition: .18s left ease-in-out;
-}*/
-
-/*.ios #customize-theme-controls {
-	-webkit-transition: left 0s;
-	transition: left 0s;
-}*/
-
-/*.section-open #customize-info,
-.section-open #customize-theme-controls {
-	left: -100%;
-}*/
-
 .accordion-sub-container.control-panel-content {
 	display: none;
 	position: absolute;
@@ -393,7 +361,7 @@ h3.customize-section-title {
 	transition: left 0s;
 }
 
-.accordion-sub-container.control-panel-content.closing {
+.accordion-sub-container.control-panel-content.transitioning {
 	display: block;
 }
 
@@ -436,20 +404,14 @@ h3.customize-section-title {
 	-webkit-box-shadow: none;
 	box-shadow: none;
 	cursor: pointer;
-	-webkit-transition: left .18s ease-in-out, color .1s ease-in-out, background .1s ease-in-out;
-	transition: left .18s ease-in-out, color .1s ease-in-out, background .1s ease-in-out;
+	-webkit-transition: color .1s ease-in-out, background .1s ease-in-out;
+	transition: color .1s ease-in-out, background .1s ease-in-out;
 }
 
 .customize-section-back {
 	height: 74px;
 }
 
-.ios .customize-panel-back,
-.ios .customize-section-back {
-	-webkit-transition: left 0s;
-	transition: left 0s;
-}
-
 .ios .customize-panel-back {
 	display: none;
 }
@@ -515,39 +477,6 @@ h3.customize-section-title {
 	padding-left: 62px;
 }
 
-#customize-theme-controls .control-section.current-panel {
-	padding: 0;
-}
-
-#customize-theme-controls .control-section > h3.accordion-section-title {
-	position: relative;
-	left: 0;
-}
-
-#customize-theme-controls .control-section.current-panel > h3.accordion-section-title {
-	left: -354px;
-	-webkit-transition: left ease-in-out .18s;
-	transition: left ease-in-out .18s;
-}
-
-.ios #customize-theme-controls .control-section.current-panel > h3.accordion-section-title {
-	-webkit-transition: left 0s;
-	transition: left 0s;
-}
-
-/*.wp-full-overlay.section-open #customize-controls .wp-full-overlay-sidebar-content {
-	visibility: hidden;
-	overflow-y: hidden;
-}
-*/
-/*.wp-full-overlay.section-open .wp-full-overlay-sidebar-content .accordion-section.open {
-	visibility: visible;
-}
-
-.wp-full-overlay.section-open .wp-full-overlay-sidebar-content .accordion-section.open .accordion-section-content {
-	overflow-y: auto;
-}*/
-
 p.customize-section-description {
 	font-style: normal;
 	margin-top: 22px;
@@ -1159,10 +1088,6 @@ p.customize-section-description {
 	padding: 15px 8px 0 8px;
 }
 
-/*.control-section.open .customize-themes-panel {
-	display: block;
-}*/
-
 #customize-theme-controls .customize-themes-panel .accordion-section-content {
 	background: transparent;
 	display: block;
@@ -1208,29 +1133,15 @@ p.customize-section-description {
 	width: 100%;
 }
 
-/*#accordion-section-themes .accordion-section-title:after {*/
 .control-section-themes .accordion-section-title:after,
 .customize-themes-panel .accordion-section-title:after {
 	display: none;
 }
 
-/*#customize-theme-controls .control-section-themes.current-panel > h3.accordion-section-title {
-	left: 0;
-}*/
-
 .customize-themes-panel.control-panel-content {
-/*	position: absolute;
-	left: -100%;
-	top: 0;
-	width: 100%;*/
 	border-top: 1px solid #ddd;
 }
 
-/*.in-themes-panel #customize-info,
-.in-themes-panel #customize-theme-controls > ul > .accordion-section {
-	left: 100%;
-}*/
-
 /* Details View */
 .wp-customizer .theme-overlay {
 	display: none;
diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
index 39de2d2..bec58c5 100644
--- a/src/wp-admin/js/customize-controls.js
+++ b/src/wp-admin/js/customize-controls.js
@@ -718,26 +718,68 @@
 				parent = overlay.find( '.customize-pane-parent' ),
 				backBtn = content.find( '.customize-section-back' ),
 				sectionTitle = section.container.find( '.accordion-section-title' ).first(),
-				expand;
+				expand, handleTransition;
+
+			/**
+			 * Handle transitions if they are supported by the browser.
+			 *
+			 * @param  {object} args
+			 * @param  {object} args.focusElement  Object gaining focus on after transition.
+			 */
+			handleTransition = function ( args ) {
+				var focus;
+
+				focus = function () {
+					if ( ! _.isUndefined( args.focusElement ) ) {
+						args.focusElement.focus();
+					}
+				};
+
+				container.scrollTop( 0 );
+				if ( normalizedTransitionendEventName ) {
+					_.each( [ content, overlay ], function ( el ) {
+						el.addClass( 'transitioning' );
+					} );
+
+					if ( ! overlay.hasClass( 'in-sub-panel' ) ) {
+						_.each( [ info, parent ], function ( el ) {
+							el.addClass( 'transitioning' );
+						} );
+					}
+
+					content.on( normalizedTransitionendEventName, function ( event ) {
+						if ( ! content.is( event.target ) || 'transform' !== event.originalEvent.propertyName ) {
+							return this;
+						}
+						content.off( normalizedTransitionendEventName );
+
+						_.each( [ content, overlay ], function ( el ) {
+							el.removeClass( 'transitioning' );
+						} );
+
+						if ( info.hasClass( 'transitioning' ) ) {
+							_.each( [ info, parent ], function ( el ) {
+								el.removeClass( 'transitioning' );
+							} );
+						}
+
+						focus();
+						return this;
+					} );
+				} else {
+					focus();
+				}
+			};
 
 			if ( expanded && ! content.hasClass( 'open' ) ) {
 
 				if ( args.unchanged ) {
 					expand = args.completeCallback;
 				} else {
-					container.scrollTop( 0 );
 					expand = function() {
-						content.one( normalizedTransitionendEventName, function () {
-							info.removeClass( 'closing' );
-							parent.removeClass( 'closing' );
-							overlay.removeClass( 'transitioning' );
-							backBtn.focus();
-						} );
-
+						handleTransition( { focusElement: backBtn } );
 						content.addClass( 'open' );
-						info.addClass( 'closing' );
-						parent.addClass( 'closing' );
-						overlay.addClass( 'section-open transitioning' );
+						overlay.addClass( 'section-open' );
 
 						sectionTitle.attr( 'tabindex', '-1' );
 						backBtn.attr( 'tabindex', '0' );
@@ -770,18 +812,9 @@
 
 			} else if ( ! expanded && content.hasClass( 'open' ) ) {
 
-				content.one( normalizedTransitionendEventName, function () {
-					content.removeClass( 'closing' );
-					info.removeClass( 'closing' );
-					parent.removeClass( 'closing' );
-					overlay.removeClass( 'transitioning' );
-					sectionTitle.focus();
-				} );
-
-				content.removeClass( 'open' ).addClass( 'closing' );
-				info.addClass( 'closing' );
-				parent.addClass( 'closing' );
-				overlay.removeClass( 'section-open transitioning' );
+				handleTransition( { focusElement: sectionTitle } );
+				content.removeClass( 'open' );
+				overlay.removeClass( 'section-open' );
 
 				backBtn.attr( 'tabindex', '-1' );
 				sectionTitle.attr( 'tabindex', '0' );
@@ -984,9 +1017,51 @@
 				info = overlay.find( '#customize-info' ),
 				parent = overlay.find( '.customize-pane-parent' ),
 				customizeBtn = section.find( '.customize-theme' ),
-				changeBtn = panel.container.find( '.change-theme' );
+				changeBtn = panel.container.find( '.change-theme' ),
+				handleTransition;
+
+			/**
+			 * Handle transitions if they are supported by the browser.
+			 *
+			 * @param  {object} args
+			 * @param  {object} args.focusElement  Object gaining focus on after transition.
+			 */
+			handleTransition = function ( args ) {
+				var focus, transitionedElements = [ section, info, parent, overlay ];
+				
+				focus = function () {
+					if ( ! _.isUndefined( args.focusElement ) ) {
+						args.focusElement.focus();
+					}
+				};
+
+				container.scrollTop( 0 );
+				if ( normalizedTransitionendEventName ) {
+					_.each( transitionedElements, function ( el ) {
+						el.addClass( 'transitioning' );
+					} );
+
+					section.on( normalizedTransitionendEventName, function ( event ) {
+						if ( ! section.is( event.target ) || 'transform' !== event.originalEvent.propertyName ) {
+							return this;
+						}
+						section.off( normalizedTransitionendEventName );
+
+						_.each( transitionedElements, function ( el ) {
+							el.removeClass( 'transitioning' );
+						} );
+
+						focus();
+						_.delay( panel.renderScreenshots, 10 );
+						return this;
+					} );
+				} else {
+					focus();
+				}
+			};
 
 			if ( expanded && ! section.hasClass( 'current-panel' ) ) {
+
 				// Collapse any sibling sections/panels
 				api.section.each( function ( otherSection ) {
 					if ( otherSection !== panel ) {
@@ -997,42 +1072,24 @@
 					otherPanel.collapse( { duration: 0 } );
 				});
 
-				section.one( normalizedTransitionendEventName, function () {
-					info.removeClass( 'closing' );
-					parent.removeClass( 'closing' );
-					overlay.removeClass( 'transitioning' );
-					customizeBtn.focus();
-					_.delay( panel.renderScreenshots, 10 );
-				} );
-
+				handleTransition( { focusElement: customizeBtn } );
 				section.addClass( 'current-panel' );
-				info.addClass( 'closing' );
-				parent.addClass( 'closing' );
-				overlay.addClass( 'in-themes-panel transitioning' );
+				overlay.addClass( 'in-themes-panel' );
 
-				container.scrollTop( 0 );
 				panel.$customizeSidebar.on( 'scroll.customize-themes-section', _.throttle( panel.renderScreenshots, 300 ) );
 
 				if ( args.completeCallback ) {
 					args.completeCallback();
 				}
 			} else if ( ! expanded && section.hasClass( 'current-panel' ) ) {
-				section.one( normalizedTransitionendEventName, function () {
-					section.removeClass( 'closing' );
-					info.removeClass( 'closing' );
-					parent.removeClass( 'closing' );
-					overlay.removeClass( 'transitioning' );
-					changeBtn.focus();
-				} );
 
-				section.removeClass( 'current-panel' ).addClass( 'closing' );
-				info.addClass( 'closing' );
-				parent.addClass( 'closing' );
-				overlay.removeClass( 'in-themes-panel' ).addClass( 'transitioning' );
+				handleTransition( { focusElement: changeBtn } );
+				section.removeClass( 'current-panel' );
+				overlay.removeClass( 'in-themes-panel' );
+
 				panel.$customizeSidebar.off( 'scroll.customize-themes-section' );
 
 				customizeBtn.attr( 'tabindex', '0' );
-				container.scrollTop( 0 );
 				
 				if ( args.completeCallback ) {
 					args.completeCallback();
@@ -1393,7 +1450,47 @@
 				info = overlay.find( '#customize-info' ),
 				parent = overlay.find( '.customize-pane-parent' ),
 				topPanel = panel.container.find( '.accordion-section-title' ),
-				backBtn = accordionSection.find( '.customize-panel-back' );
+				backBtn = accordionSection.find( '.customize-panel-back' ),
+				handleTransition;
+
+			/**
+			 * Handle transitions if they are supported by the browser.
+			 *
+			 * @param  {object} args
+			 * @param  {object} args.focusElement  Object gaining focus on after transition.
+			 */
+			handleTransition = function ( args ) {
+				var focus, transitionedElements = [ accordionSection, info, parent, overlay ];
+				
+				focus = function () {
+					if ( ! _.isUndefined( args.focusElement ) ) {
+						args.focusElement.focus();
+					}
+				};
+
+				container.scrollTop( 0 );
+				if ( normalizedTransitionendEventName ) {
+					_.each( transitionedElements, function ( el ) {
+						el.addClass( 'transitioning' );
+					} );
+
+					accordionSection.on( normalizedTransitionendEventName, function ( event ) {
+						if ( ! accordionSection.is( event.target ) || 'transform' !== event.originalEvent.propertyName ) {
+							return this;
+						}
+						accordionSection.off( normalizedTransitionendEventName );
+
+						_.each( transitionedElements, function ( el ) {
+							el.removeClass( 'transitioning' );
+						} );
+
+						focus();
+						return this;
+					} );
+				} else {
+					focus();
+				}
+			};
 
 			if ( expanded && ! accordionSection.hasClass( 'current-panel' ) ) {
 
@@ -1409,48 +1506,29 @@
 					}
 				});
 
-				accordionSection.one( normalizedTransitionendEventName, function () {
-					info.removeClass( 'closing' );
-					parent.removeClass( 'closing' );
-					overlay.removeClass( 'transitioning' );
-					backBtn.focus();
-				} );
-
+				handleTransition( { focusElement: backBtn } );
+				overlay.addClass( 'in-sub-panel' );
 				accordionSection.addClass( 'current-panel' );
-				info.addClass( 'closing' );
-				parent.addClass( 'closing' );
-				overlay.addClass( 'in-sub-panel transitioning' );
-
-				container.scrollTop( 0 );
-				if ( args.completeCallback ) {
-					args.completeCallback();
-				}
 
 				topPanel.attr( 'tabindex', '-1' );
 				backBtn.attr( 'tabindex', '0' );
 
-			} else if ( ! expanded && accordionSection.hasClass( 'current-panel' ) ) {
-				accordionSection.one( normalizedTransitionendEventName, function () {
-					accordionSection.removeClass( 'closing' );
-					info.removeClass( 'closing' );
-					parent.removeClass( 'closing' );
-					overlay.removeClass( 'transitioning' );
-					topPanel.focus();
-				} );
-
-				accordionSection.removeClass( 'current-panel' ).addClass( 'closing' );
-				info.addClass( 'closing' );
-				parent.addClass( 'closing' );
-				overlay.removeClass( 'in-sub-panel' ).addClass( 'transitioning' );
-
 				if ( args.completeCallback ) {
 					args.completeCallback();
 				}
 
+			} else if ( ! expanded && accordionSection.hasClass( 'current-panel' ) ) {
+
+				handleTransition( { focusElement: topPanel } );
+				overlay.removeClass( 'in-sub-panel' );
+				accordionSection.removeClass( 'current-panel' );
+
 				topPanel.attr( 'tabindex', '0' );
 				backBtn.attr( 'tabindex', '-1' );
 
-				container.scrollTop( 0 );
+				if ( args.completeCallback ) {
+					args.completeCallback();
+				}
 			}
 		},
 
