diff --git a/unpacked/MathJax.js b/unpacked/MathJax.js
index a8b6dbeb3..ccee686ca 100644
--- a/unpacked/MathJax.js
+++ b/unpacked/MathJax.js
@@ -2569,6 +2569,8 @@ MathJax.Hub.Startup = {
         }
         if (SETTINGS.FastPreview && !MathJax.Extension["fast-preview"])
           MathJax.Hub.config.extensions.push("fast-preview.js");
+        if (config.menuSettings.assistiveMML && !MathJax.Extension.AssistiveMML)
+          MathJax.Hub.config.extensions.push("AssistiveMML.js");
       },MathJax.Hub.config],
       ["Post",this.signal,"End Cookie"]
     );
@@ -3090,12 +3092,13 @@ MathJax.Hub.Startup = {
     isMac:       (navigator.platform.substr(0,3) === "Mac"),
     isPC:        (navigator.platform.substr(0,3) === "Win"),
     isMSIE:      ("ActiveXObject" in window && "clipboardData" in window),
-    isMsEdge:    (!!AGENT.match(/Edge\//)),
+    isEdge:      ("MSGestureEvent" in window && "chrome" in window &&
+                     window.chrome.loadTimes == null),
     isFirefox:   (!!AGENT.match(/Gecko\//) && !AGENT.match(/like Gecko/)),
     isSafari:    (!!AGENT.match(/ (Apple)?WebKit\//) && !AGENT.match(/ like iPhone /) &&
-                     (!window.chrome || window.chrome.loadTimes == null)),
-    isChrome:    (window.chrome != null && window.chrome.loadTimes != null),
-    isOpera:     (window.opera != null && window.opera.version != null),
+                     (!window.chrome || window.chrome.app == null)),
+    isChrome:    ("chrome" in window && window.chrome.loadTimes != null),
+    isOpera:     ("opera" in window && window.opera.version != null),
     isKonqueror: ("konqueror" in window && navigator.vendor == "KDE"),
     versionAtLeast: function (v) {
       var bv = (this.version).split('.'); v = (new String(v)).split('.');
@@ -3123,7 +3126,7 @@ MathJax.Hub.Startup = {
       HUB.Browser = HUB.Insert(new String(browser),BROWSERS);
       var VERSION = new RegExp(
         ".*(Version/| Trident/.*; rv:)((?:\\d+\\.)+\\d+)|" +                      // for Safari, Opera10, and IE11+
-        ".*("+browser+")"+(browser == "MSIE" ? " " : "/")+"((?:\\d+\\.)*\\d+)|"+  // for one of the main browser
+        ".*("+browser+")"+(browser == "MSIE" ? " " : "/")+"((?:\\d+\\.)*\\d+)|"+  // for one of the main browsers
         "(?:^|\\(| )([a-z][-a-z0-9._: ]+|(?:Apple)?WebKit)/((?:\\d+\\.)+\\d+)");  // for unrecognized browser
       var MATCH = VERSION.exec(xAGENT) || ["","","","unknown","0.0"];
       HUB.Browser.name = (MATCH[1] != "" ? browser : (MATCH[3] || MATCH[5]));
@@ -3177,8 +3180,15 @@ MathJax.Hub.Startup = {
                           AGENT.match(/ Fennec\//) != null ||
                           AGENT.match(/Mobile/) != null);
     },
+    Chrome: function (browser) {
+      browser.noContextMenu = browser.isMobile = !!navigator.userAgent.match(/ Mobile[ \/]/);
+    },
     Opera: function (browser) {browser.version = opera.version()},
+    Edge: function (browser) {
+      browser.isMobile = !!navigator.userAgent.match(/ Phone/);
+    },
     MSIE: function (browser) {
+      browser.isMobile = !!navigator.userAgent.match(/ Phone/);
       browser.isIE9 = !!(document.documentMode && (window.performance || window.msPerformance));
       MathJax.HTML.setScriptBug = !browser.isIE9 || document.documentMode < 9;
       MathJax.Hub.msieHTMLCollectionBug = (document.documentMode < 9);
diff --git a/unpacked/extensions/AssistiveMML.js b/unpacked/extensions/AssistiveMML.js
new file mode 100644
index 000000000..59b1c795f
--- /dev/null
+++ b/unpacked/extensions/AssistiveMML.js
@@ -0,0 +1,127 @@
+/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+
+/*************************************************************
+ *
+ *  MathJax/extensions/AssistiveMML.js
+ *  
+ *  Implements an extension that inserts hidden MathML into the
+ *  page for screen readers or other asistive technology.
+ *  
+ *  ---------------------------------------------------------------------
+ *  
+ *  Copyright (c) 2015 The MathJax Consortium
+ * 
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+(function (AJAX,CALLBACK,HUB,HTML) {
+  var SETTINGS = HUB.config.menuSettings;
+  
+  var AssistiveMML = MathJax.Extension["AssistiveMML"] = {
+    version: "2.6",
+    
+    config: {
+      disabled: false,
+      styles: {
+        ".MJX_Assistive_MathML": {
+          position:"absolute!important",
+          clip: (HUB.Browser.isMSIE && (document.documentMode||0) < 8 ?
+                 "rect(1px 1px 1px 1px)" : "rect(1px, 1px, 1px, 1px)"),
+          padding: "1px 0 0 0!important",
+          border: "0!important",
+          height: "1px!important",
+          width: "1px!important",
+          overflow: "hidden!important",
+          display:"block!important"
+        }
+      }
+    },
+    
+    Config: function () {
+      if (!this.config.disabled && SETTINGS.assistiveMML == null)
+        HUB.Config({menuSettings:{assistiveMML:true}});
+      AJAX.Styles(this.config.styles);
+      HUB.Register.MessageHook("End Math",function (msg) {AssistiveMML.EndMathHook(msg[1])});
+    },
+    
+    //
+    //  The hook for the End Math signal.
+    //  This sets up a state object that lists the jax and index into the jax,
+    //    and a dummy callback that is used to synchronizing with MathJax.
+    //    It will be called when the jax are all processed, and that will
+    //    let the MathJax queue continue (it will block until then).
+    //
+    EndMathHook: function (node) {
+      if (!SETTINGS.assistiveMML) return;
+      var state = {
+        jax: HUB.getAllJax(node), i: 0,
+        callback: MathJax.Callback({})
+      };
+      this.HandleMML(state);
+      return state.callback;
+    },
+
+    //
+    //  For each jax in the state, look up the frame.
+    //  If the jax doesn't use NativeMML and hasn't already been handled:
+    //    Get the MathML for the jax, taking resets into account.
+    //    Add a data-mathml attribute to the frame, and
+    //    Create a span that is not visible on screen and put the MathML in it,
+    //      and add it to the frame.
+    //  When all the jax are processed, call the callback.
+    //
+    HandleMML: function (state) {
+      var m = state.jax.length, jax, mml, frame, span;
+      while (state.i < m) {
+        jax = state.jax[state.i];
+        frame = document.getElementById(jax.inputID+"-Frame");
+        if (jax.outputJax !== "NativeMML" && frame && !frame.getAttribute("data-mathml")) {
+          try {
+            mml = jax.root.toMathML("").replace(/\n */g,"").replace(/<!--.*?-->/g,"");
+          } catch (err) {
+            if (!err.restart) throw err; // an actual error
+            return MathJax.Callback.After(["HandleMML",this,state],err.restart);
+          }
+          frame.setAttribute("data-mathml",mml);
+	  span = HTML.addElement(frame,"span",{
+            isMathJax: true, className: "MJX_Assistive_MathML"
+          });
+	  span.innerHTML = mml;
+          frame.firstChild.setAttribute("aria-hidden","true");
+          span.setAttribute("aria-readonly","true");
+        }
+        state.i++;
+      }
+      state.callback();
+    }
+    
+  };
+
+  HUB.Startup.signal.Post("AssistiveMML Ready");
+
+})(MathJax.Ajax,MathJax.Callback,MathJax.Hub,MathJax.HTML);
+
+//
+//  Make sure the toMathML extension is loaded before we signal
+//  the load complete for this extension.  Then wait for the end
+//  of the user configuration before configuring this extension. 
+//
+MathJax.Callback.Queue(
+  ["Require",MathJax.Ajax,"[MathJax]/extensions/toMathML.js"],
+  ["loadComplete",MathJax.Ajax,"[MathJax]/extensions/AssistiveMML.js"],
+  function () {
+    MathJax.Hub.Register.StartupHook("End Config",["Config",MathJax.Extension.AssistiveMML]);
+  }
+);
+
diff --git a/unpacked/extensions/HelpDialog.js b/unpacked/extensions/HelpDialog.js
index 09365fd26..2c16eb1ca 100644
--- a/unpacked/extensions/HelpDialog.js
+++ b/unpacked/extensions/HelpDialog.js
@@ -29,7 +29,13 @@
 
   var STIXURL = "http://www.stixfonts.org/";
   var MENU = MathJax.Menu;
+  var FALSE, KEY;
+  HUB.Register.StartupHook("MathEvents Ready",function () {
+    FALSE = MathJax.Extension.MathEvents.Event.False;
+    KEY = MathJax.Extension.MathEvents.Event.KEY;
+  });
 
+  
   var CONFIG = HUB.CombineConfig("HelpDialog",{
 
     styles: {
@@ -101,10 +107,10 @@
   HELP.Post = function () {
     this.div = MENU.Background(this);
     var help = HTML.addElement(this.div,"div",{
-      id: "MathJax_Help"
+      id: "MathJax_Help", tabIndex: 0, onkeydown: HELP.Keydown
     },LOCALE._("HelpDialog",[
       ["b",{style:{fontSize:"120%"}},[["Help","MathJax Help"]]],
-      ["div",{id: "MathJax_HelpContent"},[
+      ["div",{id: "MathJax_HelpContent", tabIndex: 0},[
         ["p",{},[["MathJax",
           "*MathJax* is a JavaScript library that allows page authors to include " +
           "mathematics within their web pages.  As a reader, you don't need to do " +
@@ -148,10 +154,13 @@
         ]
       ]],
       ["a",{href:"http://www.mathjax.org/"},["www.mathjax.org"]],
-      ["span",{id: "MathJax_HelpClose", onclick: HELP.Remove},
+      ["span",{id: "MathJax_HelpClose", onclick: HELP.Remove,
+               onkeydown: HELP.Keydown, tabIndex: 0,
+               "aria-label": "Close", "aria-describedby": "Close window"},
         [["span",{},["\u00D7"]]]
       ]
     ]));
+    help.focus();
     LOCALE.setCSS(help);
     var doc = (document.documentElement||{});
     var H = window.innerHeight || doc.clientHeight || doc.scrollHeight || 0;
@@ -167,6 +176,15 @@
   HELP.Remove = function (event) {
     if (HELP.div) {document.body.removeChild(HELP.div); delete HELP.div}
   };
+  HELP.Keydown = function(event) {
+    if (event.keyCode === KEY.ESCAPE ||
+        (this.id === "MathJax_HelpClose" &&
+         (event.keyCode === KEY.SPACE || event.keyCode === KEY.RETURN))) {
+      HELP.Remove(event);
+      MENU.CurrentNode().focus();
+      FALSE(event);
+    }
+  },
 
   MathJax.Callback.Queue(
     HUB.Register.StartupHook("End Config",{}), // wait until config is complete
diff --git a/unpacked/extensions/MathEvents.js b/unpacked/extensions/MathEvents.js
index 3bcf07b40..f9ccbefa8 100644
--- a/unpacked/extensions/MathEvents.js
+++ b/unpacked/extensions/MathEvents.js
@@ -4,20 +4,20 @@
 /*************************************************************
  *
  *  MathJax/extensions/MathEvents.js
- *  
+ *
  *  Implements the event handlers needed by the output jax to perform
  *  menu, hover, and other events.
  *
  *  ---------------------------------------------------------------------
- *  
+ *
  *  Copyright (c) 2011-2015 The MathJax Consortium
- * 
+ *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
  *  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -27,12 +27,12 @@
 
 (function (HUB,HTML,AJAX,CALLBACK,LOCALE,OUTPUT,INPUT) {
   var VERSION = "2.5.0";
-  
+
   var EXTENSION = MathJax.Extension;
   var ME = EXTENSION.MathEvents = {version: VERSION};
-  
+
   var SETTINGS = HUB.config.menuSettings;
-  
+
   var CONFIG = {
     hover: 500,              // time required to be considered a hover
     frame: {
@@ -41,7 +41,7 @@
       bcolor: "#A6D",        // frame border color
       hwidth: "15px",        // haze width
       hcolor: "#83A"         // haze color
-    },       
+    },
     button: {
       x: -6, y: -3,          // menu button offsets
       wx: -2                 // button offset for full-width equations
@@ -99,16 +99,30 @@
     }
   };
 
-  
+
   //
   //  Common event-handling code
   //
   var EVENT = ME.Event = {
-    
+
     LEFTBUTTON: 0,           // the event.button value for left button
     RIGHTBUTTON: 2,          // the event.button value for right button
     MENUKEY: "altKey",       // the event value for alternate context menu
 
+    /*************************************************************/
+    /*
+     *  Enum element for key codes.
+     */
+    KEY: {
+      RETURN: 13,
+      ESCAPE: 27,
+      SPACE: 32,
+      LEFT: 37,
+      UP: 38,
+      RIGHT: 39,
+      DOWN: 40
+    },
+
     Mousedown: function (event) {return EVENT.Handler(event,"Mousedown",this)},
     Mouseup:   function (event) {return EVENT.Handler(event,"Mouseup",this)},
     Mousemove: function (event) {return EVENT.Handler(event,"Mousemove",this)},
@@ -117,7 +131,7 @@
     Click:     function (event) {return EVENT.Handler(event,"Click",this)},
     DblClick:  function (event) {return EVENT.Handler(event,"DblClick",this)},
     Menu:      function (event) {return EVENT.Handler(event,"ContextMenu",this)},
-    
+
     //
     //  Call the output jax's event handler or the zoom handler
     //
@@ -129,7 +143,7 @@
       if (jax[type]) {return jax[type](event,math)}
       if (EXTENSION.MathZoom) {return EXTENSION.MathZoom.HandleEvent(event,type,math)}
     },
-    
+
     //
     //  Try to cancel the event in every way we can
     //
@@ -143,6 +157,15 @@
       return false;
     },
 
+    //
+    // Keydown event handler. Should only fire on Space key.
+    //
+    Keydown: function (event, math) {
+      if (event.keyCode === EVENT.KEY.SPACE) {
+        EVENT.ContextMenu(event, this);
+      };
+    },
+
     //
     //  Load the contextual menu code, if needed, and post the menu
     //
@@ -165,7 +188,7 @@
       }
 
       //
-      //  If the menu code is loaded, 
+      //  If the menu code is loaded,
       //    Check if localization needs loading;
       //    If not, post the menu, and return.
       //    Otherwise wait for the localization to load
@@ -178,18 +201,18 @@
         load = LOCALE.loadDomain("MathMenu");
         if (!load) {
           MENU.jax = jax;
-          var source = MENU.menu.Find("Show Math As").menu;
-	  source.items[0].name = jax.sourceMenuTitle;
-	  source.items[0].format = (jax.sourceMenuFormat||"MathML");
+          var source = MENU.menu.Find("Show Math As").submenu;
+          source.items[0].name = jax.sourceMenuTitle;
+          source.items[0].format = (jax.sourceMenuFormat||"MathML");
           source.items[1].name = INPUT[jax.inputJax].sourceMenuTitle;
           source.items[5].disabled = !INPUT[jax.inputJax].annotationEncoding;
 
-          // 
+          //
           // Try and find each known annotation format and enable the menu
           // items accordingly.
           //
           var annotations = source.items[2]; annotations.disabled = true;
-          var annotationItems = annotations.menu.items;
+          var annotationItems = annotations.submenu.items;
           annotationList = MathJax.Hub.Config.semanticsAnnotations;
           for (var i = 0, m = annotationItems.length; i < m; i++) {
             var name = annotationItems[i].name[1]
@@ -226,7 +249,7 @@
       );
       return EVENT.False(event);
     },
-    
+
     //
     //  Mousedown handler for alternate means of accessing menu
     //
@@ -243,26 +266,26 @@
         return JAX.ContextMenu(event,math,true);
       }
     },
-    
+
     ClearSelection: function () {
       if (ME.safariContextMenuBug) {setTimeout("window.getSelection().empty()",0)}
       if (document.selection) {setTimeout("document.selection.empty()",0)}
     },
-    
+
     getBBox: function (span) {
       span.appendChild(ME.topImg);
       var h = ME.topImg.offsetTop, d = span.offsetHeight-h, w = span.offsetWidth;
       span.removeChild(ME.topImg);
       return {w:w, h:h, d:d};
     }
-    
+
   };
-  
+
   //
   //  Handle hover "discoverability"
   //
   var HOVER = ME.Hover = {
-    
+
     //
     //  Check if we are moving from a non-MathJax element to a MathJax one
     //  and either start fading in again (if it is fading out) or start the
@@ -309,7 +332,7 @@
         return EVENT.False(event);
       }
     },
-    
+
     //
     //  Clear the old timer and start a new one
     //
@@ -320,7 +343,7 @@
     ClearHoverTimer: function () {
       if (this.hoverTimer) {clearTimeout(this.hoverTimer); delete this.hoverTimer}
     },
-    
+
     //
     //  Handle putting up the hover frame
     //
@@ -431,7 +454,7 @@
         jax.hover.timer = setTimeout(CALLBACK(["HoverFade",this,jax]),(delay||CONFIG.fadeDelay));
       }
     },
-    
+
     //
     //  Handle a click on the menu button
     //
@@ -439,7 +462,7 @@
       if (!event) {event = window.event}
       return OUTPUT[this.jax].ContextMenu(event,this.math,true);
     },
-    
+
     //
     //  Clear all hover timers
     //
@@ -449,7 +472,7 @@
       HOVER.ClearHoverTimer();
       delete jax.hover;
     },
-    
+
     //
     //  Make a measurement in pixels
     //
@@ -469,9 +492,9 @@
     }
 
   };
-  
+
   //
-  //  Handle touch events.  
+  //  Handle touch events.
   //
   //  Use double-tap-and-hold as a replacement for context menu event.
   //  Use double-tap as a replacement for double click.
@@ -480,7 +503,7 @@
 
     last: 0,          // time of last tap event
     delay: 500,       // delay time for double-click
-    
+
     //
     //  Check if this is a double-tap, and if so, start the timer
     //  for the double-tap and hold (to trigger the contextual menu)
@@ -494,9 +517,9 @@
         event.preventDefault();
       }
     },
-          
+
     //
-    //  Check if there is a timeout pending, i.e., we have a 
+    //  Check if there is a timeout pending, i.e., we have a
     //  double-tap and were waiting to see if it is held long
     //  enough for the menu.  Since we got the end before the
     //  timeout, it is a double-click, not a double-tap-and-hold.
@@ -512,7 +535,7 @@
         return EVENT.Handler((event.touches[0]||event.touch),"DblClick",this);
       }
     },
-        
+
     //
     //  If the timeout passes without an end event, we issue
     //  the contextual menu event.
@@ -521,10 +544,10 @@
       delete TOUCH.timeout; TOUCH.last = 0; TOUCH.up = false;
       return EVENT.Handler((event.touches[0]||event.touch),"ContextMenu",math);
     }
-    
+
   };
-  
-  /* 
+
+  /*
    * //
    * //  Mobile screens are small, so use larger version of arrow
    * //
@@ -534,7 +557,7 @@
    *   CONFIG.button.x = -6;
    * }
    */
-  
+
   //
   //  Set up browser-specific values
   //
@@ -557,7 +580,7 @@
       ME.noContextMenuBug = true;      // doesn't produce contextmenu event
     }
   });
-  
+
   //
   //  Used in measuring zoom and hover positions
   //
@@ -578,7 +601,7 @@
       haze["-moz-box-shadow"] = haze["-khtml-box-shadow"] =
         "0px 0px "+CONFIG.frame.hwidth+" "+CONFIG.frame.hcolor;
   };
-  
+
   //
   //  Queue the events needed for startup
   //
@@ -590,6 +613,6 @@
     ["Post",HUB.Startup.signal,"MathEvents Ready"],
     ["loadComplete",AJAX,"[MathJax]/extensions/MathEvents.js"]
   );
-  
+
 })(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.Callback,
    MathJax.Localization,MathJax.OutputJax,MathJax.InputJax);
diff --git a/unpacked/extensions/MathML/mml3.js b/unpacked/extensions/MathML/mml3.js
index f14e3bff9..90a98f59b 100644
--- a/unpacked/extensions/MathML/mml3.js
+++ b/unpacked/extensions/MathML/mml3.js
@@ -80,7 +80,7 @@ MathJax.Hub.Register.StartupHook("MathML Jax Ready",function () {
    */
   var BROWSER = MathJax.Hub.Browser;
   var exslt = '';
-  if (BROWSER.isMsEdge || BROWSER.isMSIE) {
+  if (BROWSER.isEdge || BROWSER.isMSIE) {
     exslt = 'urn:schemas-microsoft-com:xslt'
   } else {
     exslt = 'http://exslt.org/common';
@@ -767,7 +767,16 @@ MathJax.Hub.Register.StartupHook("MathML Jax Ready",function () {
   }
   
   // Tweak CSS to avoid some browsers rearranging HTML output
-  MathJax.Ajax.Styles(".MathJax span { direction: ltr !important; display: inline-block !important;}");
+  MathJax.Ajax.Styles({
+    ".MathJax .mi, .MathJax .mo, .MathJax .mn, .MathJax .mtext": {
+      direction: "ltr",
+      display: "inline-block"
+    },
+    ".MathJax .ms, .MathJax .mspace, .MathJax .mglyph": {
+      direction: "ltr",
+      display: "inline-block"
+    }
+  });
 
   MathJax.Hub.Startup.signal.Post("MathML mml3.js Ready");
 });
diff --git a/unpacked/extensions/MathMenu.js b/unpacked/extensions/MathMenu.js
index 8a3419308..c1f7009d1 100644
--- a/unpacked/extensions/MathMenu.js
+++ b/unpacked/extensions/MathMenu.js
@@ -4,21 +4,21 @@
 /*************************************************************
  *
  *  MathJax/extensions/MathMenu.js
- *  
+ *
  *  Implements a right-mouse (or CTRL-click) menu over mathematics
  *  elements that gives the user the ability to copy the source,
  *  change the math size, and zoom settings.
  *
  *  ---------------------------------------------------------------------
- *  
+ *
  *  Copyright (c) 2010-2015 The MathJax Consortium
- * 
+ *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
  *  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -29,8 +29,8 @@
 (function (HUB,HTML,AJAX,CALLBACK,OUTPUT) {
   var VERSION = "2.5.0";
 
-  var SIGNAL = MathJax.Callback.Signal("menu")  // signal for menu events
-  
+  var SIGNAL = MathJax.Callback.Signal("menu");  // signal for menu events
+
   MathJax.Extension.MathMenu = {
     version: VERSION,
     signal: SIGNAL
@@ -42,10 +42,10 @@
       [["MathMenu",id]].concat([].slice.call(arguments,1))
     );
   };
-
+  
   var isPC = HUB.Browser.isPC, isMSIE = HUB.Browser.isMSIE, isIE9 = ((document.documentMode||0) > 8);
   var ROUND = (isPC ? null : "5px");
-  
+
   var CONFIG = HUB.CombineConfig("MathMenu",{
     delay: 150,                                    // the delay for submenus
 
@@ -72,7 +72,7 @@
       left: Math.round((screen.width - 400)/2),
       top:  Math.round((screen.height - 300)/3)
     },
-    
+
     styles: {
       "#MathJax_About": {
         position:"fixed", left:"50%", width:"auto", "text-align":"center",
@@ -143,28 +143,28 @@
         padding: (isPC ? "2px 2em 4px 1.33em" : "1px 2em 3px 1.33em"),
         "font-style":"italic"
       },
-    
+
       ".MathJax_MenuRule": {
         "border-top": (isPC ? "1px solid #CCCCCC" : "1px solid #DDDDDD"),
         margin: (isPC ? "4px 1px 0px" : "4px 3px")
       },
-     
+
       ".MathJax_MenuDisabled": {
         color:"GrayText"
       },
-     
+
       ".MathJax_MenuActive": {
         "background-color": (isPC ? "Highlight" : "#606872"),
         color: (isPC ? "HighlightText" : "white")
       },
-      
+
       "#MathJax_AboutClose": {
         top:".2em", right:".2em"
       },
       ".MathJax_Menu .MathJax_MenuClose": {
         top:"-10px", left:"-10px"
       },
-      
+
       ".MathJax_MenuClose": {
         position:"absolute",
         cursor:"pointer",
@@ -184,7 +184,7 @@
         "-webkit-border-radius": "18px",             // Safari and Chrome
         "-moz-border-radius": "18px",                // Firefox
         "-khtml-border-radius": "18px",              // Konqueror
-        "line-height":0, 
+        "line-height":0,
         padding:"8px 0 6px"     // may need to be browser-specific
       },
       ".MathJax_MenuClose:hover": {
@@ -194,27 +194,72 @@
       ".MathJax_MenuClose:hover span": {
         "background-color":"#CCC!important"
       }
-
     }
   });
-  
-  var FALSE, HOVER;
+
+  var FALSE, HOVER, KEY;
   HUB.Register.StartupHook("MathEvents Ready",function () {
     FALSE = MathJax.Extension.MathEvents.Event.False;
     HOVER = MathJax.Extension.MathEvents.Hover;
+    KEY = MathJax.Extension.MathEvents.Event.KEY;
   });
-  
+
+
+  /*************************************************************/
+  /*
+   *  Abstract class of all keyboard navigatable objects.
+   */
+  var NAV = MathJax.Object.Subclass({
+    /*
+     * Moving in the list of items.
+     */
+    Keydown: function(event, menu) {
+      switch (event.keyCode) {
+      case KEY.ESCAPE:
+        this.Remove(event, menu);
+        break;
+      case KEY.RIGHT:
+        this.Right(event, menu);
+        break;
+      case KEY.LEFT:
+        this.Left(event, menu);
+        break;
+      case KEY.UP:
+        this.Up(event, menu);
+        break;
+      case KEY.DOWN:
+        this.Down(event, menu);
+        break;
+      case KEY.RETURN:
+      case KEY.SPACE:
+        this.Space(event, menu);
+        break;
+      default:
+        return;
+        break;
+      }
+      return FALSE(event);
+    },
+    Escape: function(event, menu) { },
+    Right: function(event, menu) { },
+    Left: function(event, menu) { },
+    Up: function(event, menu) { },
+    Down: function(event, menu) { },
+    Space: function(event, menu) { }
+  }, {});
+
+
   /*************************************************************/
   /*
    *  The main menu class
    */
-  var MENU = MathJax.Menu = MathJax.Object.Subclass({
+  var MENU = MathJax.Menu = NAV.Subclass({
     version: VERSION,
     items: [],
     posted: false,
     title: null,
     margin: 5,
-    
+
     Init: function (def) {this.items = [].slice.call(arguments,0)},
     With: function (def) {if (def) {HUB.Insert(this,def)}; return this},
 
@@ -234,7 +279,8 @@
       var menu = HTML.Element("div",{
         onmouseup: MENU.Mouseup, ondblclick: FALSE,
         ondragstart: FALSE, onselectstart: FALSE, oncontextmenu: FALSE,
-        menuItem: this, className: "MathJax_Menu"
+        menuItem: this, className: "MathJax_Menu", onkeydown: MENU.Keydown,
+        role: "navigation"
       });
       if (!forceLTR) {MathJax.Localization.setCSS(menu)}
 
@@ -245,21 +291,30 @@
           ontouchstart: MENU.Close, ontouchend: FALSE, onmousedown: MENU.Close, onmouseup: FALSE
         },[["span",{},"\u00D7"]]);
       }
-      
+
       div.appendChild(menu);
       this.posted = true;
-      
       menu.style.width = (menu.offsetWidth+2) + "px";
-      var x = event.pageX, y = event.pageY;
-      if (!x && !y) {
+      if (event) {
+        var x = event.pageX, y = event.pageY;
+      }
+      if (!x && !y && event && event.clientX && event.clientY) {
         x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
         y = event.clientY + document.body.scrollTop  + document.documentElement.scrollTop;
       }
       if (!parent) {
+        var node = MENU.CurrentNode() || event.target;
+        if (!x && !y && node) {
+          var offsetX = window.pageXOffset || document.documentElement.scrollLeft;
+          var offsetY = window.pageYOffset || document.documentElement.scrollTop;
+          var rect = node.getBoundingClientRect();
+          x = (rect.right + rect.left) / 2 + offsetX;
+          y = (rect.bottom + rect.top) / 2 + offsetY;
+        }
         if (x + menu.offsetWidth > document.body.offsetWidth - this.margin)
            {x = document.body.offsetWidth - menu.offsetWidth - this.margin}
         if (MENU.isMobile) {x = Math.max(5,x-Math.floor(menu.offsetWidth/2)); y -= 20}
-        MENU.skipUp = event.isContextMenu;
+        if (event) {MENU.skipUp = event.isContextMenu;}
       } else {
         var side = "left", mw = parent.offsetWidth;
         x = (MENU.isMobile ? 30 : mw - 2); y = 0;
@@ -280,10 +335,19 @@
           menu.style["KhtmlBorderRadiusTop"+side] = 0;  // Konqueror
         }
       }
-      
+
       menu.style.left = x+"px"; menu.style.top = y+"px";
-      
       if (document.selection && document.selection.empty) {document.selection.empty()}
+
+      // Focusing while keeping the scroll position.
+      var oldX = window.pageXOffset || document.documentElement.scrollLeft;
+      var oldY = window.pageYOffset || document.documentElement.scrollTop;
+      MENU.Focus(menu);
+      if (event.type === "keydown") {
+        MENU.skipMouseoverFromKey = true;
+        setTimeout(function() {delete MENU.skipMouseoverFromKey;}, CONFIG.delay);
+      }
+      window.scrollTo(oldX, oldY);
       return FALSE(event);
     },
 
@@ -301,6 +365,7 @@
         delete MENU.jax.hover.nofade;
         HOVER.UnHover(MENU.jax);
       }
+      MENU.Unfocus(menu);
       return FALSE(event);
     },
 
@@ -314,15 +379,15 @@
       for (var i = 0, m = this.items.length; i < m; i++) {
         if (this.items[i].name[n] === name) {
           if (names.length) {
-            if (!this.items[i].menu) {return null}
-            return this.items[i].menu.FindN(n,names[0],names.slice(1));
+            if (!this.items[i].submenu) {return null}
+            return this.items[i].submenu.FindN(n,names[0],names.slice(1));
           }
           return this.items[i];
         }
       }
       return null;
     },
-    
+
     /*
      *  Find the index of a menu item (so we can insert before or after it)
      */
@@ -332,25 +397,49 @@
       for (var i = 0, m = this.items.length; i < m; i++)
         {if (this.items[i].name[n] === name) {return i}}
       return null;
+    },
+
+    Right: function(event, menu) {
+      MENU.Right(event, menu);
+    },
+    Left: function(event, menu) {
+      MENU.Left(event, menu);
+    },
+    Up: function(event, menu) {
+      var node = menu.lastChild;
+      node.menuItem.Activate(event, node);
+    },
+    Down: function(event, menu) {
+      var node = menu.firstChild;
+      node.menuItem.Activate(event, node);
+    },
+    Space: function(event, menu) {
+      this.Remove(event, menu);
     }
-    
   },{
-    
+
     config: CONFIG,
 
-    div: null,     // the DOM elements for the menu and submenus
-
-    Close:      function (event)
-      {return MENU.Event(event,this.menu||this.parentNode,(this.menu?"Touchend":"Remove"))},
     Remove:     function (event) {return MENU.Event(event,this,"Remove")},
     Mouseover:  function (event) {return MENU.Event(event,this,"Mouseover")},
     Mouseout:   function (event) {return MENU.Event(event,this,"Mouseout")},
     Mousedown:  function (event) {return MENU.Event(event,this,"Mousedown")},
     Mouseup:    function (event) {return MENU.Event(event,this,"Mouseup")},
+    Keydown:    function (event) {return MENU.Event(event,this,"Keydown")},
+    /*
+     *  Events for mobile devices.
+     */
     Touchstart: function (event) {return MENU.Event(event,this,"Touchstart")},
     Touchend:   function (event) {return MENU.Event(event,this,"Touchend")},
+    Close:      function (event) {
+      return MENU.Event(event,this.menu||this.parentNode,(this.menu?"Touchend":"Remove"));
+    },
     Event: function (event,menu,type,force) {
       if (MENU.skipMouseover && type === "Mouseover" && !force) {return FALSE(event)}
+      if (MENU.skipMouseoverFromKey && type === "Mouseover") {
+        delete MENU.skipMouseoverFromKey;
+        return FALSE(event);
+      }
       if (MENU.skipUp) {
         if (type.match(/Mouseup|Touchend/)) {delete MENU.skipUp; return FALSE(event)}
         if (type === "Touchstart" ||
@@ -361,7 +450,6 @@
       if (item && item[type]) {return item[type](event,menu)}
       return null;
     },
-
     /*
      *  Style for the background DIV
      */
@@ -371,7 +459,8 @@
     },
 
     Background: function (menu) {
-      var div = HTML.addElement(document.body,"div",{style:this.BGSTYLE, id:"MathJax_MenuFrame"},
+      var div = HTML.addElement(document.body,"div",
+                    {style:this.BGSTYLE, id:"MathJax_MenuFrame"},
                     [["div",{style: this.BGSTYLE, menuItem: menu, onmousedown: this.Remove}]]);
       var bg = div.firstChild;
       if (MENU.msieBackgroundBug) {
@@ -400,32 +489,109 @@
         bg.style.height = document.body.scrollHeight + "px";
       }
     },
+
+    /*************************************************************/
+    /*
+     *  Keyboard navigation of menu.
+     */
+    posted: false,  // Is a menu open?
+    active: null,   // The focused in HTML node in the menu.
+
+    GetNode: function(jax) {
+      var node = document.getElementById(jax.inputID + "-Frame");
+      return node.isMathJax ? node : node.firstChild;
+    },
+    CurrentNode: function() {
+      return MENU.GetNode(MENU.jax);
+    },
+    AllNodes: function() {
+      var jaxs = MathJax.Hub.getAllJax();
+      var nodes = [];
+      for (var i = 0, jax; jax = jaxs[i]; i++) {
+        nodes.push(MENU.GetNode(jax));
+      }
+      return nodes;
+    },
+    ActiveNode: function() {
+      return MENU.active;
+    },
+    FocusNode: function(node) {
+      MENU.active = node;
+      node.focus();
+    },
+    //
+    // Focus is a global affair, since we only ever want a single focused item.
+    //
+    Focus: function(menu) {
+      !MENU.posted ? MENU.Activate(menu) : MENU.ActiveNode().tabIndex = -1;
+      menu.tabIndex = 0;
+      MENU.FocusNode(menu);
+    },
+    Activate: function(event, menu) {
+      var jaxs = MENU.AllNodes();
+      for (var j = 0, jax; jax = jaxs[j]; j++) {
+        jax.tabIndex = -1;
+      }
+      MENU.posted = true;
+    },
+    Unfocus: function() {
+      MENU.ActiveNode().tabIndex = -1;
+      var jaxs = MENU.AllNodes();
+      for (var j = 0, jax; jax = jaxs[j]; j++) {
+        jax.tabIndex = 0;
+      }
+      MENU.FocusNode(MENU.CurrentNode());
+      MENU.posted = false;
+    },
+    MoveHorizontal: function(event, menu, move) {
+      if (!event.shiftKey) return;
+      var jaxs = MENU.AllNodes();
+      var len = jaxs.length;
+      if (len === 0) return;
+      var next = jaxs[MENU.Mod(move(MENU.IndexOf(jaxs, MENU.CurrentNode())), len)];
+      if (next === MENU.CurrentNode()) return;
+      MENU.menu.Remove(event, menu);
+      MENU.jax = MathJax.Hub.getJaxFor(next);
+      MENU.FocusNode(next);
+      MENU.menu.Post(null);
+    },
+    Right: function(event, menu) {
+      MENU.MoveHorizontal(event, menu, function(x) {return x + 1;});
+    },
+    Left: function(event, menu) {
+      MENU.MoveHorizontal(event, menu, function(x) {return x - 1;});
+    },
+
+    //TODO: Move to utility class.
+    // Computes a mod n.
+    Mod: function(a, n) {
+      return ((a % n) + n) % n;
+    },
+    IndexOf: (Array.prototype.indexOf ?
+              function (A, item, start) {return A.indexOf(item, start);} :
+              function (A, item, start) {
+                for (var i = (start || 0), j = A.length; i < j; i++) {
+                  if (item === A[i]) return i;
+                }
+                return -1;
+              }),
     
     saveCookie: function () {HTML.Cookie.Set("menu",this.cookie)},
     getCookie: function () {this.cookie = HTML.Cookie.Get("menu")}
 
   });
 
+  MathJax.Menu.NAV = NAV;
+
   /*************************************************************/
   /*
    *  Abstract class of menu items.
    */
-  var ITEM = MENU.ITEM = MathJax.Object.Subclass({
-    name: "", // the menu item's label as [id,label] pair
-    node: null,
+  var ITEM = MENU.ITEM = NAV.Subclass({
 
-    /*
-     *  Accessor method for node.
-     */
-    GetNode: function() {
-      return this.node;
-    },
-    /*
-     *  Registers the HTML node of the menu item.
-     */
-    SetNode: function(node) {
-      this.node = node;
-    },
+    name: "", // The menu item's label as [id,label] pair.
+    node: null,  // The HTML node of the item.
+    menu: null,  // The parent menu containing that item. HTML node.
 
     Attributes: function(def) {
       return HUB.Insert(
@@ -435,40 +601,51 @@
          className: "MathJax_MenuItem", menuItem: this},
         def);
     },
+
     Create: function (menu) {
       if (!this.hidden) {
         var def = this.Attributes();
         var label = this.Label(def,menu);
         var node = HTML.addElement(menu, "div", def, label);
-        this.SetNode(node);
       }
     },
     Name: function () {return _(this.name[0],this.name[1])},
 
     Mouseover: function (event,menu) {
-      if (!this.disabled) {this.Activate(menu)}
-      if (!this.menu || !this.menu.posted) {
-        var menus = document.getElementById("MathJax_MenuFrame").childNodes,
-            items = menu.parentNode.childNodes;
-        for (var i = 0, m = items.length; i < m; i++) {
-          var item = items[i].menuItem;
-          if (item && item.menu && item.menu.posted) {item.Deactivate(items[i])}
-        }
-        m = menus.length-1;
-        while (m >= 0 && menu.parentNode.menuItem !== menus[m].menuItem) {
-          menus[m].menuItem.posted = false;
-          menus[m].parentNode.removeChild(menus[m]);
-          m--;
-        }
-        if (this.Timer && !MENU.isMobile) {this.Timer(event,menu)}
+      if (menu.parentNode === MENU.ActiveNode().parentNode) {
+       this.Deactivate(MENU.ActiveNode());
       }
+      this.Activate(event, menu);
     },
     Mouseout: function (event,menu) {
-      if (!this.menu || !this.menu.posted) {this.Deactivate(menu)}
-      if (this.timer) {clearTimeout(this.timer); delete this.timer}
+      this.Deactivate(menu);
     },
     Mouseup: function (event,menu) {return this.Remove(event,menu)},
-    
+
+
+    DeactivateSubmenus: function(menu) {
+      var menus = document.getElementById("MathJax_MenuFrame").childNodes,
+          items = ITEM.GetMenuNode(menu).childNodes;
+      for (var i = 0, m = items.length; i < m; i++) {
+        var item = items[i].menuItem;
+        // Deactivates submenu items.
+        if (item && item.submenu && item.submenu.posted &&
+            item !== menu.menuItem) {
+          item.Deactivate(items[i]);
+        }
+      }
+      this.RemoveSubmenus(menu, menus);
+    },
+    RemoveSubmenus: function(menu, menus) {
+      menus = menus || document.getElementById("MathJax_MenuFrame").childNodes;
+      var m = menus.length-1;
+      while (m >= 0 && ITEM.GetMenuNode(menu).menuItem !== menus[m].menuItem) {
+        menus[m].menuItem.posted = false;
+        menus[m].parentNode.removeChild(menus[m]);
+        m--;
+      }
+    },
+
     Touchstart: function (event,menu) {return this.TouchEvent(event,menu,"Mousedown")},
     Touchend: function (event,menu)   {return this.TouchEvent(event,menu,"Mouseup")},
     TouchEvent: function (event,menu,type) {
@@ -481,19 +658,20 @@
       MENU.Event(event,menu,type);
       return false;
     },
-    
+
     Remove: function (event,menu) {
       menu = menu.parentNode.menuItem;
       return menu.Remove(event,menu);
     },
 
-    Activate: function (menu) {this.Deactivate(menu); menu.className += " MathJax_MenuActive"},
-    Deactivate: function (menu) {menu.className = menu.className.replace(/ MathJax_MenuActive/,"")},
-
     With: function (def) {if (def) {HUB.Insert(this,def)}; return this},
-    
+
     isRTL: function () {return MENU.isRTL},
     rtlClass: function () {return (this.isRTL() ? " RTL" : "")}
+  }, {
+    GetMenuNode: function(item) {
+      return item.parentNode;
+    }
   });
 
   /*************************************************************/
@@ -503,20 +681,90 @@
   MENU.ENTRY = MENU.ITEM.Subclass({
 
     role: "menuitem",  // Aria role.
-    
-    Attributes: function() {
-      var def = this.SUPER(arguments).Attributes.call(
-        this,
+
+    Attributes: function(def) {
+      def = HUB.Insert(
         {onmouseover: MENU.Mouseover, onmouseout: MENU.Mouseout,
          onmousedown: MENU.Mousedown, role: this.role,
-         'aria-disabled': !!this.disabled});
+         onkeydown: MENU.Keydown,
+         "aria-disabled": !!this.disabled},
+        def);
+      def = this.SUPER(arguments).Attributes.call(this, def);
       if (this.disabled) {
         def.className += " MathJax_MenuDisabled";
       }
       return def;
+    },
+    MoveVertical: function(event, item, move) {
+      var menuNode = ITEM.GetMenuNode(item);
+      var items = [];
+      for (var i = 0, allItems = menuNode.menuItem.items, it;
+           it = allItems[i]; i++) {
+        if (!it.hidden) {
+          items.push(it);
+        }
+      }
+      var index = MENU.IndexOf(items, this);
+      if (index === -1) return;
+      var len = items.length;
+      var children = menuNode.childNodes;
+      do {
+        index = MENU.Mod(move(index), len);
+      } while (items[index].hidden || !children[index].role);
+      this.Deactivate(item);
+      items[index].Activate(event, children[index]);
+    },
+    Up: function(event, item) {
+      this.MoveVertical(event, item, function(x) { return x - 1; });
+    },
+    Down: function(event, item) {
+      this.MoveVertical(event, item, function(x) { return x + 1; });
+    },
+    Right: function(event, item) {
+      this.MoveHorizontal(event, item, MENU.Right, !this.isRTL());
+    },
+    Left: function(event, item) {
+      this.MoveHorizontal(event, item, MENU.Left, this.isRTL());
+    },
+    MoveHorizontal: function(event, item, move, rtl) {
+      var menuNode = ITEM.GetMenuNode(item);
+      if (menuNode.menuItem === MENU.menu && event.shiftKey) {
+        move(event, item);
+      }
+      if (rtl) return;
+      if (menuNode.menuItem !== MENU.menu) {
+        this.Deactivate(item);
+      }
+      var parentNodes = menuNode.previousSibling.childNodes;
+      var length = parentNodes.length;
+      while (length--) {
+        var parent = parentNodes[length];
+        if (parent.menuItem.submenu &&
+            parent.menuItem.submenu === menuNode.menuItem) {
+          MENU.Focus(parent);
+          break;
+        }
+      }
+      this.RemoveSubmenus(item);
+    },
+    Space: function (event, menu) {
+      this.Mouseup(event, menu);
+    },
+
+    Activate: function (event, menu) {
+      this.Deactivate(menu);
+      if (!this.disabled) {
+        menu.className += " MathJax_MenuActive";
+      }
+      this.DeactivateSubmenus(menu);
+      MENU.Focus(menu);
+    },
+    Deactivate: function (menu) {
+      menu.className = menu.className.replace(/ MathJax_MenuActive/,"");
     }
+
   });
-  
+
   /*************************************************************/
   /*
    *  A menu item that performs a command when selected
@@ -529,7 +777,7 @@
       this.name = name; this.action = action;
       this.With(def);
     },
-    
+
     Label: function (def,menu) {return [this.Name()]},
     Mouseup: function (event,menu) {
       if (!this.disabled) {
@@ -546,7 +794,7 @@
    *  A menu item that posts a submenu
    */
   MENU.ITEM.SUBMENU = MENU.ENTRY.Subclass({
-    menu: null,        // the submenu
+    submenu: null,        // the submenu
     marker: "\u25BA",  // the submenu arrow
     markerRTL: "\u25C4", // the submenu arrow for RTL
 
@@ -554,43 +802,83 @@
       if (!(name instanceof Array)) {name = [name,name]}  // make [id,label] pair
       this.name = name; var i = 1;
       if (!(def instanceof MENU.ITEM)) {this.With(def), i++}
-      this.menu = MENU.apply(MENU,[].slice.call(arguments,i));
+      this.submenu = MENU.apply(MENU,[].slice.call(arguments,i));
     },
     Label: function (def,menu) {
-      this.menu.posted = false;
+      this.submenu.posted = false;
       return [this.Name()+" ",["span",{
         className:"MathJax_MenuArrow" + this.rtlClass()
       },[this.isRTL() ? this.markerRTL : this.marker]]];
     },
     Timer: function (event,menu) {
-      if (this.timer) {clearTimeout(this.timer)}
-      event = {clientX: event.clientX, clientY: event.clientY}; // MSIE can't pass the event below
+      this.ClearTimer();
+      event = {type: event.type,
+               clientX: event.clientX, clientY: event.clientY}; // MSIE can't pass the event below
       this.timer = setTimeout(CALLBACK(["Mouseup",this,event,menu]),CONFIG.delay);
     },
+    ClearTimer: function() {
+      if (this.timer) {
+        clearTimeout(this.timer);
+      }
+    },
     Touchend: function (event,menu) {
-      var forceout = this.menu.posted;
+      var forceout = this.submenu.posted;
       var result = this.SUPER(arguments).Touchend.apply(this,arguments);
       if (forceout) {this.Deactivate(menu); delete ITEM.lastItem; delete ITEM.lastMenu}
       return result;
     },
+    Mouseout: function(event, menu) {
+      if (!this.submenu.posted) {
+        this.Deactivate(menu);
+      }
+      this.ClearTimer();
+    },
+    Mouseover: function(event, menu) {
+      this.Activate(event, menu);
+    },
     Mouseup: function (event,menu) {
       if (!this.disabled) {
-        if (!this.menu.posted) {
-          if (this.timer) {clearTimeout(this.timer); delete this.timer}
-          this.menu.Post(event,menu,this.ltr);
+        if (!this.submenu.posted) {
+          this.ClearTimer();
+          this.submenu.Post(event, menu, this.ltr);
+          MENU.Focus(menu);
         } else {
-         var menus = document.getElementById("MathJax_MenuFrame").childNodes,
-              m = menus.length-1;
-          while (m >= 0) {
-            var child = menus[m];
-            child.menuItem.posted = false;
-            child.parentNode.removeChild(child);
-            if (child.menuItem === this.menu) {break};
-            m--;
-          }
+          this.DeactivateSubmenus(menu);
         }
       }
       return FALSE(event);
+    },
+    Activate: function (event, menu) {
+      if (!this.disabled) {
+        this.Deactivate(menu);
+        menu.className += " MathJax_MenuActive";
+      }
+      if (!this.submenu.posted) {
+        this.DeactivateSubmenus(menu);
+        if (!MENU.isMobile) {
+          this.Timer(event,menu);
+        }
+      }
+      MENU.Focus(menu);
+    },
+    MoveVertical: function(event, item, move) {
+      this.ClearTimer();
+      this.SUPER(arguments).MoveVertical.apply(this, arguments);
+    },
+    MoveHorizontal: function(event, menu, move, rtl) {
+      if (!rtl) {
+        this.SUPER(arguments).MoveHorizontal.apply(this, arguments);
+        return;
+      }
+      if (this.disabled) return;
+      if (!this.submenu.posted) {
+        this.Activate(event, menu);
+        return;
+      }
+      var submenuNodes = ITEM.GetMenuNode(menu).nextSibling.childNodes;
+      if (submenuNodes.length > 0) {
+        this.submenu.items[0].Activate(event, submenuNodes[0]);
+      }
     }
   });
 
@@ -602,7 +890,7 @@
     variable: null,     // the variable name
     marker: (isPC ? "\u25CF" : "\u2713"),   // the checkmark
     role: "menuitemradio",
-    
+
     Init: function (name,variable,def) {
       if (!(name instanceof Array)) {name = [name,name]}  // make [id,label] pair
       this.name = name; this.variable = variable; this.With(def);
@@ -621,7 +909,7 @@
           if (item && item.variable === this.variable)
             {child[i].firstChild.style.display = "none"}
         }
-        menu.firstChild.display = ""; 
+        menu.firstChild.display = "";
         CONFIG.settings[this.variable] = this.value;
         MENU.cookie[this.variable] = CONFIG.settings[this.variable]; MENU.saveCookie();
         SIGNAL.Post(["radio button",this]);
@@ -667,7 +955,9 @@
   /*
    *  A menu item that is a label
    */
-  MENU.ITEM.LABEL = MENU.ITEM.Subclass({
+  MENU.ITEM.LABEL = MENU.ENTRY.Subclass({
+    role: "menuitem",  // Aria role.
+
     Init: function (name,def) {
       if (!(name instanceof Array)) {name = [name,name]}  // make [id,label] pair
       this.name = name; this.With(def);
@@ -675,7 +965,12 @@
     Label: function (def,menu) {
       def.className += " MathJax_MenuLabel";
       return [this.Name()];
-    }
+    },
+    Activate: function(event, menu) {
+      this.Deactivate(menu);
+      MENU.Focus(menu);
+    },
+    Mouseup: function (event,menu) { }
   });
 
   /*************************************************************/
@@ -688,7 +983,7 @@
       return null;
     }
   });
-  
+
   /*************************************************************/
   /*************************************************************/
 
@@ -697,13 +992,8 @@
    */
   MENU.About = function () {
     var HTMLCSS = OUTPUT["HTML-CSS"] || {};
-    var font = 
-       (HTMLCSS.imgFonts ? "image" :
-       (HTMLCSS.fontInUse ?
-         (HTMLCSS.webFonts ? "web" : "local")+" "+HTMLCSS.fontInUse :
-       (OUTPUT.SVG ? "web SVG" : "generic")) ) + " fonts";
-    var format = (!HTMLCSS.webFonts || HTMLCSS.imgFonts ? null :
-        HTMLCSS.allowWebFonts.replace(/otf/,"woff or otf") + " fonts");
+    var font = MENU.About.GetFont();
+    var format = MENU.About.GetFormat();
     var jax = ["MathJax.js v"+MathJax.fileversion,["br"]];
     jax.push(["div",{style:{"border-top":"groove 2px",margin:".25em 0"}}]);
     MENU.About.GetJax(jax,MathJax.InputJax,["InputJax","%1 Input Jax v%2"]);
@@ -712,24 +1002,28 @@
     jax.push(["div",{style:{"border-top":"groove 2px",margin:".25em 0"}}]);
     MENU.About.GetJax(jax,MathJax.Extension,["Extension","%1 Extension v%2"],true);
     jax.push(["div",{style:{"border-top":"groove 2px",margin:".25em 0"}}],["center",{},[
-      HUB.Browser + " v"+HUB.Browser.version + (format ? 
+      HUB.Browser + " v"+HUB.Browser.version + (format ?
         " \u2014 " + _(format.replace(/ /g,""),format) : "")
     ]]);
     MENU.About.div = MENU.Background(MENU.About);
     var about = HTML.addElement(MENU.About.div,"div",{
-      id: "MathJax_About"
+      id: "MathJax_About", tabIndex: 0, onkeydown: MENU.About.Keydown
     },[
       ["b",{style:{fontSize:"120%"}},["MathJax"]]," v"+MathJax.version,["br"],
       _(font.replace(/ /g,""),"using "+font),["br"],["br"],
       ["span",{style:{
         display:"inline-block", "text-align":"left", "font-size":"80%",
-        "max-height":"20em", overflow:"auto", 
+        "max-height":"20em", overflow:"auto",
         "background-color":"#E4E4E4", padding:".4em .6em", border:"1px inset"
-      }},jax],["br"],["br"],
+      }, tabIndex: 0},jax],["br"],["br"],
       ["a",{href:"http://www.mathjax.org/"},["www.mathjax.org"]],
-      ["span",{className:"MathJax_MenuClose",id:"MathJax_AboutClose",onclick:MENU.About.Remove},
+      ["span",{className:"MathJax_MenuClose",id:"MathJax_AboutClose",
+               onclick:MENU.About.Remove,
+               onkeydown: MENU.About.Keydown, tabIndex: 0,
+               "aria-label": "Close", "aria-describedby": "Close window"},
         [["span",{},"\u00D7"]]]
     ]);
+    about.focus();
     MathJax.Localization.setCSS(about);
     var doc = (document.documentElement||{});
     var H = window.innerHeight || doc.clientHeight || doc.scrollHeight || 0;
@@ -745,6 +1039,15 @@
   MENU.About.Remove = function (event) {
     if (MENU.About.div) {document.body.removeChild(MENU.About.div); delete MENU.About.div}
   };
+  MENU.About.Keydown = function(event) {
+    if (event.keyCode === KEY.ESCAPE ||
+        (this.id === "MathJax_AboutClose" &&
+         (event.keyCode === KEY.SPACE || event.keyCode === KEY.RETURN))) {
+      MENU.About.Remove(event);
+      MENU.CurrentNode().focus();
+      FALSE(event);
+    }
+  },
   MENU.About.GetJax = function (jax,JAX,type,noTypeCheck) {
     var info = [];
     for (var id in JAX) {if (JAX.hasOwnProperty(id) && JAX[id]) {
@@ -755,8 +1058,22 @@
     for (var i = 0, m = info.length; i < m; i++) {jax.push(info[i],["br"])}
     return jax;
   };
+  MENU.About.GetFont = function () {
+    var jax = MathJax.Hub.outputJax["jax/mml"][0] || {};
+    var font = {
+      SVG: "web SVG",
+      CommonHTML: "web TeX",
+      "HTML-CSS": (jax.imgFonts ? "image" : (jax.webFonts ? "web" : "local")+" "+jax.fontInUse)
+    }[jax.id] || "generic";
+    return font + " fonts";
+  };
+  MENU.About.GetFormat = function () {
+    var jax = MathJax.Hub.outputJax["jax/mml"][0] || {};
+    if (jax.id !== "HTML-CSS"|| !jax.webFonts || jax.imgFonts) return;
+    return jax.allowWebFonts.replace(/otf/,"woff or otf") + " fonts";
+  };
+
 
-  
   /*
    *  Handle the MathJax HELP menu
    */
@@ -764,7 +1081,7 @@
     AJAX.Require("[MathJax]/extensions/HelpDialog.js",
                  function () {MathJax.Extension.Help.Dialog()});
   };
-  
+
   /*
    *  Handle showing of element's source
    */
@@ -835,7 +1152,7 @@
       var table = w.document.body.firstChild;
       setTimeout(function () {
         var H = (w.outerHeight-w.innerHeight)||30, W = (w.outerWidth-w.innerWidth)||30, x, y;
-        W = Math.max(100,Math.min(Math.floor(.5*screen.width),table.offsetWidth+W+25));
+        W = Math.max(140,Math.min(Math.floor(.5*screen.width),table.offsetWidth+W+25));
         H = Math.max(40,Math.min(Math.floor(.5*screen.height),table.offsetHeight+H+25));
         if (MENU.prototype.msieHeightBug) {H += 35}; // for title bar in XP
         w.resizeTo(W,H);
@@ -848,7 +1165,7 @@
       },50);
     }
   };
-  
+
   /*
    *  Handle rescaling all the math
    */
@@ -872,14 +1189,14 @@
                       "The scale should be a percentage (e.g., 120%%)"))}
     }
   };
-  
+
   /*
    *  Handle loading the zoom code
    */
   MENU.Zoom = function () {
     if (!MathJax.Extension.MathZoom) {AJAX.Require("[MathJax]/extensions/MathZoom.js")}
   };
-  
+
   /*
    *  Handle changing the renderer
    */
@@ -893,9 +1210,10 @@
       switch (CONFIG.settings.renderer) {
         case "NativeMML":
           if (!CONFIG.settings.warnedMML) {
-            if (BROWSER.isChrome && BROWSER.version.substr(0,3) !== "24.") {message = MESSAGE.MML.WebKit} 
+            if (BROWSER.isChrome && BROWSER.version.substr(0,3) !== "24.") {message = MESSAGE.MML.WebKit}
             else if (BROWSER.isSafari && !BROWSER.versionAtLeast("5.0")) {message = MESSAGE.MML.WebKit}
             else if (BROWSER.isMSIE) {if (!BROWSER.hasMathPlayer) {message = MESSAGE.MML.MSIE}}
+            else if (BROWSER.isEdge) {message = MESSAGE.MML.WebKit}
             else {message = MESSAGE.MML[BROWSER]}
             warned = "warnedMML";
           }
@@ -905,7 +1223,7 @@
           if (!CONFIG.settings.warnedSVG) {
             if (BROWSER.isMSIE && !isIE9) {message = MESSAGE.SVG.MSIE}
           }
-          break;  
+          break;
       }
       if (message) {
         message = _(message[0],message[1]);
@@ -938,7 +1256,7 @@
       MSIE:    ["MSIENativeMMLWarning",
                  "Internet Explorer requires the MathPlayer plugin " +
                  "in order to process MathML output."],
-      
+
       Opera:   ["OperaNativeMMLWarning",
                  "Opera's support for MathML is limited, so switching to " +
                  "MathML output may cause some expressions to render poorly."],
@@ -951,7 +1269,7 @@
                  "Your browser's native MathML does not implement all the features " +
                  "used by MathJax, so some expressions may not render properly."]
     },
-    
+
     SVG: {
       MSIE:    ["MSIESVGWarning",
                  "SVG is not implemented in Internet Explorer prior to " +
@@ -960,7 +1278,7 @@
                  "not display properly."]
     }
   };
-  
+
   /*
    *  Handle setting the HTMLCSS fonts
    */
@@ -968,7 +1286,7 @@
     var HTMLCSS = OUTPUT["HTML-CSS"]; if (!HTMLCSS) return;
     document.location.reload();
   };
-  
+
   /*
    *  Handle selection of locale and rerender the page
    */
@@ -990,7 +1308,7 @@
       });
     }
   };
-  
+
   /*
    *  Handle setting MathPlayer events
    */
@@ -1023,7 +1341,7 @@
       "The MathJax contextual menu will be disabled, but you can " +
       "Alt-Click on an expression to obtain the MathJax menu instead."]
   };
-  
+
   /*************************************************************/
   /*************************************************************/
 
@@ -1059,7 +1377,7 @@
   //
   MENU.CreateLocaleMenu = function () {
     if (!MENU.menu) return;
-    var menu = MENU.menu.Find("Language").menu, items = menu.items;
+    var menu = MENU.menu.Find("Language").submenu, items = menu.items;
     //
     //  Get the names of the languages and sort them
     //
@@ -1085,7 +1403,7 @@
   //
   MENU.CreateAnnotationMenu = function () {
     if (!MENU.menu) return;
-    var menu = MENU.menu.Find("Show Math As","Annotation").menu;
+    var menu = MENU.menu.Find("Show Math As","Annotation").submenu;
     var annotations = CONFIG.semanticsAnnotations;
     for (var a in annotations) {
       if (annotations.hasOwnProperty(a)) {
@@ -1154,7 +1472,8 @@
           ITEM.RADIO("MathML",     "renderer", {action: MENU.Renderer, value:"NativeMML"}),
           ITEM.RADIO("SVG",        "renderer", {action: MENU.Renderer}),
           ITEM.RULE(),
-          ITEM.CHECKBOX("Fast Preview", "FastPreview")
+          ITEM.CHECKBOX("Fast Preview", "FastPreview"),
+          ITEM.CHECKBOX("Assistive MathML", "assistiveMML", {hidden:!CONFIG.showAssistiveMML})
         ),
         ITEM.SUBMENU("MathPlayer",  {hidden:!HUB.Browser.isMSIE || !CONFIG.showMathPlayer,
                                                     disabled:!HUB.Browser.hasMathPlayer},
@@ -1201,11 +1520,11 @@
     if (MENU.isMobile) {
       (function () {
         var settings = CONFIG.settings;
-        var trigger = MENU.menu.Find("Math Settings","Zoom Trigger").menu;
+        var trigger = MENU.menu.Find("Math Settings","Zoom Trigger").submenu;
         trigger.items[0].disabled = trigger.items[1].disabled = true;
         if (settings.zoom === "Hover" || settings.zoom == "Click") {settings.zoom = "None"}
         trigger.items = trigger.items.slice(0,4);
-    
+
         if (navigator.appVersion.match(/[ (]Android[) ]/)) {
           MENU.ITEM.SUBMENU.Augment({marker: "\u00BB"});
         }
@@ -1215,7 +1534,7 @@
     MENU.CreateLocaleMenu();
     MENU.CreateAnnotationMenu();
   });
-  
+
   MENU.showRenderer = function (show) {
     MENU.cookie.showRenderer = CONFIG.showRenderer = show; MENU.saveCookie();
     MENU.menu.Find("Math Settings","Math Renderer").hidden = !show;
@@ -1241,12 +1560,16 @@
     MENU.cookie.showLocale = CONFIG.showLocale = show; MENU.saveCookie();
     MENU.menu.Find("Language").hidden = !show;
   };
+  MENU.showAssistiveMML = function (show) {
+    MENU.cookie.showAssistiveMML = CONFIG.showAssistiveMML = show; MENU.saveCookie();
+    MENU.menu.Find("Math Settings","Math Renderer","Assistive MathML").hidden = !show;
+  };
   
   MathJax.Hub.Register.StartupHook("HTML-CSS Jax Ready",function () {
     if (!MathJax.OutputJax["HTML-CSS"].config.imageFont)
       {MENU.menu.Find("Math Settings","Font Preference","TeX (image)").disabled = true}
   });
-  
+
   /*************************************************************/
 
   CALLBACK.Queue(
diff --git a/unpacked/extensions/TeX/AMSmath.js b/unpacked/extensions/TeX/AMSmath.js
index 545135362..c6d974b21 100644
--- a/unpacked/extensions/TeX/AMSmath.js
+++ b/unpacked/extensions/TeX/AMSmath.js
@@ -134,14 +134,14 @@ MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
       aligned:       ['AlignedAMSArray',null,null,null,'rlrlrlrlrlrl',COLS([0,2,0,2,0,2,0,2,0,2,0]),".5em",'D'],
       gathered:      ['AlignedAMSArray',null,null,null,'c',null,".5em",'D'],
 
-      subarray:      ['Array',null,null,null,null,COLS([0,0,0,0]),"0.1em",'S',1],
+      subarray:      ['Array',null,null,null,null,COLS([0]),"0.1em",'S',1],
       smallmatrix:   ['Array',null,null,null,'c',COLS([1/3]),".2em",'S',1],
       
       'equation':    ['EquationBegin','Equation',true],
       'equation*':   ['EquationBegin','EquationStar',false],
 
-      eqnarray:      ['AMSarray',null,true,true, 'rcl',MML.LENGTH.THICKMATHSPACE,".5em"],
-      'eqnarray*':   ['AMSarray',null,false,true,'rcl',MML.LENGTH.THICKMATHSPACE,".5em"]
+      eqnarray:      ['AMSarray',null,true,true, 'rcl',COLS([0]),".5em"],
+      'eqnarray*':   ['AMSarray',null,false,true,'rcl',COLS([0]),".5em"]
     },
     
     delimiter: {
diff --git a/unpacked/extensions/mml2jax.js b/unpacked/extensions/mml2jax.js
index a348bc55e..8edb8d5c1 100644
--- a/unpacked/extensions/mml2jax.js
+++ b/unpacked/extensions/mml2jax.js
@@ -99,8 +99,8 @@ MathJax.Extension.mml2jax = {
     }
     for (var i = 0, m = math.length; i < m; i++) {
       var parent = math[i].parentNode;
-      if (parent && parent.className !== preview && !math[i].prefix === !namespace)
-        {array.push(math[i])}
+      if (parent && parent.className !== preview &&
+         !parent.isMathJax && !math[i].prefix === !namespace) array.push(math[i]);
     }
   },
   
diff --git a/unpacked/jax/output/CommonHTML/autoload/mmultiscripts.js b/unpacked/jax/output/CommonHTML/autoload/mmultiscripts.js
index e412a1c91..1a1914e17 100644
--- a/unpacked/jax/output/CommonHTML/autoload/mmultiscripts.js
+++ b/unpacked/jax/output/CommonHTML/autoload/mmultiscripts.js
@@ -45,7 +45,7 @@ MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
       //
       var base, bbox;
       if (stretch) {
-        base = node.getElementsByTagName("mjx-base")[0];
+        base = CHTML.getNode(node,"mjx-base");
       } else {
         this.CHTMLaddChild(node,0,{type:"mjx-base", noBBox:true, forceChild:true});
         base = node.firstChild;
@@ -137,10 +137,10 @@ MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
     //
     CHTMLgetScripts: function (BOX,BBOX,stretch,node) {
       if (stretch) {
-        BOX.sub = node.getElementsByTagName("mjx-sub")[0];
-        BOX.sup = node.getElementsByTagName("mjx-sup")[0];
-        BOX.presub = node.getElementsByTagName("mjx-presub")[0];
-        BOX.presup = node.getElementsByTagName("mjx-presup")[0];
+        BOX.sub = CHTML.getNode(node,"mjx-sub");
+        BOX.sup = CHTML.getNode(node,"mjx-sup");
+        BOX.presub = CHTML.getNode(node,"mjx-presub");
+        BOX.presup = CHTML.getNode(node,"mjx-presup");
         BBOX.sub = this.CHTMLbbox.sub;
         BBOX.sup = this.CHTMLbbox.sup;
         BBOX.presub = this.CHTMLbbox.presub;
@@ -182,7 +182,7 @@ MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
           BBOX = state.BBOX[type] = CHTML.BBOX.empty();
           if (state.w) {
             BOX.style.paddingLeft = CHTML.Em(state.w);
-            BBOX.w = BBOX.r = state.w;
+            BBOX.w = BBOX.r = state.w; BBOX.x = state.w;
           }
         }
         data.toCommonHTML(BOX);
@@ -198,7 +198,7 @@ MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
     //  right-justify the scripts, otherwise, left-justify them.
     //
     CHTMLpadScript: function (type,w,bbox,state) {
-      if (!bbox) bbox = {w:0, fake:1};
+      if (!bbox) bbox = {w:0, fake:1, rscale:1};
       var BBOX = state.BBOX[type], dx = 0, dw = 0;
       if (BBOX) {
         if (bbox.rscale*bbox.w < w) {
@@ -252,7 +252,7 @@ MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
     CHTMLplaceSubSup: function (sub,sbox,sup,Sbox,x,delta,u,v,s) {
       sub.style.paddingRight = CHTML.Em(s); sbox.w += s;
       sup.style.paddingBottom = CHTML.Em(u+v-Sbox.d-sbox.h);
-      sup.style.paddingLeft = CHTML.Em(delta);
+      sup.style.paddingLeft = CHTML.Em(delta+(Sbox.x||0));
       sup.style.paddingRight = CHTML.Em(s); Sbox.w += s;
       sup.parentNode.style.verticalAlign = CHTML.Em(-v);
       this.CHTML.combine(sbox,x,-v);
@@ -272,7 +272,7 @@ MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
     CHTMLplacePresubPresup: function (presub,pbox,presup,Pbox,delta,u,v,s) {
       presub.style.paddingLeft = CHTML.Em(s);
       presup.style.paddingBottom = CHTML.Em(u+v-Pbox.d-pbox.h);
-      presup.style.paddingLeft = CHTML.Em(delta+s);
+      presup.style.paddingLeft = CHTML.Em(delta+s+(Pbox.x||0));
       presup.style.paddingRight = CHTML.Em(-delta);
       presup.parentNode.style.verticalAlign = CHTML.Em(-v);
       this.CHTML.combine(pbox,s,-v);
diff --git a/unpacked/jax/output/CommonHTML/autoload/multiline.js b/unpacked/jax/output/CommonHTML/autoload/multiline.js
index 3b30c07f4..fcccc549a 100644
--- a/unpacked/jax/output/CommonHTML/autoload/multiline.js
+++ b/unpacked/jax/output/CommonHTML/autoload/multiline.js
@@ -505,9 +505,9 @@ MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
       //
       if (end.length === 0) {
         var NODE = this.CHTMLnodeElement(),
-            stack = NODE.getElementsByTagName("mjx-stack")[0],
-            sup = NODE.getElementsByTagName("mjx-sup")[0],
-            sub = NODE.getElementsByTagName("mjx-sub")[0];
+            stack = CHTML.getNode(NODE,"mjx-stack"),
+            sup = CHTML.getNode(NODE,"mjx-sup"),
+            sub = CHTML.getNode(NODE,"mjx-sub");
         if (stack)      node.appendChild(stack);
           else if (sup) node.appendChild(sup);
           else if (sub) node.appendChild(sub);
@@ -569,9 +569,9 @@ MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
       //
       if (start.length < 1) {
         NODE = this.CHTMLnodeElement();
-        var prestack = NODE.getElementsByTagName("mjx-prestack")[0],
-            presup = NODE.getElementsByTagName("mjx-presup")[0],
-            presub = NODE.getElementsByTagName("mjx-presub")[0];
+        var prestack = CHTML.getNode(NODE,"mjx-prestack"),
+            presup = CHTML.getNode(NODE,"mjx-presup"),
+            presub = CHTML.getNode(NODE,"mjx-presub");
         if (prestack)      node.appendChild(prestack);
           else if (presup) node.appendChild(presup);
           else if (presub) node.appendChild(presub);
@@ -598,9 +598,9 @@ MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
       //
       if (end.length === 0) {
         NODE = this.CHTMLnodeElement();
-        var stack = NODE.getElementsByTagName("mjx-stack")[0],
-            sup = NODE.getElementsByTagName("mjx-sup")[0],
-            sub = NODE.getElementsByTagName("mjx-sub")[0];
+        var stack = CHTML.getNode(NODE,"mjx-stack"),
+            sup = CHTML.getNode(NODE,"mjx-sup"),
+            sub = CHTML.getNode(NODE,"mjx-sub");
         if (stack)      node.appendChild(stack);
           else if (sup) node.appendChild(sup);
           else if (sub) node.appendChild(sub);
diff --git a/unpacked/jax/output/CommonHTML/jax.js b/unpacked/jax/output/CommonHTML/jax.js
index 991be9d85..b51900f06 100644
--- a/unpacked/jax/output/CommonHTML/jax.js
+++ b/unpacked/jax/output/CommonHTML/jax.js
@@ -324,8 +324,9 @@
       if (type.substr(0,4) === "mjx-") {
         if (!def) def = {};
         if (def.className) def.className = type+" "+def.className; else def.className = type;
+        type = "span";
       }
-      return this.HTMLElement("span",def,content);
+      return this.HTMLElement(type,def,content);
     },
     addElement: function (node,type,def,content) {
       return node.appendChild(this.Element(type,def,content));
@@ -334,6 +335,22 @@
     ucMatch: HTML.ucMatch,
     setScript: HTML.setScript,
     
+    //
+    //  This replaces node.getElementsByTagName(type)[0]
+    //  and should be replaced by that if we go back to using
+    //  custom tags
+    //
+    getNode: (document.getElementsByClassName ? 
+      function (node,type) {return node.getElementsByClassName(type)[0]} :
+      function (node,type) {
+        var nodes = node.getElementsByTagName("span");
+        var name = RegExp("\\b"+type+"\\b");
+        for (var i = 0, m = nodes.length; i < m; i++) {
+          if (name.test(nodes[i].className)) return nodes[i];
+        }
+      }
+    ),
+    
 
     /********************************************/
     
@@ -360,7 +377,7 @@
         //  Remove any existing output
         //
         prev = script.previousSibling;
-	if (prev && prev.nodeName.toLowerCase() === "mjx-chtml")
+	if (prev && prev.className && String(prev.className).substr(0,9) === "mjx-chtml")
 	  prev.parentNode.removeChild(prev);
         //
         //  Add the node for the math and mark it as being processed
@@ -371,7 +388,9 @@
           id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id,
           oncontextmenu:EVENT.Menu, onmousedown: EVENT.Mousedown,
           onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout, onmousemove:EVENT.Mousemove,
-          onclick:EVENT.Click, ondblclick:EVENT.DblClick
+	  onclick:EVENT.Click, ondblclick:EVENT.DblClick,
+          // Added for keyboard accessible menu.
+          onkeydown: EVENT.Keydown, tabIndex: "0"  
         });
         if (jax.CHTML.display) {
           //
@@ -1325,7 +1344,7 @@
         if (child) {
           var type = options.childNodes;
           if (type) {
-            if (type instanceof Array) type = type[i];
+            if (type instanceof Array) type = type[i]||"span";
             node = CHTML.addElement(node,type);
           }
           cnode = child.toCommonHTML(node,options.childOptions);
@@ -1664,6 +1683,9 @@
     MML.math.Augment({
       toCommonHTML: function (node) {
         node = this.CHTMLdefaultNode(node);
+        var alttext = this.Get("alttext");
+        if (alttext && !node.getAttribute("aria-label")) node.setAttribute("aria-label",alttext);
+        if (!node.getAttribute("role")) node.setAttribute("role","math");
         if (this.CHTML.pwidth) {
           node.parentNode.style.width = this.CHTML.pwidth;
           node.parentNode.style.minWidth = this.CHTML.mwidth;
@@ -2029,9 +2051,9 @@
         //
         var base, under, over, nodes = [];
         if (stretch) {
-          base = node.getElementsByTagName("mjx-op")[0];
-          under = node.getElementsByTagName("mjx-under")[0];
-          over = node.getElementsByTagName("mjx-over")[0];
+          base = CHTML.getNode(node,"mjx-op");
+          under = CHTML.getNode(node,"mjx-under");
+          over = CHTML.getNode(node,"mjx-over");
           nodes[0] = base; nodes[1] = under||over; nodes[2] = over;
         } else {
           var types = ["mjx-op","mjx-under","mjx-over"];
@@ -2229,9 +2251,9 @@
         //
         var base, sub, sup;
         if (stretch) {
-          base = node.getElementsByTagName("mjx-base")[0];
-          sub = node.getElementsByTagName("mjx-sub")[0];
-          sup = node.getElementsByTagName("mjx-sup")[0];
+          base = CHTML.getNode(node,"mjx-base");
+          sub = CHTML.getNode(node,"mjx-sub");
+          sup = CHTML.getNode(node,"mjx-sup");
         } else {
           var types = ["mjx-base","mjx-sub","mjx-sup"];
           if (this.sup === 1) types[1] = types[2];
diff --git a/unpacked/jax/output/HTML-CSS/jax.js b/unpacked/jax/output/HTML-CSS/jax.js
index b673d2c6e..5dec3a2d0 100644
--- a/unpacked/jax/output/HTML-CSS/jax.js
+++ b/unpacked/jax/output/HTML-CSS/jax.js
@@ -344,7 +344,23 @@
         "#MathJax_Tooltip *": {
           filter: "none", opacity:1, background:"transparent" // for IE
         },
-        
+
+        // Focus elements for keyboard tabbing.
+        ".MathJax:focus": (
+          (MathJax.Hub.Browser.isSafari || MathJax.Hub.Browser.isChrome) ? {
+            display:"inline-block",
+            outline:"none",
+            margin:"-3px",
+            padding:"3px",
+            "-webkit-box-shadow": "0px 0px 5px #345, inset 0px 0px 5px #345",
+            "box-shadow": "0px 0px 5px #345, inset 0px 0px 5px #345"
+          } : {
+            display:"inline-block",
+            outline:"none",
+            border:"1px dotted",
+            margin:"-1px"
+          }),
+
         //
         //  Used for testing web fonts against the default font used while
         //  web fonts are loading
@@ -569,8 +585,11 @@
         span = div = this.Element("span",{
 	  className:"MathJax", id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id,
           oncontextmenu:EVENT.Menu, onmousedown: EVENT.Mousedown,
-          onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout, onmousemove:EVENT.Mousemove,
-	  onclick:EVENT.Click, ondblclick:EVENT.DblClick
+          onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout,
+          onmousemove:EVENT.Mousemove, onclick:EVENT.Click,
+          ondblclick:EVENT.DblClick,
+          // Added for keyboard accessible menu.
+          onkeydown: EVENT.Keydown, tabIndex: "0"
         });
 	if (HUB.Browser.noContextMenu) {
 	  span.ontouchstart = TOUCH.start;
@@ -2868,7 +2887,6 @@
           var alttext = this.Get("alttext");
           if (alttext && !span.getAttribute("aria-label")) span.setAttribute("aria-label",alttext);
           if (!span.getAttribute("role")) span.setAttribute("role","math");
-//        span.setAttribute("tabindex",0);  // causes focus outline, so disable for now
 	  stack = HTMLCSS.createStack(span); box = HTMLCSS.createBox(stack);
           // Move font-size from outer span to stack to avoid line separation 
           // problem in strict HTML mode
diff --git a/unpacked/jax/output/NativeMML/jax.js b/unpacked/jax/output/NativeMML/jax.js
index 3c6f7c289..3d444f745 100644
--- a/unpacked/jax/output/NativeMML/jax.js
+++ b/unpacked/jax/output/NativeMML/jax.js
@@ -326,6 +326,9 @@
         container.onmousedown   = EVENT.Mousedown;
         container.onclick       = EVENT.Click;
         container.ondblclick    = EVENT.DblClick;
+        // Added for keyboard accessible menu.
+        container.onkeydown = EVENT.Keydown;
+        container.tabIndex = "0";
 	if (HUB.Browser.noContextMenu) {
 	  container.ontouchstart = TOUCH.start;
 	  container.ontouchend   = TOUCH.end;
diff --git a/unpacked/jax/output/PreviewHTML/jax.js b/unpacked/jax/output/PreviewHTML/jax.js
index c8ce3d77a..7532af253 100644
--- a/unpacked/jax/output/PreviewHTML/jax.js
+++ b/unpacked/jax/output/PreviewHTML/jax.js
@@ -197,7 +197,9 @@
 	  className:"MathJax_PHTML", id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id,
           oncontextmenu:EVENT.Menu, onmousedown: EVENT.Mousedown,
           onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout, onmousemove:EVENT.Mousemove,
-	  onclick:EVENT.Click, ondblclick:EVENT.DblClick
+	  onclick:EVENT.Click, ondblclick:EVENT.DblClick,
+          // Added for keyboard accessible menu.
+          onkeydown: EVENT.Keydown, tabIndex: "0"  
         });
 	if (HUB.Browser.noContextMenu) {
 	  span.ontouchstart = TOUCH.start;
diff --git a/unpacked/jax/output/SVG/jax.js b/unpacked/jax/output/SVG/jax.js
index 64783ed09..c273f3a9d 100644
--- a/unpacked/jax/output/SVG/jax.js
+++ b/unpacked/jax/output/SVG/jax.js
@@ -220,7 +220,9 @@
  	  className:"MathJax_SVG", id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id,
           oncontextmenu:EVENT.Menu, onmousedown: EVENT.Mousedown,
           onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout, onmousemove:EVENT.Mousemove,
-	  onclick:EVENT.Click, ondblclick:EVENT.DblClick
+	  onclick:EVENT.Click, ondblclick:EVENT.DblClick,
+          // Added for keyboard accessible menu.
+          onkeydown: EVENT.Keydown, tabIndex: "0"
         });
 	if (HUB.Browser.noContextMenu) {
 	  span.ontouchstart = TOUCH.start;
@@ -2098,9 +2100,8 @@
           //  Add it to the MathJax span
           //
           var alttext = this.Get("alttext");
-          if (alttext && !svg.element.getAttribute("aria-label")) span.setAttribute("aria-label",alttext);
-          if (!svg.element.getAttribute("role")) span.setAttribute("role","math");
-//        span.setAttribute("tabindex",0);  // causes focus outline, so disable for now
+          if (alttext && !svg.element.getAttribute("aria-label")) svg.element.setAttribute("aria-label",alttext);
+          if (!svg.element.getAttribute("role")) svg.element.setAttribute("role","img");
           span.appendChild(svg.element);
           svg.element = null;
           //