diff --git a/libraries/foundation-6/js/foundation.core.js b/libraries/foundation-6/js/foundation.core.js
index cc79830c8d00d44841e321939b6567165c826b88..b5301744538ebbb53c078536f24251fc4546014c 100644
--- a/libraries/foundation-6/js/foundation.core.js
+++ b/libraries/foundation-6/js/foundation.core.js
@@ -4,7 +4,7 @@ import $ from 'jquery';
 import { GetYoDigits } from './foundation.util.core';
 import { MediaQuery } from './foundation.util.mediaQuery';
 
-var FOUNDATION_VERSION = '6.4.2';
+var FOUNDATION_VERSION = '6.4.3';
 
 // Global Foundation object
 // This is attached to the window, or used as a module for AMD/Browserify
diff --git a/libraries/tablesorter/js/jquery.tablesorter.js b/libraries/tablesorter/js/jquery.tablesorter.js
index f83a1d13f497f5685e76ea865ddbaf812876df4b..fb79d7cdeb0f9fc58d57762e39262164053502a9 100644
--- a/libraries/tablesorter/js/jquery.tablesorter.js
+++ b/libraries/tablesorter/js/jquery.tablesorter.js
@@ -421,10 +421,10 @@
 				e.stopPropagation();
 				ts.applyWidgetId( this, id );
 			})
-			.bind( 'applyWidgets' + namespace, function( e, init ) {
+			.bind( 'applyWidgets' + namespace, function( e, callback ) {
 				e.stopPropagation();
-				// apply widgets
-				ts.applyWidget( this, init );
+				// apply widgets (false = not initializing)
+				ts.applyWidget( this, false, callback );
 			})
 			.bind( 'refreshWidgets' + namespace, function( e, all, dontapply ) {
 				e.stopPropagation();
@@ -2130,6 +2130,7 @@
 					c.widgetInit[ name[ index ] ] = false;
 				}
 			}
+			c.$table.triggerHandler( 'widgetRemoveEnd', table );
 		},
 
 		refreshWidgets : function( table, doAll, dontapply ) {
diff --git a/libraries/tablesorter/js/widgets/widget-columnSelector.js b/libraries/tablesorter/js/widgets/widget-columnSelector.js
index c67ff369d1d1b9cb1904430abd992ec0843dbf5f..0ce7b3bd7198d1931d339e700e6bb7194ba6f0ce 100644
--- a/libraries/tablesorter/js/widgets/widget-columnSelector.js
+++ b/libraries/tablesorter/js/widgets/widget-columnSelector.js
@@ -269,16 +269,16 @@
 				c.$table.triggerHandler(wo.columnSelector_updated);
 			}
 		},
-		addSelectors: function( prefix, column ) {
+		addSelectors: function( wo, prefix, column ) {
 			var array = [],
 				temp = ' col:nth-child(' + column + ')';
 			array.push(prefix + temp + ',' + prefix + '_extra_table' + temp);
-			temp = ' tr:not(.hasSpan) th[data-column="' + ( column - 1 ) + '"]';
+			temp = ' tr:not(.' + wo.columnSelector_classHasSpan + ') th[data-column="' + ( column - 1 ) + '"]';
 			array.push(prefix + temp + ',' + prefix + '_extra_table' + temp);
-			temp = ' tr:not(.hasSpan) td:nth-child(' + column + ')';
+			temp = ' tr:not(.' + wo.columnSelector_classHasSpan + ') td:nth-child(' + column + ')';
 			array.push(prefix + temp + ',' + prefix + '_extra_table' + temp);
 			// for other cells in colspan columns
-			temp = ' tr td:not(' + prefix + 'HasSpan)[data-column="' + (column - 1) + '"]';
+			temp = ' tr td:not(' + prefix + wo.columnSelector_classHasSpan + ')[data-column="' + (column - 1) + '"]';
 			array.push(prefix + temp + ',' + prefix + '_extra_table' + temp);
 			return array;
 		},
@@ -301,7 +301,7 @@
 					isHidden[ column + 1 ] = ts.getData( c.$headerIndexed[ column ], col, 'columnSelector' ) === 'false';
 					if ( isHidden[ column + 1 ] ) {
 						// hide columnSelector false column (in auto mode)
-						mediaAll = mediaAll.concat( tsColSel.addSelectors( prefix, column + 1 ) );
+						mediaAll = mediaAll.concat( tsColSel.addSelectors( wo, prefix, column + 1 ) );
 					}
 				}
 			}
@@ -313,7 +313,7 @@
 					column = parseInt($(this).attr('data-column'), 10) + 1;
 					// don't reveal columnSelector false columns
 					if ( !isHidden[ column ] ) {
-						breaks = breaks.concat( tsColSel.addSelectors( prefix, column ) );
+						breaks = breaks.concat( tsColSel.addSelectors( wo, prefix, column ) );
 					}
 				});
 				if (breaks.length) {
@@ -343,7 +343,7 @@
 			colSel.$container.find('input[data-column]').filter('[data-column!="auto"]').each(function(){
 				if (!this.checked) {
 					column = parseInt( $(this).attr('data-column'), 10 ) + 1;
-					styles = styles.concat( tsColSel.addSelectors( prefix, column ) );
+					styles = styles.concat( tsColSel.addSelectors( wo, prefix, column ) );
 				}
 				$(this).toggleClass( wo.columnSelector_cssChecked, this.checked );
 			});
@@ -373,10 +373,10 @@
 				if ( span > 1 ) {
 					hasSpans = true;
 					$cells.eq( index )
-						.addClass( c.namespace.slice( 1 ) + 'columnselectorHasSpan' )
+						.addClass( c.namespace.slice( 1 ) + 'columnselector' + wo.columnSelector_classHasSpan )
 						.attr( 'data-col-span', span );
 					// add data-column values
-					ts.computeColumnIndex( $cells.eq( index ).parent().addClass( 'hasSpan' ) );
+					ts.computeColumnIndex( $cells.eq( index ).parent().addClass( wo.columnSelector_classHasSpan ) );
 				}
 			}
 			// only add resize end if using media queries
@@ -402,7 +402,9 @@
 				autoModeOn = wo.columnSelector_mediaquery && colSel.auto,
 				// find all header/footer cells in case a regular column follows a colspan; see #1238
 				$headers = c.$table.children( 'thead, tfoot' ).children().children()
-					.add( $(c.namespace + '_extra_table').children( 'thead, tfoot' ).children().children() ),
+					.add( $(c.namespace + '_extra_table').children( 'thead, tfoot' ).children().children() )
+					// include grouping widget headers (they have colspans!)
+					.add( c.$table.find( '.group-header' ).children() ),
 				len = $headers.length;
 			for ( index = 0; index < len; index++ ) {
 				$cell = $headers.eq(index);
@@ -422,7 +424,7 @@
 						$cell.addClass( filtered );
 					}
 				} else if ( typeof colSel.states[ col ] !== 'undefined' && colSel.states[ col ] !== null ) {
-					$cell.toggleClass( filtered, !colSel.states[ col ] );
+					$cell.toggleClass( filtered, !autoModeOn && !colSel.states[ col ] );
 				}
 			}
 		},
@@ -533,6 +535,8 @@
 			// class name added to checked checkboxes - this fixes an issue with Chrome not updating FontAwesome
 			// applied icons; use this class name (input.checked) instead of input:checked
 			columnSelector_cssChecked : 'checked',
+			// class name added to rows that have a span (e.g. grouping widget & other rows inside the tbody)
+			columnSelector_classHasSpan : 'hasSpan',
 			// event triggered when columnSelector completes
 			columnSelector_updated : 'columnUpdate'
 		},
@@ -546,10 +550,10 @@
 			if ( csel.$popup ) { csel.$popup.empty(); }
 			csel.$style.remove();
 			csel.$breakpoints.remove();
-			$( c.namespace + 'columnselectorHasSpan' ).removeClass( wo.filter_filteredRow || 'filtered' );
+			$( c.namespace + 'columnselector' + wo.columnSelector_classHasSpan )
+				.removeClass( wo.filter_filteredRow || 'filtered' );
 			c.$table.find('[data-col-span]').each(function(indx, el) {
 				var $el = $(el);
-				console.log($el, $el.attr('data-col-span'));
 				$el.attr('colspan', $el.attr('data-col-span'));
 			});
 			c.$table.off('updateAll' + namespace + ' update' + namespace);
diff --git a/libraries/tablesorter/js/widgets/widget-grouping.js b/libraries/tablesorter/js/widgets/widget-grouping.js
index b7dc09a10a886e15fa4d9ddbb9623bd0340c9d42..1503edca3168c40a031a207196b4747511cbdb2f 100644
--- a/libraries/tablesorter/js/widgets/widget-grouping.js
+++ b/libraries/tablesorter/js/widgets/widget-grouping.js
@@ -172,7 +172,10 @@
 
 		groupHeaderHTML : function( c, wo, data ) {
 			var name = ( data.currentGroup || '' ).toString().replace(/</g, '&lt;').replace(/>/g, '&gt;');
-			return '<tr class="group-header ' + c.selectorRemove.slice(1) +
+			return '<tr class="group-header ' + c.selectorRemove.slice(1) + ' ' +
+				// prevent grouping row from being hidden by the columnSelector;
+				// classHasSpan option added 2.29.0
+				( wo.columnSelector_classHasSpan || 'hasSpan' ) +
 				'" unselectable="on" ' + ( c.tabIndex ? 'tabindex="0" ' : '' ) + 'data-group-index="' +
 				data.groupIndex + '">' +
 				'<td colspan="' + c.columns + '">' +
@@ -221,6 +224,10 @@
 					}
 				}
 			}
+			if ( ts.hasWidget( c.table, 'columnSelector' ) ) {
+				// make sure to handle the colspan adjustments of the grouping rows
+				ts.columnSelector.setUpColspan( c, wo );
+			}
 		},
 		insertGroupHeader: function( c, wo, data ) {
 			var $header = c.$headerIndexed[ data.column ],
diff --git a/libraries/tablesorter/js/widgets/widget-resizable.js b/libraries/tablesorter/js/widgets/widget-resizable.js
index 543b143e47958ccdb33b9aaf948589dad582845d..d82b7b48c1733af20c572fa2677ce6fa89d34b18 100644
--- a/libraries/tablesorter/js/widgets/widget-resizable.js
+++ b/libraries/tablesorter/js/widgets/widget-resizable.js
@@ -325,6 +325,7 @@
 			vars.$target = vars.$next = null;
 			// will update stickyHeaders, just in case, see #912
 			c.$table.triggerHandler('stickyHeadersUpdate');
+			c.$table.triggerHandler('resizableComplete');
 		}
 	};
 
diff --git a/libraries/tablesorter/js/widgets/widget-scroller.js b/libraries/tablesorter/js/widgets/widget-scroller.js
index d005b3a7964e6ba70ab8d7bb56a5a3f8a571a3e8..0708e5f4201004b416bd717b68d4664a81a27099 100644
--- a/libraries/tablesorter/js/widgets/widget-scroller.js
+++ b/libraries/tablesorter/js/widgets/widget-scroller.js
@@ -273,6 +273,9 @@
 			$tableWrap
 				.off( 'scroll' + namespace )
 				.on( 'scroll' + namespace, function() {
+					// Save position
+					wo.scroller_saved[0] = $tableWrap.scrollLeft();
+					wo.scroller_saved[1] = $tableWrap.scrollTop();
 					if ( wo.scroller_jumpToHeader ) {
 						var pos = $win.scrollTop() - $hdr.offset().top;
 						if ( $( this ).scrollTop() !== 0 && pos < tbHt && pos > 0 ) {
@@ -841,6 +844,7 @@
 			// adjust caption height, see #1202
 			$fixedColumn.find('caption').height( wo.scroller_$header.find( 'caption' ).height() );
 
+			$tableWrap.scroll();
 			wo.scroller_isBusy = false;
 
 		},
diff --git a/libraries/tablesorter/js/widgets/widget-sort2Hash.js b/libraries/tablesorter/js/widgets/widget-sort2Hash.js
index cbb12c6e60cf1abe9fab50fd3869d0951220dc8f..1af47bfe193b44a88c212c89b04a41e6e132566e 100644
--- a/libraries/tablesorter/js/widgets/widget-sort2Hash.js
+++ b/libraries/tablesorter/js/widgets/widget-sort2Hash.js
@@ -225,8 +225,27 @@
 				hash = s2h.cleanHash( c, wo, component, hash );
 				str += value;
 			});
-			// add updated hash
-			window.location.hash = ( ( window.location.hash || '' ).replace( '#', '' ).length ? hash : wo.sort2Hash_hash ) + str;
+
+			var hashChar = wo.sort2Hash_hash;
+			// Combine new hash with any existing hashes
+			var newHash = (
+				( window.location.hash || '' ).replace( hashChar, '' ).length ?
+				hash : hashChar
+			) + str;
+
+			if (wo.sort2Hash_replaceHistory) {
+				var baseUrl = window.location.href.split(hashChar)[0];
+				// Ensure that there is a leading hash character
+				var firstChar = newHash[0];
+				if (firstChar != hashChar) {
+					newHash = hashChar + newHash;
+				}
+				// Update URL in browser
+				window.location.replace(baseUrl + newHash);
+			} else {
+				// Add updated hash
+				window.location.hash = newHash;
+			}
 		}
 	};
 
@@ -239,6 +258,7 @@
 			sort2Hash_headerTextAttr    : 'data-header', // data attribute containing alternate header text
 			sort2Hash_directionText     : [ 0, 1 ], // [ 'asc', 'desc' ],
 			sort2Hash_overrideSaveSort  : false,    // if true, override saveSort widget if saved sort available
+			sort2Hash_replaceHistory    : false,    // if true, hash changes are not saved to browser history
 
 			// this option > table ID > table index on page
 			sort2Hash_tableId           : null,
diff --git a/libraries/tablesorter/js/widgets/widget-stickyHeaders.js b/libraries/tablesorter/js/widgets/widget-stickyHeaders.js
index 12447b6b95a62ad38f5aeadfa9fef98d6aa4bb0c..f55ed7e81ff89f8076e0ae56f2d3fbff0447933f 100644
--- a/libraries/tablesorter/js/widgets/widget-stickyHeaders.js
+++ b/libraries/tablesorter/js/widgets/widget-stickyHeaders.js
@@ -174,6 +174,7 @@
 						scrollTop = attachTop + stickyOffset + nestedStickyTop - captionHeight,
 						tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)) - captionHeight,
 						isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
+						state = isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide,
 						cssSettings = { visibility : isVisible };
 					if ($attach.length) {
 						cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
@@ -183,10 +184,13 @@
 						cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft();
 					}
 					cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
-					$stickyWrap
-						.removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
-						.addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide )
-						.css(cssSettings);
+					// attached sticky headers always need updating
+					if ( !$stickyWrap.hasClass( state ) || $attach.length ) {
+						$stickyWrap
+							.removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
+							.addClass( state )
+							.css(cssSettings);
+					}
 					if (isVisible !== laststate || resizing) {
 						// make sure the column widths match
 						resizeHeader();