diff --git a/README.md b/README.md
index 61499d39..f3a200a8 100644
--- a/README.md
+++ b/README.md
@@ -267,21 +267,28 @@ Triaging issues
 Issues will be triaged by the core team using the following primary set of tags:
 
 priority:
-    P1: top priority; typically blocks releases.
-    P2: one below that
-    P3: non-urgent
-    P4/P5: bluesky some day, who knows.
+
+* P1: top priority; typically blocks releases
+* P2: still need to fix, but lower than P1
+* P3: non-urgent
+* P4: intereseting idea - bluesky some day
+* P5: recorded for posterity/to avoid duplicates. No intention to resolves right now.
 
 bug or feature:
-  bug severity:
-     * cosmetic - feature works functionally but UI/UX is broken.
-     * critical - whole app doesn't work
-     * major - entire feature doesn't work
-     * minor - partially broken feature (but still usable)
 
-     * release blocker
+* bug
+* feature
 
-     * ui/ux (think of this as cosmetic)
+bug severity:
+  
+* cosmetic - feature works functionally but UI/UX is broken
+* critical - whole app doesn't work
+* major - entire feature doesn't work
+* minor - partially broken feature (but still usable)
 
-     * network (specific to network conditions)
-     * platform (platform specific)
+additional categories:
+
+* release blocker
+* ui/ux (think of this as cosmetic)
+* network (specific to network conditions)
+* platform (platform specific)
diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js
index 5fb0324c..e723cf1a 100644
--- a/src/components/structures/RoomDirectory.js
+++ b/src/components/structures/RoomDirectory.js
@@ -162,7 +162,7 @@ module.exports = React.createClass({
             var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
             Modal.createDialog(ErrorDialog, {
                 title: "Failed to get public room list",
-                description: err.message
+                description: "The server may be unavailable or overloaded",
             });
         });
     },
@@ -208,9 +208,10 @@ module.exports = React.createClass({
                 }, function(err) {
                     modal.close();
                     this.refreshRoomList();
+                    console.error("Failed to " + step + ": " + err);
                     Modal.createDialog(ErrorDialog, {
-                        title: "Failed to "+step,
-                        description: err.toString()
+                        title: "Error",
+                        description: "Failed to " + step,
                     });
                 });
             }
diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js
index 0469f52a..67c47263 100644
--- a/src/components/structures/RoomSubList.js
+++ b/src/components/structures/RoomSubList.js
@@ -505,9 +505,10 @@ var RoomSubList = React.createClass({
                         // Do any final stuff here
                     }).fail(function(err) {
                         var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+                        console.error("Failed to add tag " + self.props.tagName + " to room" + err);
                         Modal.createDialog(ErrorDialog, {
-                            title: "Failed to add tag " + self.props.tagName + " to room",
-                            description: err.toString()
+                            title: "Error", 
+                            description: "Failed to add tag " + self.props.tagName + " to room",
                         });
                     });
                     break;
diff --git a/src/components/views/rooms/DNDRoomTile.js b/src/components/views/rooms/DNDRoomTile.js
index 233fb8bb..6296552d 100644
--- a/src/components/views/rooms/DNDRoomTile.js
+++ b/src/components/views/rooms/DNDRoomTile.js
@@ -84,9 +84,10 @@ var roomTileSource = {
                     //component.state.set({ spinner: component.state.spinner-- });
                 }).fail(function(err) {
                     var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+                    console.error("Failed to remove tag " + item.originalList.props.tagName + " from room: " + err);
                     Modal.createDialog(ErrorDialog, {
-                        title: "Failed to remove tag " + item.originalList.props.tagName + " from room",
-                        description: err.toString()
+                        title: "Error",
+                        description: "Failed to remove tag " + item.originalList.props.tagName + " from room",
                     });
                 });
             }
@@ -103,9 +104,10 @@ var roomTileSource = {
                     //component.state.set({ spinner: component.state.spinner-- });
                 }).fail(function(err) {
                     var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+                    console.error("Failed to add tag " + item.targetList.props.tagName + " to room: " + err);
                     Modal.createDialog(ErrorDialog, {
-                        title: "Failed to add tag " + item.targetList.props.tagName + " to room",
-                        description: err.toString()
+                        title: "Error",
+                        description: "Failed to add tag " + item.targetList.props.tagName + " to room",
                     });
                 });
             }
diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js
index 506b34df..b5fc2f3d 100644
--- a/src/components/views/settings/Notifications.js
+++ b/src/components/views/settings/Notifications.js
@@ -238,9 +238,10 @@ module.exports = React.createClass({
                 self._refreshFromServer();
             }, function(error) {
                 var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+                console.error("Failed to change settings: " + error);
                 Modal.createDialog(ErrorDialog, {
-                    title: "Can't change settings",
-                    description: error.toString(),
+                    title: "Error",
+                    description: "Failed to change settings",
                     onFinished: self._refreshFromServer
                 });
             });
@@ -307,9 +308,10 @@ module.exports = React.createClass({
             self._refreshFromServer();
         }, function(error) {
             var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+            console.error("Can't update user notification settings: " + error);
             Modal.createDialog(ErrorDialog, {
-                title: "Can't update user notification settings",
-                description: error.toString(),
+                title: "Error",
+                description: "Can't update user notification settings",
                 onFinished: self._refreshFromServer
             });
         });
@@ -348,9 +350,10 @@ module.exports = React.createClass({
 
         var onError = function(error) {
             var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+            console.error("Failed to update keywords: " + error);
             Modal.createDialog(ErrorDialog, {
-                title: "Can't update keywords",
-                description: error.toString(),
+                title: "Error",
+                description: "Failed to update keywords",
                 onFinished: self._refreshFromServer
             });
         }
diff --git a/src/skins/vector/css/_common.scss b/src/skins/vector/css/_common.scss
index 25c94238..a44a503e 100644
--- a/src/skins/vector/css/_common.scss
+++ b/src/skins/vector/css/_common.scss
@@ -187,12 +187,16 @@ textarea {
 }
 
 .mx_Dialog_cancelButton {
-    float: right;
-    margin-top: 5px;
-    margin-right: 5px;
+    position: absolute;
+    right: 11px;
+    top: 13px;
     cursor: pointer;
 }
 
+.mx_Dialog_cancelButton object {
+    pointer-events: none;
+}
+
 .mx_Dialog_content {
     margin: 24px 58px 68px 0;
     font-size: 14px;
diff --git a/src/skins/vector/css/_components.scss b/src/skins/vector/css/_components.scss
index 650cf3d5..2c81103f 100644
--- a/src/skins/vector/css/_components.scss
+++ b/src/skins/vector/css/_components.scss
@@ -13,6 +13,7 @@
 @import "./matrix-react-sdk/structures/login/_Login.scss";
 @import "./matrix-react-sdk/views/avatars/_BaseAvatar.scss";
 @import "./matrix-react-sdk/views/dialogs/_BugReportDialog.scss";
+@import "./matrix-react-sdk/views/dialogs/_ChatCreateOrReuseChatDialog.scss";
 @import "./matrix-react-sdk/views/dialogs/_ChatInviteDialog.scss";
 @import "./matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss";
 @import "./matrix-react-sdk/views/dialogs/_EncryptedEventDialog.scss";
diff --git a/src/skins/vector/css/matrix-react-sdk/structures/_MatrixChat.scss b/src/skins/vector/css/matrix-react-sdk/structures/_MatrixChat.scss
index 05a39ea7..10528b36 100644
--- a/src/skins/vector/css/matrix-react-sdk/structures/_MatrixChat.scss
+++ b/src/skins/vector/css/matrix-react-sdk/structures/_MatrixChat.scss
@@ -90,16 +90,13 @@ limitations under the License.
        */
     overflow-x: auto;
 
-    /* XXX: Hack: apparently if you try to nest a flex-box
-     * within a non-flex-box within a flex-box, the height
-     * of the innermost element gets miscalculated if the
-     * parents are both auto.  Height has to be auto here
-     * for RoomView to correctly fit when the Toolbar is shown.
-     * Ideally we'd launch straight into the RoomView at this
-     * point, but instead we fudge it and make the middlePanel
-     * flex itself.
-     */
     display: flex;
+
+    /* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari
+       needed height 100% all the way down to the HomePage. Height does not
+       have to be auto, empirically.
+    */
+    height: 100%;
 }
 
 .mx_MatrixChat .mx_RightPanel {
diff --git a/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ChatCreateOrReuseChatDialog.scss b/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ChatCreateOrReuseChatDialog.scss
new file mode 100644
index 00000000..926e7411
--- /dev/null
+++ b/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ChatCreateOrReuseChatDialog.scss
@@ -0,0 +1,27 @@
+/*
+Copyright 2016 OpenMarket Ltd
+
+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.
+*/
+
+.mx_ChatCreateOrReuseDialog .mx_ChatCreateOrReuseDialog_tiles {
+    margin-top: 24px;
+}
+
+.mx_ChatCreateOrReuseDialog .mx_Dialog_content {
+    margin-bottom: 24px;
+}
+
+.mx_ChatCreateOrReuseDialog .mx_RoomTile_badge {
+    display: none;
+}
diff --git a/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss b/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss
index 58ea56ee..abd4e9c1 100644
--- a/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss
+++ b/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss
@@ -14,22 +14,39 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
+.mx_ConfirmUserActionDialog .mx_Dialog_content {
+    min-height: 48px;
+    margin-bottom: 24px;
+}
+
 .mx_ConfirmUserActionDialog_avatar {
     float: left;
     margin-right: 20px;
+    margin-top: -2px;
 }
 
 .mx_ConfirmUserActionDialog_name {
-    font-size: 150%;
+    font-size: 18px;
 }
 
 .mx_ConfirmUserActionDialog_userId {
-    font-style: italic;
+    font-size: 13px;
 }
 
 .mx_ConfirmUserActionDialog_reasonField {
-    margin-bottom: 40px;
+    font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
+    font-size: 14px;
+    color: $primary-fg-color;
+
+    border-radius: 3px;
+    border: solid 1px $input-border-color;
+    line-height: 36px;
+    padding-left: 16px;
+    padding-right: 16px;
+    padding-top: 1px;
+    padding-bottom: 1px;
+
+    margin-bottom: 24px;
+
     width: 90%;
-    font-size: 120%;
-    height: 35px;
 }
diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/_EventTile.scss b/src/skins/vector/css/matrix-react-sdk/views/rooms/_EventTile.scss
index 52c88cab..f241d2c5 100644
--- a/src/skins/vector/css/matrix-react-sdk/views/rooms/_EventTile.scss
+++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/_EventTile.scss
@@ -130,6 +130,16 @@ limitations under the License.
     color: $event-notsent-color;
 }
 
+.mx_EventTile_redacted {
+    padding-top: 0px;
+}
+
+.mx_EventTile_redacted .mx_EventTile_line,
+.mx_EventTile_redacted:hover .mx_EventTile_line,
+.mx_EventTile_redacted.menu .mx_EventTile_line {
+    background-color: $primary-fg-color;
+}
+
 .mx_EventTile_highlight,
 .mx_EventTile_highlight .markdown-body
  {
diff --git a/src/skins/vector/css/vector-web/structures/_HomePage.scss b/src/skins/vector/css/vector-web/structures/_HomePage.scss
index 11040c4b..e2af399d 100644
--- a/src/skins/vector/css/vector-web/structures/_HomePage.scss
+++ b/src/skins/vector/css/vector-web/structures/_HomePage.scss
@@ -18,6 +18,8 @@ limitations under the License.
 .mx_HomePage {
     max-width: 960px;
     width: 100%;
+    height: 100%;
+    overflow-y: hidden;
     margin-left: auto;
     margin-right: auto;
 }
diff --git a/src/vector/index.js b/src/vector/index.js
index 8b0da6fa..3b117106 100644
--- a/src/vector/index.js
+++ b/src/vector/index.js
@@ -102,15 +102,24 @@ var validBrowser = checkBrowserFeatures([
     "objectfit"
 ]);
 
+// Parse the given window.location and return parameters that can be used when calling
+// MatrixChat.showScreen(screen, params)
+function getScreenFromLocation(location) {
+    const fragparts = parseQsFromFragment(location);
+    return {
+        screen: fragparts.location.substring(1),
+        params: fragparts.params,
+    }
+}
+
 // Here, we do some crude URL analysis to allow
 // deep-linking.
 function routeUrl(location) {
     if (!window.matrixChat) return;
 
-    console.log("Routing URL "+location);
-    var fragparts = parseQsFromFragment(location);
-    window.matrixChat.showScreen(fragparts.location.substring(1),
-                                 fragparts.params);
+    console.log("Routing URL ", location.href);
+    const s = getScreenFromLocation(location);
+    window.matrixChat.showScreen(s.screen, s.params);
 }
 
 function onHashChange(ev) {
@@ -121,22 +130,13 @@ function onHashChange(ev) {
     routeUrl(window.location);
 }
 
-var loaded = false;
-var lastLoadedScreen = null;
-
 // This will be called whenever the SDK changes screens,
 // so a web page can update the URL bar appropriately.
 var onNewScreen = function(screen) {
     console.log("newscreen "+screen);
-    // just remember the most recent screen while we are loading, so that the
-    // user doesn't see the URL bar doing a dance
-    if (!loaded) {
-        lastLoadedScreen = screen;
-    } else {
-        var hash = '#/' + screen;
-        lastLocationHashSet = hash;
-        window.location.hash = hash;
-    }
+    var hash = '#/' + screen;
+    lastLocationHashSet = hash;
+    window.location.hash = hash;
 }
 
 // We use this to work out what URL the SDK should
@@ -268,8 +268,7 @@ async function loadApp() {
     } else if (validBrowser) {
         UpdateChecker.start();
 
-        var MatrixChat = sdk.getComponent('structures.MatrixChat');
-
+        const MatrixChat = sdk.getComponent('structures.MatrixChat');
         window.matrixChat = ReactDOM.render(
             <MatrixChat
                 onNewScreen={onNewScreen}
@@ -280,19 +279,11 @@ async function loadApp() {
                 startingFragmentQueryParams={fragparts.params}
                 enableGuest={true}
                 onLoadCompleted={onLoadCompleted}
+                initialScreenAfterLogin={getScreenFromLocation(window.location)}
                 defaultDeviceDisplayName={PlatformPeg.get().getDefaultDeviceDisplayName()}
             />,
             document.getElementById('matrixchat')
         );
-
-        routeUrl(window.location);
-
-        // we didn't propagate screen changes to the URL bar while we were loading; do it now.
-        loaded = true;
-        if (lastLoadedScreen) {
-            onNewScreen(lastLoadedScreen);
-            lastLoadedScreen = null;
-        }
     }
     else {
         console.error("Browser is missing required features.");