diff --git a/lib/browserid/prove_template.ejs b/lib/browserid/prove_template.ejs
index d9bd314860831e56c4bb86b28586153cb20320d8..d20e219da9555171ef51302105a93acec5549179 100644
--- a/lib/browserid/prove_template.ejs
+++ b/lib/browserid/prove_template.ejs
@@ -6,5 +6,5 @@
 <%= gettext('If you are NOT trying to sign into this site, just ignore this email.') %>
 
 <%= gettext('Thanks,') %>
-<%= gettext('BrowserID') %>
+<%= gettext('Persona') %>
 <%= gettext('(A better way to sign in)') %>
diff --git a/package.json b/package.json
index fac169eda190ea9b0407b0c6cf92218152a219d4..7801ed885964e53f924355ddae3bb3d909007649 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,7 @@
     },
     "devDependencies": {
         "vows": "0.5.13",
-        "awsbox": "0.2.11",
+        "awsbox": "0.2.12",
         "irc": "0.3.3"
     },
     "scripts": {
diff --git a/resources/static/communication_iframe/start.js b/resources/static/communication_iframe/start.js
index 57ce36dcaca52ba1d78fc3db41208e89371444ec..fa26648aef2caed72eeb18c9a81b2259cee266c5 100644
--- a/resources/static/communication_iframe/start.js
+++ b/resources/static/communication_iframe/start.js
@@ -9,6 +9,11 @@
       user = bid.User,
       storage = bid.Storage;
 
+  // Initialize all localstorage values to default values.  Neccesary for
+  // proper sync of IE8 localStorage across multiple simultaneous
+  // browser sessions.
+  storage.setDefaultValues();
+
   network.init();
 
   var chan = Channel.build({
diff --git a/resources/static/css/style.css b/resources/static/css/style.css
index 35bfa524ab66efd353488ddd596061022bb3fc77..94aac066d5eea89dbaef6c4d9df944a96b34ffaa 100644
--- a/resources/static/css/style.css
+++ b/resources/static/css/style.css
@@ -515,30 +515,10 @@ button.delete:active {
   padding: 0;
 }
 
-#signUpForm .red {
-  color: red;
-}
-
 #signUpForm .submit {
   height: 28px;
 }
 
-#signUpForm .error {
-  margin-top: 20px;
-  color: red;
-  background-color: rgba(255,0,0,0.25);
-  -ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3fff0000,endColorstr=#3fff0000);
-  filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3fff0000,endColorstr=#3fff0000);
-  zoom: 1;
-  padding: 5px;
-  line-height: 16px;
-
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-       -o-border-radius: 3px;
-          border-radius: 3px;
-}
-
 #signUpForm > .siteinfo {
   margin-bottom: 10px;
 }
diff --git a/resources/static/dialog/controllers/dialog.js b/resources/static/dialog/controllers/dialog.js
index 34f9f2f135c30e7d76370e85e555b072274ba230..7e40c8c531c50ae78e90a79a06045908ef0a2b49 100644
--- a/resources/static/dialog/controllers/dialog.js
+++ b/resources/static/dialog/controllers/dialog.js
@@ -174,6 +174,11 @@ BrowserID.Modules.Dialog = (function() {
           // that come from other domains, only allow absolute paths from the
           // origin.
           params.siteLogo = fixupAbsolutePath(origin_url, paramsFromRP.siteLogo);
+          // To avoid mixed content errors, only allow siteLogos to be served
+          // from https RPs
+          if (URLParse(origin_url).scheme !== "https") {
+            throw "only https sites can specify a siteLogo";
+          }
         }
 
         if (paramsFromRP.siteName) {
diff --git a/resources/static/dialog/views/error.ejs b/resources/static/dialog/views/error.ejs
index 0b35cd680dc17fcb47e25adc6284ae7cce111b46..2a0ee0066700746b6c73e31818f4353ee1156976 100644
--- a/resources/static/dialog/views/error.ejs
+++ b/resources/static/dialog/views/error.ejs
@@ -14,6 +14,10 @@
       <%= gettext("Persona requires cookies") %>
     </h2>
     <%= format(gettext("Please close this window, <a %s>enable cookies</a> and try again"), [" target='_blank' href='http://support.mozilla.org/en-US/kb/Websites%20say%20cookies%20are%20blocked'"]) %>
+  <% } else if(typeof title === "string") { %>
+    <h2>
+      <span class="emphasis"><%= title %></span>
+    </h2>
   <% } else { %>
     <h2 id="defaultError">
       <%= gettext("We are very sorry.") %><span class="emphasis"> <%= gettext("There has been an error!") %></span>
diff --git a/resources/static/i/badge.png b/resources/static/i/badge.png
index 1af14efe525f3e2291cd88d37d195b147801d504..2b082db5dd486134b6c1fa86f5e609dff6c0f8c0 100644
Binary files a/resources/static/i/badge.png and b/resources/static/i/badge.png differ
diff --git a/resources/static/i/button-arrow.png b/resources/static/i/button-arrow.png
index 2ec7e2609a4bf633b1fdfc1fb0d5bc65c2db56cb..b5d7a1d87635c7e9719b52970604ad060a599fbb 100644
Binary files a/resources/static/i/button-arrow.png and b/resources/static/i/button-arrow.png differ
diff --git a/resources/static/i/count.png b/resources/static/i/count.png
index 2f031bd84fd4528f74782eb417fef154e3c7f811..b6bccc3dc40388432b3ede95ce1204d50a5f78a1 100644
Binary files a/resources/static/i/count.png and b/resources/static/i/count.png differ
diff --git a/resources/static/i/firefox_logo.png b/resources/static/i/firefox_logo.png
index c55a338081cc1e0f1d2e78fc50226695c0b37488..c4dad373e1f95655102af8fa3a617324539e8402 100644
Binary files a/resources/static/i/firefox_logo.png and b/resources/static/i/firefox_logo.png differ
diff --git a/resources/static/i/grain.png b/resources/static/i/grain.png
index 2980ee90e52f15cd22eabebf59344fca831e7410..796f5fbeb24967faaf3046b51de12b0f9048e32b 100644
Binary files a/resources/static/i/grain.png and b/resources/static/i/grain.png differ
diff --git a/resources/static/i/marketplace-header.png b/resources/static/i/marketplace-header.png
index 03286253845256e4166036d2d933cdd2fcc1b3b1..5dbb70f6c1a8700932eda4f58899cf3cbfd5aea8 100644
Binary files a/resources/static/i/marketplace-header.png and b/resources/static/i/marketplace-header.png differ
diff --git a/resources/static/i/persona-logo-transparent.png b/resources/static/i/persona-logo-transparent.png
index 5484f73c13f1f0a8295a6bacf0792c57e2b4f567..c249e97fa2daf6de091f0d78a702872c0a7bafd5 100644
Binary files a/resources/static/i/persona-logo-transparent.png and b/resources/static/i/persona-logo-transparent.png differ
diff --git a/resources/static/i/persona-logo-wordmark.png b/resources/static/i/persona-logo-wordmark.png
index f64670ec0b53e2f8ed6f136eb0b288e955b9054a..38e0804a30ada75db73f7832b266914f4aa3bb45 100644
Binary files a/resources/static/i/persona-logo-wordmark.png and b/resources/static/i/persona-logo-wordmark.png differ
diff --git a/resources/static/i/tutorial_1.png b/resources/static/i/tutorial_1.png
index a19fac78c3d591d55d96c08ed2df2a477e650483..eebf4b458198996f902493f577d120e03be877fe 100644
Binary files a/resources/static/i/tutorial_1.png and b/resources/static/i/tutorial_1.png differ
diff --git a/resources/static/i/tutorial_2.png b/resources/static/i/tutorial_2.png
index 27b66d43a19114e1085cff3e8a71b2d2aa5199f9..11a7bf247fd96bb90e157bd2184a1e7e7174131d 100644
Binary files a/resources/static/i/tutorial_2.png and b/resources/static/i/tutorial_2.png differ
diff --git a/resources/static/i/tutorial_3.png b/resources/static/i/tutorial_3.png
index f3d0f6d19cdedfc10f2836bfaed47e3a33d5b500..3c6c11efd3f56aeed6bc74b303d9ab4715ea6971 100644
Binary files a/resources/static/i/tutorial_3.png and b/resources/static/i/tutorial_3.png differ
diff --git a/resources/static/pages/verify_secondary_address.js b/resources/static/pages/verify_secondary_address.js
index df4561ec37b6707e3401afafd4f7c07225ba283a..5b2f7f20051e8bd9c3ce71c181ac75c2cc6c4c69 100644
--- a/resources/static/pages/verify_secondary_address.js
+++ b/resources/static/pages/verify_secondary_address.js
@@ -19,7 +19,6 @@ BrowserID.verifySecondaryAddress = (function() {
       tooltip = bid.Tooltip,
       token,
       sc,
-      needsPassword,
       mustAuth,
       verifyFunction,
       doc = document,
@@ -29,11 +28,6 @@ BrowserID.verifySecondaryAddress = (function() {
       redirectTo,
       redirectTimeout;  // set in config if available, use REDIRECT_SECONDS otw.
 
-  function showError(el, oncomplete) {
-    dom.hide(".hint,#signUpForm");
-    $(el).fadeIn(ANIMATION_TIME, oncomplete);
-  }
-
   function showRegistrationInfo(info) {
     dom.setInner("#email", info.email);
 
@@ -55,38 +49,37 @@ BrowserID.verifySecondaryAddress = (function() {
 
   function submit(oncomplete) {
     var pass = dom.getInner("#password") || undefined,
-        vpass = dom.getInner("#vpassword") || undefined,
-        inputValid = (!needsPassword ||
-                    validation.passwordAndValidationPassword(pass, vpass))
-             && (!mustAuth ||
-                    validation.password(pass));
+        inputValid = !mustAuth || validation.password(pass);
 
     if (inputValid) {
       user[verifyFunction](token, pass, function(info) {
         dom.addClass("body", "complete");
 
-        var verified = info.valid,
-            selector = verified ? "#congrats" : "#cannotcomplete";
-
-        pageHelpers.replaceFormWithNotice(selector, function() {
-          if (redirectTo && verified) {
-
-            // set the loggedIn status for the site.  This allows us to get
-            // a silent assertion without relying on the dialog to set the
-            // loggedIn status for the domain.  This is useful when the user
-            // closes the dialog OR if redirection happens before the dialog
-            // has had a chance to finish its business.
-            storage.setLoggedIn(URLParse(redirectTo).originOnly(), email);
-
-            setTimeout(function() {
-              doc.location.href = redirectTo;
+        var verified = info.valid;
+
+        if (verified) {
+          pageHelpers.replaceFormWithNotice("#congrats", function() {
+            if (redirectTo) {
+              // set the loggedIn status for the site.  This allows us to get
+              // a silent assertion without relying on the dialog to set the
+              // loggedIn status for the domain.  This is useful when the user
+              // closes the dialog OR if redirection happens before the dialog
+              // has had a chance to finish its business.
+              storage.setLoggedIn(URLParse(redirectTo).originOnly(), email);
+
+              setTimeout(function() {
+                doc.location.href = redirectTo;
+                complete(oncomplete, verified);
+              }, redirectTimeout);
+            }
+            else {
               complete(oncomplete, verified);
-            }, redirectTimeout);
-          }
-          else {
-            complete(oncomplete, verified);
-          }
-        });
+            }
+          });
+        }
+        else {
+          pageHelpers.showFailure(errors.cannotComplete, info, oncomplete);
+        }
       }, function(info) {
         if (info.network && info.network.status === 401) {
           tooltip.showTooltip("#cannot_authenticate");
@@ -103,36 +96,30 @@ BrowserID.verifySecondaryAddress = (function() {
   }
 
   function startVerification(oncomplete) {
+    var self=this;
     user.tokenInfo(token, function(info) {
       if (info) {
         redirectTo = info.returnTo;
         email = info.email;
         showRegistrationInfo(info);
 
-        needsPassword = info.needs_password;
         mustAuth = info.must_auth;
-
-        if (needsPassword) {
-          // This is a fix for legacy users who started the user creation
-          // process without setting their password in the dialog.  If the user
-          // needs a password, they must set it now.  Once all legacy users are
-          // verified or their links invalidated, this flow can be removed.
-          dom.addClass("body", "enter_password");
-          dom.addClass("body", "enter_verify_password");
-          complete(oncomplete, true);
-        }
-        else if (mustAuth) {
-          // These are users who have set their passwords inside of the dialog.
+        if (mustAuth) {
+          // These are users who are authenticating in a different browser or
+          // session than the initiator.
           dom.addClass("body", "enter_password");
           complete(oncomplete, true);
         }
         else {
-          // These are users who do not have to set their passwords at all.
+          // Easy case where user is in same browser and same session, just
+          // verify and be done with it all!
           submit(oncomplete);
         }
       }
       else {
-        showError("#cannotconfirm");
+        // renderError is used directly instead of pageHelpers.showFailure
+        // because showFailure hides the title in the extended info.
+        self.renderError("error", errors.cannotConfirm);
         complete(oncomplete, false);
       }
     }, pageHelpers.getFailure(errors.getTokenInfo, oncomplete));
@@ -140,7 +127,8 @@ BrowserID.verifySecondaryAddress = (function() {
 
   var Module = bid.Modules.PageModule.extend({
     start: function(options) {
-      this.checkRequired(options, "token", "verifyFunction");
+      var self=this;
+      self.checkRequired(options, "token", "verifyFunction");
 
       token = options.token;
       verifyFunction = options.verifyFunction;
@@ -151,9 +139,9 @@ BrowserID.verifySecondaryAddress = (function() {
         redirectTimeout = REDIRECT_SECONDS * 1000;
       }
 
-      startVerification(options.ready);
+      startVerification.call(self, options.ready);
 
-      sc.start.call(this, options);
+      sc.start.call(self, options);
     },
 
     submit: submit
diff --git a/resources/static/shared/error-messages.js b/resources/static/shared/error-messages.js
index 2ce74cfde884cc3adb5a4103cd12e30794f5be89..5b3530452890c3d112c358fdc92164a68bda9e85 100644
--- a/resources/static/shared/error-messages.js
+++ b/resources/static/shared/error-messages.js
@@ -35,6 +35,14 @@ BrowserID.Errors = (function(){
       title: "Cancelling User Account"
     },
 
+    cannotConfirm: {
+      title: gettext("There was a problem with your signup link. Has this address already been registered?")
+    },
+
+    cannotComplete: {
+      title: gettext("Error encountered trying to complete registration.")
+    },
+
     checkAuthentication: {
       title: "Checking Authentication"
     },
diff --git a/resources/static/shared/storage.js b/resources/static/shared/storage.js
index 7b4e768ac2d2ab3d37e36365fed4b919fd3c039b..4163e0e6bf73f420ca776d9ea5c8f6cb3b180479 100644
--- a/resources/static/shared/storage.js
+++ b/resources/static/shared/storage.js
@@ -49,11 +49,34 @@ BrowserID.Storage = (function() {
 
   function clear() {
     storage.removeItem("emails");
-    storage.removeItem("tempKeypair");
     storage.removeItem("siteInfo");
     storage.removeItem("managePage");
   }
 
+  // initialize all localStorage values to default if they are unset.
+  // this function is only neccesary on IE8 where there are localStorage
+  // synchronization issues between different browsing contexts, however
+  // it's intended to avoid IE8 specific bugs from being introduced.
+  // see issue #1637
+  function setDefaultValues() {
+    _.each({
+      emailToUserID: {},
+      emails: {},
+      interaction_data: {},
+      loggedIn: {},
+      main_site: {},
+      managePage: {},
+      returnTo: null,
+      siteInfo: {},
+      stagedOnBehalfOf: null,
+      usersComputer: {}
+    }, function(defaultVal, key) {
+      if (!storage[key]) {
+        storage[key] = JSON.stringify(defaultVal);
+      }
+    });
+  }
+
   function getEmails() {
     try {
       var emails = JSON.parse(storage.emails || "{}");
@@ -124,28 +147,6 @@ BrowserID.Storage = (function() {
     }
   }
 
-  function storeTemporaryKeypair(keypair) {
-    storage.tempKeypair = JSON.stringify({
-      publicKey: keypair.publicKey.toSimpleObject(),
-      secretKey: keypair.secretKey.toSimpleObject()
-    });
-  }
-
-  function retrieveTemporaryKeypair() {
-    var raw_kp = JSON.parse(storage.tempKeypair || "");
-    storage.tempKeypair = null;
-    if (raw_kp) {
-      prepareDeps();
-
-      var kp = {};
-      kp.publicKey = jwcrypto.loadPublicKeyFromObject(raw_kp.publicKey);
-      kp.secretKey = jwcrypto.loadSecretKeyFromObject(raw_kp.secretKey);
-      return kp;
-    } else {
-      return null;
-    }
-  }
-
   function setReturnTo(returnToURL) {
     storage.returnTo = JSON.stringify({
       at: new Date().toString(),
@@ -588,9 +589,14 @@ BrowserID.Storage = (function() {
      * @method clear
      */
     clear: clear,
-    storeTemporaryKeypair: storeTemporaryKeypair,
-    retrieveTemporaryKeypair: retrieveTemporaryKeypair,
     setReturnTo: setReturnTo,
-    getReturnTo: getReturnTo
+    getReturnTo: getReturnTo,
+    /**
+     * Set all used storage values to default if they are unset.  This function
+     * is required for proper localStorage sync between different browsing contexts,
+     * see issue #1637 for full details.
+     * @method setDefaultValues
+     */
+    setDefaultValues: setDefaultValues
   };
 }());
diff --git a/resources/static/test/cases/controllers/dialog.js b/resources/static/test/cases/controllers/dialog.js
index 3ab6c7d8707b073ac5fda5ef98c48707461e44bc..e7a75af818d6174a4737a623b8c99df74ca15066 100644
--- a/resources/static/test/cases/controllers/dialog.js
+++ b/resources/static/test/cases/controllers/dialog.js
@@ -560,7 +560,26 @@
     });
   });
 
-  asyncTest("get with absolute path - allowed URL but it must be properly escaped", function() {
+  asyncTest("get with absolute path and http RP - not allowed", function() {
+    createController({
+      ready: function() {
+        mediator.subscribe("start", function(msg, info) {
+          ok(false, "start should not have been called");
+        });
+
+        var siteLogo = '/i/card.png';
+        var retval = controller.get(HTTP_TEST_DOMAIN, {
+          siteLogo: siteLogo
+        });
+
+        equal(retval, "only https sites can specify a siteLogo", "expected error");
+        testErrorVisible();
+        start();
+      }
+    });
+  });
+
+  asyncTest("get with absolute path and https RP - allowed URL but is properly escaped", function() {
     createController({
       ready: function() {
         var startInfo;
@@ -569,12 +588,12 @@
         });
 
         var siteLogo = '/i/card.png" onerror="alert(\'xss\')" <script>alert(\'more xss\')</script>';
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
+        var retval = controller.get(HTTPS_TEST_DOMAIN, {
           siteLogo: siteLogo
         });
 
         testHelpers.testObjectValuesEqual(startInfo, {
-          siteLogo: encodeURI(HTTP_TEST_DOMAIN + siteLogo)
+          siteLogo: encodeURI(HTTPS_TEST_DOMAIN + siteLogo)
         });
         equal(typeof retval, "undefined", "no error expected");
         testErrorNotVisible();
diff --git a/resources/static/test/cases/pages/verify_secondary_address.js b/resources/static/test/cases/pages/verify_secondary_address.js
index 0d74afe90af7dc39c853bc3f8860a11adfbac517..ac4ddaa8b832c09fe5a03cd19c8a49a29fdcd37e 100644
--- a/resources/static/test/cases/pages/verify_secondary_address.js
+++ b/resources/static/test/cases/pages/verify_secondary_address.js
@@ -13,6 +13,7 @@
       dom = bid.DOM,
       testHelpers = bid.TestHelpers,
       testHasClass = testHelpers.testHasClass,
+      testVisible = testHelpers.testVisible,
       validToken = true,
       controller,
       config = {
@@ -56,7 +57,7 @@
   }
 
   function testCannotConfirm() {
-    ok($("#cannotconfirm").is(":visible"), "cannot confirm box is visible");
+    testHelpers.testErrorVisible();
   }
 
   test("start with missing token", function() {
@@ -70,22 +71,21 @@
     equal(error, "missing config option: token", "correct error thrown");
   });
 
-  asyncTest("no password: start with good token and site", function() {
+  asyncTest("valid token, no password necessary - verify user and show site info", function() {
     var returnTo = "https://test.domain/path";
     storage.setReturnTo(returnTo);
 
     createController(config, function() {
-      testEmail();
-      ok($(".siteinfo").is(":visible"), "siteinfo is visible when we say what it is");
-      equal($(".website:nth(0)").text(), returnTo, "website is updated");
+      testVisible("#congrats");
       testHasClass("body", "complete");
+      equal($(".website").text(), returnTo, "website is updated");
       equal(doc.location.href, returnTo, "redirection occurred to correct URL");
       equal(storage.getLoggedIn("https://test.domain"), "testuser@testuser.com", "logged in status set");
       start();
     });
   });
 
-  asyncTest("no password: start with good token and nosite", function() {
+  asyncTest("valid token, no password necessary, no saved site info - verify user but do not show site info", function() {
     createController(config, function() {
       testEmail();
       equal($(".siteinfo").is(":visible"), false, "siteinfo is not visible without having it");
@@ -94,7 +94,7 @@
     });
   });
 
-  asyncTest("no password: start with bad token", function() {
+  asyncTest("invalid token - show cannot confirm error", function() {
     xhr.useResult("invalid");
 
     createController(config, function() {
@@ -103,7 +103,7 @@
     });
   });
 
-  asyncTest("no password: start with emailForVerficationToken XHR failure", function() {
+  asyncTest("valid token with xhr error - show error screen", function() {
     xhr.useResult("ajaxError");
     createController(config, function() {
       testHelpers.testErrorVisible();
@@ -156,88 +156,4 @@
     });
   });
 
-  asyncTest("must set password, successful login", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      $("#password").val("password");
-      $("#vpassword").val("password");
-
-      testHasClass("body", "enter_password");
-      testHasClass("body", "enter_verify_password");
-
-      controller.submit(function(status) {
-        equal(status, true, "correct status");
-        testHasClass("body", "complete");
-        start();
-      });
-    });
-  });
-
-  asyncTest("must set password, too short a password", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      $("#password").val("pass");
-      $("#vpassword").val("pass");
-
-      controller.submit(function(status) {
-        equal(status, false, "correct status");
-        testHelpers.testTooltipVisible();
-        start();
-      });
-    });
-  });
-
-  asyncTest("must set password, too long a password", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      var pass = testHelpers.generateString(81);
-      $("#password").val(pass);
-      $("#vpassword").val(pass);
-
-      controller.submit(function(status) {
-        equal(status, false, "correct status");
-        testHelpers.testTooltipVisible();
-        start();
-      });
-    });
-  });
-
-  asyncTest("must set password, missing verification password", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      $("#password").val("password");
-      $("#vpassword").val("");
-
-      controller.submit(function(status) {
-        equal(status, false, "correct status");
-        testHelpers.testTooltipVisible();
-        start();
-      });
-    });
-  });
-
-  asyncTest("must set password, mismatched passwords", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      $("#password").val("password");
-      $("#vpassword").val("password1");
-
-      controller.submit(function(status) {
-        equal(status, false, "correct status");
-        testHelpers.testTooltipVisible();
-        start();
-      });
-    });
-  });
-
 }());
diff --git a/resources/static/test/cases/shared/storage.js b/resources/static/test/cases/shared/storage.js
index 5a7048c00799dfa54ebd351407cf45199264aec9..f7238bdedf1f9379b0a2f100e2e6b665b7ea69fb 100644
--- a/resources/static/test/cases/shared/storage.js
+++ b/resources/static/test/cases/shared/storage.js
@@ -155,15 +155,6 @@
     storage.clear();
     equal(typeof storage.manage_page.get("user_has_visited"), "undefined", "after reset, user_has_visited reset correctly");
   });
-
-  test("storeTemporaryKeypair", function() {
-    // XXX needs a test
-  });
-
-  test("retrieveTemporaryKeypair", function() {
-    // XXX needs a test
-  });
-
   test("setReturnTo", function() {
     storage.setReturnTo("http://some.domain/path");
     equal(storage.getReturnTo(), "http://some.domain/path", "setReturnTo/getReturnTo working as expected");
diff --git a/resources/static/test/testHelpers/helpers.js b/resources/static/test/testHelpers/helpers.js
index 25badaf79e045099ab636f585102088970a65a00..882d0049e0470879e1f031c1add47717f60d80cf 100644
--- a/resources/static/test/testHelpers/helpers.js
+++ b/resources/static/test/testHelpers/helpers.js
@@ -228,6 +228,10 @@ BrowserID.TestHelpers = (function() {
       notEqual(typeof toTest, "undefined", msg || "object is defined");
     },
 
+    testVisible: function(selector, msg) {
+      ok($(selector).is(":visible"), msg || selector + " should be visible");
+    },
+
     testHasClass: function(selector, className, msg) {
       ok($(selector).hasClass(className),
           msg || (selector + " has className " + className));
@@ -238,14 +242,14 @@ BrowserID.TestHelpers = (function() {
           msg || (selector + " does not have className " + className));
     },
 
-    testElementDoesNotExist: function(selector, msg) {
-      equal($(selector).length, 0, msg || ("element '" + selector + "' does not exist"));
-    },
-
     testElementExists: function(selector, msg) {
       ok($(selector).length, msg || ("element '" + selector + "' exists"));
     },
 
+    testElementDoesNotExist: function(selector, msg) {
+      equal($(selector).length, 0, msg || ("element '" + selector + "' does not exist"));
+    },
+
     testRPTosPPShown: function(msg) {
       TestHelpers.testHasClass("body", "rptospp", msg || "RP TOS/PP shown");
     },
diff --git a/resources/views/add_email_address.ejs b/resources/views/add_email_address.ejs
index 9a4128aeee67fac5702ae45de569cd952d41fe4a..f56a6caf70bff61116465caf50941f13d20b2bec 100644
--- a/resources/views/add_email_address.ejs
+++ b/resources/views/add_email_address.ejs
@@ -2,15 +2,12 @@
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
-<div id="hAlign" class="display_always">
+<div id="hAlign">
     <div id="vAlign">
-        <ul class="notifications">
-            <li class="notification error" id="cannotconfirm"><%= gettext('Error encountered while attempting to confirm your address. Have you previously verified this address?') %></li>
-            <li class="notification error" id="cannotcomplete"><%= gettext('Error encountered trying to complete registration.') %></li>
-        </ul>
-
-        <form id="signUpForm" class="cf">
-            <p class="hint siteinfo"><%= gettext('Finish signing into:') %> <strong><span class="website"></span></strong></p>
+        <form id="signUpForm" class="cf password_entry">
+            <p class="hint siteinfo">
+              <%= gettext('Finish signing into:') %> <strong class="website"></strong>
+            </p>
 
             <h1><%= gettext('Email Verification') %></h1>
 
@@ -19,7 +16,8 @@
                     <label for="email"><%= gettext('Email Address') %></label>
                     <input class="youraddress" id="email" placeholder="<%= gettext('Your Email') %>" type="email" value="" disabled="disabled" maxlength="254" />
                 </li>
-                <li class="password_entry">
+
+                <li>
                     <label for="password"><%= gettext('Password') %></label>
                     <input id="password" placeholder="<%= gettext('Your Password') %>" type="password" autofocus maxlength=80 />
 
@@ -27,35 +25,16 @@
                       <%= gettext('Password is required.') %>
                     </div>
 
-                    <div class="tooltip" id="password_length" for="password">
-                      <%= gettext('Password must be between 8 and 80 characters long.') %>
-                    </div>
-
                     <div id="cannot_authenticate" class="tooltip" for="password">
                       <%= gettext('The account cannot be verified with this username and password.') %>
                     </div>
                 </li>
-
-                <li class="password_entry" id="verify_password">
-                    <label for="vpassword"><%= gettext('Verify Password') %></label>
-                    <input id="vpassword" placeholder="<%= gettext('Repeat Password') %>" type="password" maxlength="80">
-
-                    <div id="vpassword_required" class="tooltip" for="vpassword">
-                      <%= gettext('Verification password is required.') %>
-                    </div>
-
-                    <div class="tooltip" id="passwords_no_match" for="vpassword">
-                      <%= gettext ('Passwords do not match.') %>
-                    </div>
-
-                </li>
             </ul>
 
             <div class="submit cf password_entry">
                 <button><%= gettext('finish') %></button>
             </div>
 
-
         </form>
 
         <div id="congrats">
diff --git a/resources/views/verify_email_address.ejs b/resources/views/verify_email_address.ejs
index d033b9417e2b39158d875138bb6ec24aca1a0286..118c70df793807bfb6586e04eb955624061bbe5a 100644
--- a/resources/views/verify_email_address.ejs
+++ b/resources/views/verify_email_address.ejs
@@ -2,15 +2,13 @@
       License, v. 2.0. If a copy of the MPL was not distributed with this
       file, You can obtain one at http://mozilla.org/MPL/2.0/. */ %>
 
-<div id="hAlign" class="display_always">
+<div id="hAlign">
     <div id="vAlign">
-        <ul class="notifications">
-            <li class="notification error" id="cannotconfirm"><%= gettext('There was a problem with your signup link. Has this address already been registered?') %></li>
-            <li class="notification error" id="cannotcomplete"><%= gettext('Error encountered trying to complete registration.') %></li>
-        </ul>
+        <form id="signUpForm" class="cf password_entry">
+            <p class="hint siteinfo">
+              <%= gettext('Finish signing into:') %> <strong class="website"></strong>
+            </p>
 
-        <form id="signUpForm" class="cf">
-            <p class="hint siteinfo"><%= gettext('Finish signing into:') %> <strong><span class="website"></span></strong></p>
             <h1><%= gettext('Last step!') %></h1>
 
             <ul class="inputs">
@@ -19,7 +17,7 @@
                     <input class="youraddress" id="email" placeholder="<%= gettext('Your Email') %>" type="email" value="" disabled="disabled" maxlength="254" />
                 </li>
 
-                <li class="password_entry">
+                <li>
                     <label for="password"><%= gettext('Password') %></label>
                     <input id="password" placeholder="<%= gettext('Your Password') %>" type="password" autofocus maxlength=80 />
 
@@ -27,28 +25,10 @@
                       <%= gettext('Password is required.') %>
                     </div>
 
-                    <div class="tooltip" id="password_length" for="password">
-                      <%= gettext('Password must be between 8 and 80 characters long.') %>
-                    </div>
-
                     <div id="cannot_authenticate" class="tooltip" for="password">
                       <%= gettext('The account cannot be verified with this username and password.') %>
                     </div>
                 </li>
-
-                <li class="password_entry" id="verify_password">
-                    <label for="vpassword"><%= gettext('Verify Password') %></label>
-                    <input id="vpassword" placeholder="<%= gettext('Repeat Password') %>" type="password" maxlength="80">
-
-                    <div id="vpassword_required" class="tooltip" for="vpassword">
-                      <%= gettext('Verification password is required.') %>
-                    </div>
-
-                    <div class="tooltip" id="passwords_no_match" for="vpassword">
-                      <%= gettext ('Passwords do not match.') %>
-                    </div>
-
-                </li>
             </ul>
 
             <div class="submit cf password_entry">