diff --git a/.gitignore b/.gitignore
index 060ca6e9..2ad05012 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,6 @@
 npm-debug.log
 electron/dist
 electron/pub
-/.idea
+**/.idea
 /config.json
 /src/component-index.js
diff --git a/README.md b/README.md
index d4b778b9..27138203 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ released version of Riot:
 1. Enter the URL into your browser and log into Riot!
 
 Releases are signed by PGP, and can be checked against the public key
-at https://riot.im/packages/keys/riot-master.asc
+at https://riot.im/packages/keys/riot.asc
 
 Note that Chrome does not allow microphone or webcam access for sites served
 over http (except localhost), so for working VoIP you will need to serve Riot
@@ -62,7 +62,7 @@ to build.
 1. If you're using the `develop` branch, install the develop versions of the
    dependencies, as the released ones will be too old:
    ```
-   scripts/fetch-develop-deps.sh
+   scripts/fetch-develop.deps.sh
    ```
    Whenever you git pull on riot-web you will also probably need to force an update
    to these dependencies - the simplest way is to re-run the script, but you can also
diff --git a/electron_app/src/electron-main.js b/electron_app/src/electron-main.js
index 99e14b74..ce5ac384 100644
--- a/electron_app/src/electron-main.js
+++ b/electron_app/src/electron-main.js
@@ -228,6 +228,17 @@ electron.app.on('ready', () => {
         }
     });
 
+    if (process.platform === 'win32') {
+        // Handle forward/backward mouse buttons in Windows
+        mainWindow.on('app-command', (e, cmd) => {
+            if (cmd === 'browser-backward' && mainWindow.webContents.canGoBack()) {
+                mainWindow.webContents.goBack();
+            } else if (cmd === 'browser-forward' && mainWindow.webContents.canGoForward()) {
+                mainWindow.webContents.goForward();
+            }
+        });
+    }
+
     webContentsHandler(mainWindow.webContents);
     mainWindowState.manage(mainWindow);
 });
diff --git a/karma.conf.js b/karma.conf.js
index d834987e..3b415b1a 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -84,13 +84,23 @@ module.exports = function (config) {
         // available preprocessors:
         // https://npmjs.org/browse/keyword/karma-preprocessor
         preprocessors: {
-            '{src,test}/**/*.js': ['webpack'],
+            '{src,test}/**/*.js': ['webpack', 'sourcemap'],
         },
 
         // test results reporter to use
-        // possible values: 'dots', 'progress'
         // available reporters: https://npmjs.org/browse/keyword/karma-reporter
-        reporters: ['progress', 'junit'],
+        reporters: ['logcapture', 'spec', 'junit', 'summary'],
+
+        specReporter: {
+            suppressErrorSummary: false, // do print error summary
+            suppressFailed: false, // do print information about failed tests
+            suppressPassed: false, // do print information about passed tests
+            showSpecTiming: true, // print the time elapsed for each spec
+        },
+
+        client: {
+            captureLogs: true,
+        },
 
         // web server port
         port: 9876,
diff --git a/package.json b/package.json
index 2b1d6e82..bb35ce89 100644
--- a/package.json
+++ b/package.json
@@ -31,8 +31,8 @@
     "build:res": "node scripts/copy-res.js",
     "build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
     "build:compile": "npm run reskindex && babel --source-maps -d lib src",
-    "build:bundle": "cross-env NODE_ENV=production webpack -p --progress",
-    "build:bundle:dev": "webpack --optimize-occurence-order --progress",
+    "build:bundle": "cross-env NODE_ENV=production webpack -p --progress --bail",
+    "build:bundle:dev": "webpack --optimize-occurence-order --progress --bail",
     "build:electron": "npm run clean && npm run build && npm run install:electron && build -wml --ia32 --x64",
     "build": "npm run reskindex && npm run build:res && npm run build:bundle",
     "build:dev": "npm run reskindex && npm run build:res && npm run build:bundle:dev",
@@ -57,7 +57,7 @@
     "bluebird": "^3.5.0",
     "browser-request": "^0.3.3",
     "classnames": "^2.1.2",
-    "draft-js": "^0.8.1",
+    "draft-js": "^0.11.0-alpha",
     "extract-text-webpack-plugin": "^0.9.1",
     "favico.js": "^0.3.10",
     "filesize": "3.5.6",
@@ -114,11 +114,15 @@
     "fs-extra": "^0.30.0",
     "html-webpack-plugin": "^2.24.0",
     "json-loader": "^0.5.3",
-    "karma": "^0.13.22",
+    "karma": "^1.7.0",
     "karma-chrome-launcher": "^0.2.3",
     "karma-cli": "^0.1.2",
     "karma-junit-reporter": "^0.4.1",
+    "karma-logcapture-reporter": "0.0.1",
     "karma-mocha": "^0.2.2",
+    "karma-sourcemap-loader": "^0.3.7",
+    "karma-spec-reporter": "0.0.31",
+    "karma-summary-reporter": "^1.3.3",
     "karma-webpack": "^1.7.0",
     "matrix-mock-request": "^1.2.0",
     "matrix-react-test-utils": "^0.2.0",
diff --git a/scripts/fetch-develop.deps.sh b/scripts/fetch-develop.deps.sh
index 4fa1a4a2..e2d40341 100755
--- a/scripts/fetch-develop.deps.sh
+++ b/scripts/fetch-develop.deps.sh
@@ -49,42 +49,47 @@ function dodep() {
         [ "$curbranch" != 'develop' ] && clone $org $repo develop
     } || return $?
 
-    (
-        cd $repo
-        echo "$repo set to branch "`git rev-parse --abbrev-ref HEAD`
-    )
+    echo "$repo set to branch "`git -C "$repo" rev-parse --abbrev-ref HEAD`
 
     mkdir -p node_modules
     rm -r "node_modules/$repo" 2>/dev/null || true
     ln -sv "../$repo" node_modules/
+
+    (
+        cd $repo
+        npm install
+    )
 }
 
+##############################
+
 echo -en 'travis_fold:start:matrix-js-sdk\r'
 echo 'Setting up matrix-js-sdk'
 
 dodep matrix-org matrix-js-sdk
-(
-    cd node_modules/matrix-js-sdk
-    npm install
-)
 
 echo -en 'travis_fold:end:matrix-js-sdk\r'
 
+##############################
+
 echo -en 'travis_fold:start:matrix-react-sdk\r'
 echo 'Setting up matrix-react-sdk'
 
 dodep matrix-org matrix-react-sdk
 
-mkdir -p node_modules/matrix-react-sdk/node_modules
+# replace the version of js-sdk that got pulled into react-sdk with a symlink
+# to our version. Make sure to do this *after* doing 'npm i' in react-sdk,
+# otherwise npm helpfully moves another-json from matrix-js-sdk/node_modules
+# into matrix-react-sdk/node_modules.
+#
+# (note this matches the instructions in the README.)
+rm -r node_modules/matrix-react-sdk/node_modules/matrix-js-sdk
 ln -s ../../matrix-js-sdk node_modules/matrix-react-sdk/node_modules/
 
-(
-    cd node_modules/matrix-react-sdk
-    npm install
-)
-
 echo -en 'travis_fold:end:matrix-react-sdk\r'
 
+##############################
+
 # Link the reskindex binary in place: if we used npm link,
 # npm would do this for us, but we don't because we'd have
 # to define the npm prefix somewhere so it could put the
diff --git a/scripts/jenkins.sh b/scripts/jenkins.sh
index 4f2e9405..7b5b4c8e 100755
--- a/scripts/jenkins.sh
+++ b/scripts/jenkins.sh
@@ -8,8 +8,11 @@ nvm use 6
 
 set -x
 
-# check out corresponding branches of dependencies
-`dirname $0`/fetch-develop.deps.sh
+# check out corresponding branches of dependencies.
+#
+# clone the deps with depth 1: we know we will only ever need that one
+# commit.
+`dirname $0`/fetch-develop.deps.sh --depth 1
 
 npm install
 
diff --git a/src/skins/vector/css/_common.scss b/src/skins/vector/css/_common.scss
index c52204c5..3189deb0 100644
--- a/src/skins/vector/css/_common.scss
+++ b/src/skins/vector/css/_common.scss
@@ -319,6 +319,7 @@ textarea {
     cursor: help;
     transition-duration: 200ms;
     font-size: smaller;
+    filter: opacity(0.5);
 }
 
 .mx_Beta:hover {
diff --git a/src/skins/vector/css/matrix-react-sdk/views/avatars/_BaseAvatar.scss b/src/skins/vector/css/matrix-react-sdk/views/avatars/_BaseAvatar.scss
index 106f0cde..320efda0 100644
--- a/src/skins/vector/css/matrix-react-sdk/views/avatars/_BaseAvatar.scss
+++ b/src/skins/vector/css/matrix-react-sdk/views/avatars/_BaseAvatar.scss
@@ -20,6 +20,7 @@ limitations under the License.
 
 .mx_BaseAvatar_initial {
     position: absolute;
+    left: 0px;
     color: $avatar-initial-color;
     text-align: center;
     speak: none;
diff --git a/src/skins/vector/css/matrix-react-sdk/views/elements/_MemberEventListSummary.scss b/src/skins/vector/css/matrix-react-sdk/views/elements/_MemberEventListSummary.scss
index 1025052b..02ecb5d8 100644
--- a/src/skins/vector/css/matrix-react-sdk/views/elements/_MemberEventListSummary.scss
+++ b/src/skins/vector/css/matrix-react-sdk/views/elements/_MemberEventListSummary.scss
@@ -50,11 +50,22 @@ limitations under the License.
 }
 
 .mx_MatrixChat_useCompactLayout {
+    .mx_MemberEventListSummary {
+        font-size: 13px;
+        .mx_EventTile_line {
+            line-height: 20px;
+        }
+    }
+
     .mx_MemberEventListSummary_line {
         line-height: 22px;
     }
 
     .mx_MemberEventListSummary_toggle {
-        margin-top: 2px;
+        margin-top: 3px;
+    }
+
+    .mx_TextualEvent.mx_MemberEventListSummary_summary {
+        font-size: 13px;
     }
 }
diff --git a/src/skins/vector/css/matrix-react-sdk/views/elements/_RichText.scss b/src/skins/vector/css/matrix-react-sdk/views/elements/_RichText.scss
index 55faab84..8825c98e 100644
--- a/src/skins/vector/css/matrix-react-sdk/views/elements/_RichText.scss
+++ b/src/skins/vector/css/matrix-react-sdk/views/elements/_RichText.scss
@@ -8,6 +8,7 @@
     display: inline-block;
     height: 20px;
     line-height: 20px;
+    padding-left: 5px;
 }
 
 /* More specific to override `.markdown-body a` color */
@@ -35,9 +36,8 @@
 .mx_UserPill .mx_BaseAvatar,
 .mx_RoomPill .mx_BaseAvatar {
     position: relative;
+    left: -3px;
     top: 2px;
-    margin-left: 2px;
-    margin-right: 2px;
 }
 
 .mx_Markdown_BOLD {
diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/_AppsDrawer.scss b/src/skins/vector/css/matrix-react-sdk/views/rooms/_AppsDrawer.scss
index 7d1ac628..75064d93 100644
--- a/src/skins/vector/css/matrix-react-sdk/views/rooms/_AppsDrawer.scss
+++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/_AppsDrawer.scss
@@ -83,11 +83,20 @@ limitations under the License.
     border: 1px solid transparent;
 }
 
+.mx_AppTileMenuBarWidgetDelete {
+    filter: none;
+}
+
 .mx_AppTileMenuBarWidget:hover {
     border: 1px solid $primary-hairline-color;
     border-radius: 2px;
 }
 
+.mx_AppTileBody{
+    height: 350px;
+    overflow: hidden;
+}
+
 .mx_AppTileBody iframe {
     width: 100%;
     height: 350px;
@@ -167,3 +176,53 @@ form.mx_Custom_Widget_Form div {
     margin-top: 10px;
     margin-bottom: 10px;
 }
+
+.mx_AppPermissionWarning {
+    text-align: center;
+    padding: 30px 0;
+    background-color: $primary-bg-color;
+}
+
+.mx_AppPermissionWarningImage {
+    margin: 10px 0;
+}
+
+.mx_AppPermissionWarningImage img {
+    width: 100px;
+}
+
+.mx_AppPermissionWarningText {
+    max-width: 400px;
+    margin: 10px auto 10px auto;
+    color: $primary-fg-color;
+}
+
+.mx_AppPermissionWarningTextLabel {
+    font-weight: bold;
+    display: block;
+}
+
+.mx_AppPermissionWarningTextURL {
+    color: $accent-color;
+}
+
+.mx_AppPermissionButton {
+    padding: 5px;
+    border-radius: 5px;
+    color: $warning-color;
+    background-color: $primary-bg-color;
+}
+
+.mx_AppPermissionButton:hover {
+    background-color: $primary-fg-color;
+    cursor: pointer;
+}
+
+.mx_AppLoading {
+    min-height: 305px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    font-weight: bold;
+}
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 cf148603..e9c62d3a 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
@@ -128,6 +128,12 @@ limitations under the License.
     color: $event-sending-color;
 }
 
+.mx_EventTile_sending .mx_UserPill,
+.mx_EventTile_sending .mx_RoomPill,
+.mx_EventTile_sending .mx_emojione {
+    opacity: 0.5;
+}
+
 .mx_EventTile_notSent {
     color: $event-notsent-color;
 }
@@ -370,6 +376,7 @@ limitations under the License.
 .mx_EventTile_content .markdown-body h6
 {
     font-family: inherit ! important;
+    color: inherit;
 }
 
 
@@ -396,7 +403,15 @@ limitations under the License.
     }
 
     .mx_EventTile.mx_EventTile_info {
+        // same as the padding for non-compact .mx_EventTile.mx_EventTile_info
         padding-top: 0px;
+        font-size: 13px;
+        .mx_EventTile_line {
+            line-height: 20px;
+        }
+        .mx_EventTile_avatar {
+            top: 4px;
+        }
     }
 
     .mx_EventTile .mx_SenderProfile {
@@ -404,6 +419,7 @@ limitations under the License.
     }
 
     .mx_EventTile.mx_EventTile_emote {
+        // add a bit more space for emotes so that avatars don't collide
         padding-top: 8px;
         .mx_EventTile_avatar {
             top: 2px;
@@ -431,10 +447,6 @@ limitations under the License.
         top: 2px;
     }
 
-    .mx_EventTile.mx_EventTile_info .mx_EventTile_avatar {
-        top: 5px;
-    }
-
     .mx_EventTile_e2eIcon {
         top: 7px;
     }
@@ -448,12 +460,21 @@ limitations under the License.
     }
 
     .mx_EventTile_continuation .mx_EventTile_readAvatars,
-    .mx_EventTile_info .mx_EventTile_readAvatars,
     .mx_EventTile_emote .mx_EventTile_readAvatars {
         top: 5px;
     }
 
+    .mx_EventTile_info .mx_EventTile_readAvatars {
+        top: 4px;
+    }
+
     .mx_RoomView_MessageList h2 {
         margin-top: 6px;
     }
+
+    .mx_EventTile_content .markdown-body {
+      p, ul, ol, dl, blockquote, pre, table {
+        margin-bottom: 4px; // 1/4 of the non-compact margin-bottom
+      }
+    }
 }
diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/_MessageComposer.scss b/src/skins/vector/css/matrix-react-sdk/views/rooms/_MessageComposer.scss
index 98c803fd..d85ce58a 100644
--- a/src/skins/vector/css/matrix-react-sdk/views/rooms/_MessageComposer.scss
+++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/_MessageComposer.scss
@@ -95,8 +95,6 @@ limitations under the License.
 .mx_MessageComposer_input .DraftEditor-root {
     width: 100%;
     flex: 1;
-    max-height: 120px;
-    overflow: auto;
     word-break: break-word;
 }
 
@@ -105,6 +103,11 @@ limitations under the License.
     padding-top: 2px;
 }
 
+.mx_MessageComposer_input .public-DraftEditor-content {
+    max-height: 120px;
+    overflow: auto;
+}
+
 .mx_MessageComposer_input blockquote {
     color: $blockquote-fg-color;
     margin: 0 0 16px;
diff --git a/src/skins/vector/img/cancel-red.svg b/src/skins/vector/img/cancel-red.svg
new file mode 100644
index 00000000..a72a970b
--- /dev/null
+++ b/src/skins/vector/img/cancel-red.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+    <!-- Generator: Sketch 3.4.2 (15857) - http://www.bohemiancoding.com/sketch -->
+    <title>Slice 1</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+        <path d="M9.74464309,-3.02908503 L8.14106175,-3.02908503 L8.14106175,8.19448443 L-3.03028759,8.19448443 L-3.03028759,9.7978515 L8.14106175,9.7978515 L8.14106175,20.9685098 L9.74464309,20.9685098 L9.74464309,9.7978515 L20.9697124,9.7978515 L20.9697124,8.19448443 L9.74464309,8.19448443 L9.74464309,-3.02908503" id="Fill-108" opacity="0.9" fill="#ff0064" sketch:type="MSShapeGroup" transform="translate(8.969712, 8.969712) rotate(-315.000000) translate(-8.969712, -8.969712) "></path>
+    </g>
+</svg>