diff --git a/.gitignore b/.gitignore
index 13466ce8..7cbd6fc2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,7 @@
 node_modules
 vector/bundle.*
 lib
+.DS_Store
+key.pem
+cert.pem
+build
diff --git a/README.md b/README.md
index a15917a4..c834e013 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ setup above, and your changes will cause an instant rebuild.
 
 However, all serious development on Vector happens on the `develop` branch.  This typically
 depends on the `develop` snapshot versions of `matrix-react-sdk` and `matrix-js-sdk`
-too, which isn't expressed in Vector's `package.json`.  To do this, check out
+too, which isn't handled by Vector's `package.json`.  To get the right dependencies, check out
 the `develop` branches of these libraries and then use `npm link` to tell Vector
 about them:
 
diff --git a/package.json b/package.json
index 27302a74..eb9c3aff 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,8 @@
     "matrix-react-sdk": "^0.0.2",
     "q": "^1.4.1",
     "react": "^0.13.3",
-    "react-loader": "^1.4.0"
+    "react-loader": "^1.4.0",
+    "sanitize-html": "^1.11.1"
   },
   "devDependencies": {
     "babel": "^5.8.23",
diff --git a/src/DateUtils.js b/src/DateUtils.js
new file mode 100644
index 00000000..fe363586
--- /dev/null
+++ b/src/DateUtils.js
@@ -0,0 +1,45 @@
+/*
+Copyright 2015 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.
+*/
+
+'use strict';
+
+var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+
+module.exports = {
+    formatDate: function(date) {
+        // date.toLocaleTimeString is completely system dependent.
+        // just go 24h for now
+        function pad(n) {
+            return (n < 10 ? '0' : '') + n;
+        }
+
+        var now = new Date();
+        if (date.toDateString() === now.toDateString()) {
+            return pad(date.getHours()) + ':' + pad(date.getMinutes());
+        }
+        else if (now.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
+            return days[date.getDay()] + " " + pad(date.getHours()) + ':' + pad(date.getMinutes());
+        }
+        else if (now.getFullYear() === date.getFullYear()) {
+            return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + pad(date.getHours()) + ':' + pad(date.getMinutes());
+        }
+        else {
+            return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + date.getFullYear() + " " + pad(date.getHours()) + ':' + pad(date.getMinutes());
+        }
+    }
+}
+
diff --git a/src/controllers/organisms/RoomList.js b/src/controllers/organisms/RoomList.js
index 151a6ca2..964a2648 100644
--- a/src/controllers/organisms/RoomList.js
+++ b/src/controllers/organisms/RoomList.js
@@ -36,11 +36,9 @@ module.exports = {
         cli.on("RoomState.events", this.onRoomStateEvents);
         cli.on("RoomMember.name", this.onRoomMemberName);
 
-        var rooms = this.getRoomList();
-        this.setState({
-            roomList: rooms,
-            activityMap: {}
-        });
+        var s = this.getRoomLists();
+        s.activityMap = {};
+        this.setState(s);
     },
 
     componentDidMount: function() {
@@ -87,9 +85,7 @@ module.exports = {
     onRoomTimeline: function(ev, room, toStartOfTimeline) {
         if (toStartOfTimeline) return;
 
-        var newState = {
-            roomList: this.getRoomList()
-        };
+        var newState = this.getRoomLists();
         if (
             room.roomId != this.props.selectedRoom &&
             ev.getSender() != MatrixClientPeg.get().credentials.userId)
@@ -123,18 +119,23 @@ module.exports = {
 
 
     refreshRoomList: function() {
-        var rooms = this.getRoomList();
-        this.setState({
-            roomList: rooms
-        });
+        this.setState(this.getRoomLists());
     },
 
-    getRoomList: function() {
-        return RoomListSorter.mostRecentActivityFirst(
+    getRoomLists: function() {
+        var s = {};
+        var inviteList = [];
+        s.roomList = RoomListSorter.mostRecentActivityFirst(
             MatrixClientPeg.get().getRooms().filter(function(room) {
                 var me = room.getMember(MatrixClientPeg.get().credentials.userId);
+
+                if (me && me.membership == "invite") {
+                    inviteList.push(room);
+                    return false;
+                }
+
                 var shouldShowRoom =  (
-                    me && (me.membership == "join" || me.membership == "invite")
+                    me && (me.membership == "join")
                 );
                 // hiding conf rooms only ever toggles shouldShowRoom to false
                 if (shouldShowRoom && HIDE_CONFERENCE_CHANS) {
@@ -153,6 +154,8 @@ module.exports = {
                 return shouldShowRoom;
             })
         );
+        s.inviteList = RoomListSorter.mostRecentActivityFirst(inviteList);
+        return s;
     },
 
     _recheckCallElement: function(selectedRoomId) {
@@ -174,10 +177,10 @@ module.exports = {
         }
     },
 
-    makeRoomTiles: function() {
+    makeRoomTiles: function(list, isInvite) {
         var self = this;
         var RoomTile = sdk.getComponent("molecules.RoomTile");
-        return this.state.roomList.map(function(room) {
+        return list.map(function(room) {
             var selected = room.roomId == self.props.selectedRoom;
             return (
                 <RoomTile
@@ -187,6 +190,7 @@ module.exports = {
                     selected={selected}
                     unread={self.state.activityMap[room.roomId] === 1}
                     highlight={self.state.activityMap[room.roomId] === 2}
+                    isInvite={isInvite}
                 />
             );
         });
diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js
index 21027cbf..c0077bc0 100644
--- a/src/controllers/organisms/RoomView.js
+++ b/src/controllers/organisms/RoomView.js
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
+var Matrix = require("matrix-js-sdk");
 var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
 var React = require("react");
 var q = require("q");
@@ -38,6 +39,8 @@ module.exports = {
             uploadingRoomSettings: false,
             numUnreadMessages: 0,
             draggingFile: false,
+            searching: false,
+            searchResults: null,
         }
     },
 
@@ -356,6 +359,41 @@ module.exports = {
         return WhoIsTyping.whoIsTypingString(this.state.room);
     },
 
+    onSearch: function(term, scope) {
+        var filter;
+        if (scope === "Room") { // FIXME: should be enum
+            filter = {
+                // XXX: it's unintuitive that the filter for searching doesn't have the same shape as the v2 filter API :(
+                rooms: [
+                    this.props.roomId
+                ]
+            };
+        }
+
+        var self = this;
+        MatrixClientPeg.get().search({
+            body: {
+                search_categories: {
+                    room_events: {
+                        search_term: term,
+                        filter: filter,
+                        event_context: {
+                            before_limit: 1,
+                            after_limit: 1,
+                        }
+                    }
+                }
+            }            
+        }).then(function(data) {
+            self.setState({
+                searchTerm: term,
+                searchResults: data,
+            });
+        }, function(error) {
+            // TODO: show dialog or something
+        });
+    },
+
     getEventTiles: function() {
         var DateSeparator = sdk.getComponent('molecules.DateSeparator');
 
@@ -364,6 +402,36 @@ module.exports = {
 
         var EventTile = sdk.getComponent('molecules.EventTile');
 
+        if (this.state.searchResults) {
+            // XXX: this dance is foul, due to the results API not returning sorted results
+            var results = this.state.searchResults.search_categories.room_events.results;
+            var eventIds = Object.keys(results);
+            // XXX: todo: merge overlapping results somehow?
+            // XXX: why doesn't searching on name work?
+            var resultList = eventIds.map(function(key) { return results[key]; }).sort(function(a, b) { b.rank - a.rank });
+            for (var i = 0; i < resultList.length; i++) {
+                var ts1 = resultList[i].result.origin_server_ts;
+                ret.push(<li key={ts1 + "-search"}><DateSeparator ts={ts1}/></li>); //  Rank: {resultList[i].rank}
+                var mxEv = new Matrix.MatrixEvent(resultList[i].result);
+                if (resultList[i].context.events_before[0]) {
+                    var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_before[0]);
+                    if (EventTile.supportsEventType(mxEv2.getType())) {
+                        ret.push(<li key={mxEv.getId() + "-1"}><EventTile mxEvent={mxEv2} contextual={true} /></li>);
+                    }
+                }
+                if (EventTile.supportsEventType(mxEv.getType())) {
+                    ret.push(<li key={mxEv.getId() + "+0"}><EventTile mxEvent={mxEv} searchTerm={this.state.searchTerm}/></li>);
+                }
+                if (resultList[i].context.events_after[0]) {
+                    var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_after[0]);
+                    if (EventTile.supportsEventType(mxEv2.getType())) {
+                        ret.push(<li key={mxEv.getId() + "+1"}><EventTile mxEvent={mxEv2} contextual={true} /></li>);
+                    }
+                }
+            }
+            return ret;
+        }
+
         for (var i = this.state.room.timeline.length-1; i >= 0 && count < this.state.messageCap; --i) {
             var mxEv = this.state.room.timeline[i];
 
diff --git a/src/skins/vector/css/atoms/ImageView.css b/src/skins/vector/css/atoms/ImageView.css
new file mode 100644
index 00000000..22ef343b
--- /dev/null
+++ b/src/skins/vector/css/atoms/ImageView.css
@@ -0,0 +1,144 @@
+/*
+Copyright 2015 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.
+*/
+
+/* This has got to be the most fragile piece of CSS ever written.
+   But empirically it works on Chrome/FF/Safari
+ */
+
+.mx_ImageView {
+    display: -webkit-flex;
+    display: flex;
+    width: 100%;
+    height: 100%;
+    -webkit-align-items: center;
+    align-items: center;
+}
+
+.mx_ImageView_lhs {
+    -webkit-box-ordinal-group: 1;
+    order: 1;
+    -webkit-flex: 1;
+    flex: 1 1 10%;
+    min-width: 60px;
+    /*
+    background-color: #080;
+    height: 20px;
+    */
+}
+
+.mx_ImageView_content {
+    -webkit-box-ordinal-group: 2;
+    order: 2;
+    /* min-width hack needed for FF */
+    min-width: 0px;
+    height: 90%;
+    -webkit-flex: 15;
+    flex: 15 15 0;
+
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    -webkit-justify-content: center;
+    align-items: center;
+    justify-content: center;
+}
+
+.mx_ImageView_content img {
+    max-width: 100%;
+    /* XXX: max-height interacts badly with flex on Chrome and doesn't relayout properly until you refresh */
+    max-height: 100%;
+    /* object-fit hack needed for Chrome due to Chrome not relaying out until you refresh */
+    object-fit: contain;
+    /* background-image: url('img/trans.png'); */
+}
+
+.mx_ImageView_labelWrapper {
+    position: absolute;
+    top: 0px;
+    height: 100%;
+    overflow: auto;
+}
+
+.mx_ImageView_label {
+    text-align: left;
+    display: flex;
+    display: -webkit-flex;
+    justify-content: center;
+    -webkit-justify-content: center;
+    flex-direction: column;
+    -webkit-flex-direction: column;
+    padding-left: 60px;
+    padding-right: 60px;
+    min-height: 100%;
+    color: #fff;
+}
+
+.mx_ImageView_name {
+    font-size: 20px;
+    margin-bottom: 6px;
+    pointer-events: all;
+}
+
+.mx_ImageView_metadata {
+    font-size: 16px;
+    opacity: 0.5;
+    pointer-events: all;
+}
+
+.mx_ImageView_download {
+    pointer-events: all;
+    display: table;
+    margin-top: 24px;
+    margin-bottom: 6px;
+    border-radius: 5px;
+    background-color: #454545;
+    font-size: 16px;
+    padding: 9px;
+    border: 1px solid #fff;
+}
+
+.mx_ImageView_size {
+    font-size: 12px;
+}
+
+.mx_ImageView_link {
+    color: #fff ! important;
+    text-decoration: none ! important;
+}
+
+.mx_ImageView_button {
+    pointer-events: all;
+    font-size: 16px;
+    opacity: 0.5;
+    margin-top: 18px;
+    cursor: pointer;
+}
+
+.mx_ImageView_shim {
+    height: 30px;
+}
+
+.mx_ImageView_rhs {
+    -webkit-box-ordinal-group: 3;
+    order: 3;
+    -webkit-flex: 1;
+    flex: 1 1 10%;
+    min-width: 300px;
+    /*
+    background-color: #800;
+    height: 20px;
+    */
+}
diff --git a/src/skins/vector/css/atoms/MemberAvatar.css b/src/skins/vector/css/atoms/MemberAvatar.css
index 6422df79..fc5fd60d 100644
--- a/src/skins/vector/css/atoms/MemberAvatar.css
+++ b/src/skins/vector/css/atoms/MemberAvatar.css
@@ -17,6 +17,5 @@ limitations under the License.
 .mx_MemberAvatar {
     z-index: 20;
     border-radius: 20px;
-    background-color: #dbdbdb;
 }
 
diff --git a/src/skins/vector/css/common.css b/src/skins/vector/css/common.css
index 93012c0f..a68d190d 100644
--- a/src/skins/vector/css/common.css
+++ b/src/skins/vector/css/common.css
@@ -22,7 +22,7 @@ html {
 }
 
 body {
-    font-family: 'Lato', Helvetica, Arial, Sans-Serif;
+    font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif;
     font-size: 16px;
     color: #454545;
     border: 0px;
@@ -34,7 +34,7 @@ div.error {
 }
 
 h2 {
-    color: #80cef4;
+    color: #454545;
     font-weight: 400;
     font-size: 20px;
     margin-top: 16px;
@@ -44,7 +44,7 @@ h2 {
 a:hover,
 a:link,
 a:visited {
-    color: #80CEF4;
+    color: #76cfa6;
 }
 
 .mx_ContextualMenu_background {
@@ -58,7 +58,7 @@ a:visited {
 }
 
 .mx_ContextualMenu {
-    border: 1px solid #a9dbf4;
+    border: 1px solid #a4a4a4;
     border-radius: 8px;
     background-color: #fff;
     color: #747474;
@@ -129,13 +129,21 @@ a:visited {
     font-size: 16px;
     position: relative;
     border-radius: 8px;
-    max-width: 75%;
+    max-width: 80%;
 }
 
-.mx_ImageView {
-    margin: 6px;
-    /* hack: flexbox bug? */
-    margin-bottom: 4px;
+.mx_Dialog_lightbox .mx_Dialog_background {
+    opacity: 0.85;
+}
+
+.mx_Dialog_lightbox .mx_Dialog {
+    border-radius: 0px;
+    background-color: transparent;
+    width: 100%;
+    height: 100%;
+    max-width: 100%;
+    max-height: 100%;
+    pointer-events: none;
 }
 
 .mx_Dialog_content {
@@ -153,7 +161,7 @@ a:visited {
     font-weight: 400;
     font-size: 16px;
     color: #fff;
-    background-color: #80cef4;
+    background-color: #76cfa6;
     margin-left: 8px;
     margin-right: 8px;
     padding-left: 1em;
@@ -164,7 +172,7 @@ a:visited {
 .mx_QuestionDialogTitle {
     min-height: 16px;
     padding: 12px;
-    border-bottom: 1px solid #a9dbf4;
+    border-bottom: 1px solid #a4a4a4;
     font-weight: bold;
     font-size: 20px;
     line-height: 1.4;
diff --git a/src/skins/vector/css/hide.css b/src/skins/vector/css/hide.css
index fbc2db20..7d8ee302 100644
--- a/src/skins/vector/css/hide.css
+++ b/src/skins/vector/css/hide.css
@@ -1,7 +1,4 @@
 .mx_RoomDropTarget,
-.mx_RoomList_favourites_label,
-.mx_RoomList_archive_label,
-.mx_RoomHeader_search,
 .mx_RoomSettings_encrypt,
 .mx_CreateRoom_encrypt,
 .mx_RightPanel_filebutton
diff --git a/src/skins/vector/css/molecules/EventAsTextTile.css b/src/skins/vector/css/molecules/EventAsTextTile.css
new file mode 100644
index 00000000..d18fdc80
--- /dev/null
+++ b/src/skins/vector/css/molecules/EventAsTextTile.css
@@ -0,0 +1,19 @@
+/*
+Copyright 2015 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_EventAsTextTile {
+    opacity: 0.5;
+}
diff --git a/src/skins/vector/css/molecules/EventTile.css b/src/skins/vector/css/molecules/EventTile.css
index 1cd2fa46..eb59711e 100644
--- a/src/skins/vector/css/molecules/EventTile.css
+++ b/src/skins/vector/css/molecules/EventTile.css
@@ -17,20 +17,19 @@ limitations under the License.
 .mx_EventTile {
     max-width: 100%;
     clear: both;
-    margin-top: 32px;
+    margin-top: 24px;
     margin-left: 56px;
 }
 
 .mx_EventTile_avatar {
-    padding-left: 12px;
+    padding-left: 18px;
     padding-right: 12px;
     margin-left: -64px;
-    margin-top: -7px;
+    margin-top: -4px;
     float: left;
 }
 
 .mx_EventTile_avatar img {
-    background-color: #dbdbdb;
     border-radius: 20px;
     border: 0px;
 }
@@ -48,19 +47,30 @@ limitations under the License.
 }
 
 .mx_EventTile .mx_MessageTimestamp {
-    color: #454545;
-    opacity: 0.5;
-    font-size: 14px;
+    color: #acacac;
+    font-size: 12px;
     float: right;
 }
 
+.mx_EventTile_line {
+    position: relative;
+}
+
 .mx_EventTile_content {
     padding-right: 100px;
     display: block;
 }
 
-.mx_EventTile_notice .mx_MessageTile_content {
-    opacity: 0.5;
+.mx_MessageTile_content {
+    display: block;
+    margin-right: 100px;
+}
+
+.mx_MessageTile_searchHighlight {
+    background-color: #76cfa6;
+    color: #fff;
+    border-radius: 5px;
+    padding: 4px;
 }
 
 .mx_EventTile_sending {
@@ -75,38 +85,41 @@ limitations under the License.
     color: #FF0064;
 }
 
+.mx_EventTile_contextual {
+    opacity: 0.4;
+}
+
 .mx_EventTile_msgOption {
     float: right;
 }
 
 .mx_MessageTimestamp {
-    display: none;
+    visibility: hidden;
 }
 
 .mx_EventTile_last .mx_MessageTimestamp {
-    display: block;
+    visibility: visible;
 }
 
 .mx_EventTile:hover .mx_MessageTimestamp {
-    display: block;
+    visibility: visible;
 }
 
 .mx_EventTile_editButton {
-    float: right;
-    display: none;
-    border: 0px;
-    outline: none;
-    margin-right: 3px;
+    position: absolute;
+    right: 1px;
+    top: 15px;
+    visibility: hidden;
 }
 
 .mx_EventTile:hover .mx_EventTile_editButton {
-    display: inline-block;
+    visibility: visible;
 }
 
 .mx_EventTile.menu .mx_EventTile_editButton {
-    display: inline-block;
+    visibility: visible;
 }
 
 .mx_EventTile.menu .mx_MessageTimestamp {
-    display: inline-block;
+    visibility: visible;
 }
diff --git a/src/skins/vector/css/molecules/MImageTile.css b/src/skins/vector/css/molecules/MImageTile.css
index 10e5b50b..94f1c919 100644
--- a/src/skins/vector/css/molecules/MImageTile.css
+++ b/src/skins/vector/css/molecules/MImageTile.css
@@ -23,12 +23,12 @@ limitations under the License.
 }
 
 .mx_MImageTile_download {
-    color: #80cef4;
+    color: #76cfa6;
     cursor: pointer;
 }
 
 .mx_MImageTile_download a {
-    color: #80cef4;
+    color: #76cfa6;
     text-decoration: none;
 }
 
diff --git a/src/skins/vector/css/molecules/MNoticeTile.css b/src/skins/vector/css/molecules/MNoticeTile.css
index 0e9c3ca1..0a0db62e 100644
--- a/src/skins/vector/css/molecules/MNoticeTile.css
+++ b/src/skins/vector/css/molecules/MNoticeTile.css
@@ -15,5 +15,5 @@ limitations under the License.
 */
 
 .mx_MNoticeTile {
-    opacity: 0.5;
+    opacity: 0.6;
 }
diff --git a/src/skins/vector/css/molecules/MTextTile.css b/src/skins/vector/css/molecules/MTextTile.css
index 5b117e41..96a9d1db 100644
--- a/src/skins/vector/css/molecules/MTextTile.css
+++ b/src/skins/vector/css/molecules/MTextTile.css
@@ -17,4 +17,3 @@ limitations under the License.
 .mx_MTextTile {
     white-space: pre-wrap;
 }
-
diff --git a/src/skins/vector/css/molecules/MemberInfo.css b/src/skins/vector/css/molecules/MemberInfo.css
index 52c48a79..6471a86c 100644
--- a/src/skins/vector/css/molecules/MemberInfo.css
+++ b/src/skins/vector/css/molecules/MemberInfo.css
@@ -14,3 +14,49 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
+.mx_MemberInfo {
+    height: 100%;
+}
+
+.mx_MemberInfo h2 {
+    margin-top: 6px;
+}
+
+.mx_MemberInfo_cancel {
+    float: right;
+    margin-right: 18px;
+    cursor: pointer;
+}
+
+.mx_MemberInfo_avatar {
+    clear: both;
+}
+
+.mx_MemberInfo_avatar img {
+    border-radius: 48px;
+}
+
+.mx_MemberInfo_profileField {
+    opacity: 0.6;
+    font-size: 14px;
+}
+
+.mx_MemberInfo_buttons {
+    margin-top: 18px;
+}
+
+.mx_MemberInfo_field {
+    cursor: pointer;
+    width: 100px;
+    text-align: center;
+    font-size: 12px;    
+    background-color: #888;
+    color: #fff;
+    font-weight: bold;
+    border-radius: 20px;
+    padding-left: 6px;
+    padding-right: 6px;
+    padding-top: 4px;
+    padding-bottom: 2px;
+    margin-bottom: 4px;
+}
diff --git a/src/skins/vector/css/molecules/MemberTile.css b/src/skins/vector/css/molecules/MemberTile.css
index faae142a..cfeaeaee 100644
--- a/src/skins/vector/css/molecules/MemberTile.css
+++ b/src/skins/vector/css/molecules/MemberTile.css
@@ -16,52 +16,27 @@ limitations under the License.
 
 .mx_MemberTile {
     display: table-row;
-    height: 49px;
     position: relative;
+    color: #454545;
+    cursor: pointer;
 }
 
 .mx_MemberTile_avatar {
     display: table-cell;
-    padding-left: 14px;
+    padding-left: 3px;
     padding-right: 12px;
-    padding-top: 3px;
-    padding-bottom: 3px;
+    padding-top: 2px;
+    padding-bottom: 0px;
     vertical-align: middle;
-    width: 40px;
-    height: 40px;
+    width: 36px;
+    height: 36px;
     position: relative;
 }
 
-.mx_MemberTile_inviteTile {
-    cursor: pointer;
-}
-
-.mx_MemberTile_inviteEditing {
-    display: initial ! important;
-}
-
-.mx_MemberTile_inviteEditing .mx_MemberTile_avatar {
-    display: none;
-}
-
-.mx_MemberTile_inviteEditing .mx_MemberTile_name {
-    width: 200px;
-}
-
-.mx_MemberTile_inviteEditing .mx_MemberTile_name input {
-    border-radius: 3px;
-    border: 1px solid #c7c7c7;
-    font-weight: 300;
-    font-size: 14px;
-    padding: 9px;
-    margin-top: 6px;
-    margin-left: 14px;
-}
-
 .mx_MemberTile_power {
     position: absolute;
-    width: 48px;
-    height: 48px;
+    width: 44px;
+    height: 44px;
     left: 10px;
     top: -1px;
 }
@@ -79,20 +54,18 @@ limitations under the License.
     vertical-align: middle;
 }
 
-.mx_MemberTile_hover {
-    background-color: #f0f0f0;
-    font-size: 12px;
-    color: #747474;    
-}
-
 .mx_MemberTile_userId {
-    font-weight: bold;
+    font-size: 14px;
     overflow: hidden;
     text-overflow: ellipsis;
 }
 
-.mx_MemberTile_leave {
-    cursor: pointer;
+.mx_MemberTile_presence {
+    font-size: 12px;
+    opacity: 0.5;
+}
+
+.mx_MemberTile_chevron {
     margin-top: 8px;
     margin-right: -4px;
     margin-left: 6px;
@@ -113,14 +86,14 @@ limitations under the License.
 
 .mx_MemberTile_unavailable .mx_MemberTile_avatar,
 .mx_MemberTile_unavailable .mx_MemberTile_name,
-.mx_MemberTile_unavailable .mx_MemberTile_nameSpan
+.mx_MemberTile_unavailable .mx_MemberTile_userId
 {
     opacity: 0.66;
 }
 
 .mx_MemberTile_offline .mx_MemberTile_avatar,
 .mx_MemberTile_offline .mx_MemberTile_name,
-.mx_MemberTile_offline .mx_MemberTile_nameSpan
+.mx_MemberTile_offline .mx_MemberTile_userId
 {
     opacity: 0.25;
 }
diff --git a/src/skins/vector/css/molecules/MessageComposer.css b/src/skins/vector/css/molecules/MessageComposer.css
index af4934ee..44e12276 100644
--- a/src/skins/vector/css/molecules/MessageComposer.css
+++ b/src/skins/vector/css/molecules/MessageComposer.css
@@ -15,39 +15,37 @@ limitations under the License.
 */
 
 .mx_MessageComposer_wrapper {
-    max-width: 720px;
-    height: 50px;
+    max-width: 960px;
+    height: 70px;
     vertical-align: middle;
     margin: auto;
     background-color: #fff;
-    border-radius: 25px;
-    border: 1px solid #a9dbf4;
+    border-top: 2px solid #e1dddd;
 }
 
 .mx_MessageComposer_row {
     display: table-row;
     width: 100%;
-    height: 50px;
+    height: 70px;
 }
 
 .mx_MessageComposer .mx_MessageComposer_avatar {
     display: table-cell;
-    padding-left: 5px;
-    padding-right: 10px;
-    height: 50px;
+    padding-left: 10px;
+    padding-right: 20px;
+    height: 70px;
 }
 
 .mx_MessageComposer .mx_MessageComposer_avatar img {
-    margin-top: 5px;
+    margin-top: 18px;
     border-radius: 20px;
-    background-color: #dbdbdb;
 }
 
 .mx_MessageComposer_input {
     display: table-cell;
     width: 100%;
     vertical-align: middle;
-    height: 50px;
+    height: 70px;
 }
 
 .mx_MessageComposer_input textarea {
@@ -64,21 +62,32 @@ limitations under the License.
     box-shadow: none;    
 
     /* needed for FF */
-    font-family: 'Lato', Helvetica, Arial, Sans-Serif;
+    font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif;
 }
 
 /* hack for FF as vertical alignment of custom placeholder text is broken */
 .mx_MessageComposer_input textarea::-moz-placeholder {
     line-height: 100%;
+    color: #76cfa6;
+}
+.mx_MessageComposer_input textarea::-webkit-input-placeholder {
+    color: #76cfa6;
 }
 
-.mx_MessageComposer_upload {
+.mx_MessageComposer_upload,
+.mx_MessageComposer_call {
     display: table-cell;
     vertical-align: middle;
-    padding-right: 15px;
+    padding-left: 10px;
+    padding-right: 10px;
     cursor: pointer;
 }
 
+.mx_MessageComposer_call {
+    padding-right: 10px;
+    padding-top: 4px;
+}
+
 .mx_MessageComposer_upload img {
     margin-top: 5px;
 }
diff --git a/src/skins/vector/css/molecules/RoomHeader.css b/src/skins/vector/css/molecules/RoomHeader.css
index f7adb618..2eeda241 100644
--- a/src/skins/vector/css/molecules/RoomHeader.css
+++ b/src/skins/vector/css/molecules/RoomHeader.css
@@ -18,10 +18,10 @@ limitations under the License.
 }
 
 .mx_RoomHeader_wrapper {
-    max-width: 720px;
+    max-width: 960px;
     margin: auto;
-    height: 88px;
-    border-bottom: 1px solid #a8dbf3;
+    height: 83px;
+    border-bottom: 1px solid #eeeeee;
 
     display: -webkit-box;
     display: -moz-box;
@@ -47,7 +47,7 @@ limitations under the License.
 .mx_RoomHeader_textButton {
     height: 48px;
     margin-top: 18px;
-    background-color: #80cef4;
+    background-color: #76cfa6;
     border-radius: 48px;
     margin-right: 8px;
     color: #fff;
@@ -71,11 +71,8 @@ limitations under the License.
     }
 
 .mx_RoomHeader_rightRow {
-    height: 48px;
-    margin-top: 18px;
+    margin-top: 32px;
     background-color: #fff;
-    border-radius: 48px;
-    border: 1px solid #a9dbf4;
 
     -webkit-box-ordinal-group: 3;
     -moz-box-ordinal-group: 3;
@@ -91,8 +88,8 @@ limitations under the License.
 }
 
 .mx_RoomHeader_simpleHeader {
-    line-height: 88px;
-    color: #80cef4;
+    line-height: 83px;
+    color: #76cfa6;
     font-weight: 400;
     font-size: 20px;
     overflow: hidden;
@@ -100,18 +97,39 @@ limitations under the License.
 }
 
 .mx_RoomHeader_name {
+    cursor: pointer;
     vertical-align: middle;
     height: 28px;
-    color: #80cef4;
-    font-weight: 400;
-    font-size: 20px;
-    padding-left: 16px;
+    color: #454545;
+    font-weight: 800;
+    font-size: 24px;
+    padding-left: 8px;
     padding-right: 16px;
     text-overflow: ellipsis;
 }
 
+.mx_RoomHeader_nametext {
+    display: inline-block;
+}
+
+.mx_RoomHeader_settingsButton {
+    display: inline-block;
+    visibility: hidden;
+    position: relative;
+    bottom: 10px;
+    left: 4px;
+}
+
+.mx_RoomHeader_name:hover {
+    color: #76cfa6;
+}
+
+.mx_RoomHeader_name:hover .mx_RoomHeader_settingsButton {
+    visibility: visible;
+}
+
 .mx_RoomHeader_nameEditing {
-    padding-left: 16px;
+    padding-left: 8px;
     padding-right: 16px;
     margin-top: -5px;
 }
@@ -133,9 +151,9 @@ limitations under the License.
     vertical-align: bottom;
     float: left;
     max-height: 38px;
-    color: #70b5d7;  
+    color: #454545;
     font-weight: 300;  
-    padding-left: 16px;
+    padding-left: 8px;
     padding-right: 16px;
     overflow: hidden;
     text-overflow: ellipsis;
@@ -153,9 +171,8 @@ limitations under the License.
 }
 
 .mx_RoomHeader_button {
-    height: 48px;
     display: table-cell;
-    vertical-align: middle;
+    vertical-align: top;
     padding-left: 8px;
     padding-right: 8px;
 }
@@ -170,4 +187,4 @@ limitations under the License.
 
 .mx_RoomHeader_voipButtons {
     margin-top: 18px;
-}
\ No newline at end of file
+}
diff --git a/src/skins/vector/css/molecules/RoomSettings.css b/src/skins/vector/css/molecules/RoomSettings.css
index 3a66f0e9..a669c5b2 100644
--- a/src/skins/vector/css/molecules/RoomSettings.css
+++ b/src/skins/vector/css/molecules/RoomSettings.css
@@ -61,7 +61,7 @@ limitations under the License.
     font-weight: 400;
     font-size: 16px;
     color: #fff;
-    background-color: #80cef4;
+    background-color: #76cfa6;
     width: auto;
     margin: auto;
     padding: 6px;
diff --git a/src/skins/vector/css/molecules/RoomTile.css b/src/skins/vector/css/molecules/RoomTile.css
index 511fc94f..f2c1daad 100644
--- a/src/skins/vector/css/molecules/RoomTile.css
+++ b/src/skins/vector/css/molecules/RoomTile.css
@@ -17,24 +17,24 @@ limitations under the License.
 .mx_RoomTile {
     cursor: pointer;
     display: table-row;
-    color: #818794;
+    font-size: 14px;
 }
 
 .mx_RoomTile_avatar {
     display: table-cell;
-    padding-right: 10px;
-    padding-top: 3px;
-    padding-bottom: 3px;
-    padding-left: 10px;
+    background: #eaf5f0;
+    padding-right: 8px;
+    padding-top: 4px;
+    padding-bottom: 2px;
+    padding-left: 18px;
     vertical-align: middle;
-    width: 36px;
-    height: 36px;
+    width: 24px;
+    height: 24px;
     position: relative;
 }
 
 .mx_RoomTile_avatar img {
     border-radius: 20px;
-    background-color: #dbdbdb;
 }
 
 .mx_RoomTile_name {
@@ -43,6 +43,13 @@ limitations under the License.
     overflow: hidden;
     text-overflow: ellipsis;
     padding-right: 16px;    
+    color: #454545;
+    opacity: 0.8;
+}
+
+.mx_RoomTile_invite {
+    opacity: 0.5;
+    font-weight: normal;
 }
 
 .collapsed .mx_RoomTile_name {
@@ -63,7 +70,7 @@ limitations under the License.
 }
 
 .mx_RoomTile_badge {    
-    background-color: #80cef4;
+    background-color: #76cfa6;
     color: #fff;
     border-radius: 26px;
     font-weight: 400;
@@ -75,6 +82,7 @@ limitations under the License.
 }
 */
 
+/*
 .mx_RoomTile_badge {    
     background-color: #ff0064;
     border: 3px solid #fff;
@@ -85,19 +93,36 @@ limitations under the License.
     right: 9px;
     bottom: 3px;
 }
+*/
+
+.mx_RoomTile_badge {
+    background-color: #76cfa6;
+    width: 4px;
+    position: absolute;
+    left: 0px;
+    top: 5px;
+    height: 24px;
+}
 
 .mx_RoomTile_unread,
 .mx_RoomTile_highlight,
 .mx_RoomTile_invited
 {
     font-weight: bold;
-    color: #000;
 }
 
 .mx_RoomTile_selected {
-    background-color: #f3f8fa;
-    color: #80cef4;
-    font-weight: bold;
+}
+
+.mx_RoomTile.mx_RoomTile_selected {
+    background: url('img/selected.png');
+    background-repeat: no-repeat;
+    background-position: right center;
+}
+
+.mx_RoomTile_arrow {
+    position: absolute;
+    right: 0px;
 }
 
 .mx_RoomTile:hover {
diff --git a/src/skins/vector/css/molecules/RoomTooltip.css b/src/skins/vector/css/molecules/RoomTooltip.css
index f45970fe..604c6a56 100644
--- a/src/skins/vector/css/molecules/RoomTooltip.css
+++ b/src/skins/vector/css/molecules/RoomTooltip.css
@@ -17,7 +17,7 @@ limitations under the License.
 .mx_RoomTooltip {
     display: none;
     position: fixed;
-    border: 1px solid #a9dbf4;
+    border: 1px solid #a4a4a4;
     border-radius: 8px;
     background-color: #fff;
     z-index: 1000;
diff --git a/src/skins/vector/css/molecules/SearchBar.css b/src/skins/vector/css/molecules/SearchBar.css
new file mode 100644
index 00000000..b116674b
--- /dev/null
+++ b/src/skins/vector/css/molecules/SearchBar.css
@@ -0,0 +1,64 @@
+/*
+Copyright 2015 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_SearchBar {
+    padding-top: 5px;
+    padding-bottom: 5px;
+    display: flex;
+    align-items: center;
+}
+
+.mx_SearchBar input {
+    display: inline block;
+    border-radius: 3px;
+    border: 1px solid #f0f0f0;
+    font-size: 16px;
+    padding: 9px;
+    padding-left: 11px;
+    margin-right: 17px;
+    width: auto;
+    flex: 1 1 0;
+}
+
+.mx_SearchBar_button {
+    display: inline;
+    border: 0px;
+    border-radius: 36px;
+    font-weight: 400;
+    font-size: 16px;
+    color: #fff;
+    background-color: #76cfa6;
+    width: auto;
+    margin: auto;
+    margin-left: 7px;
+    padding-top: 6px;
+    padding-bottom: 4px;
+    padding-left: 24px;
+    padding-right: 24px;
+    cursor: pointer;
+}
+
+.mx_SearchBar_unselected {
+    background-color: #fff;
+    color: #9fddc1;
+    border: #9fddc1 1px solid;
+} 
+
+.mx_SearchBar_cancel {
+    padding-left: 14px;
+    padding-right: 14px;
+    cursor: pointer;
+}
diff --git a/src/skins/vector/css/molecules/voip/IncomingCallbox.css b/src/skins/vector/css/molecules/voip/IncomingCallbox.css
index 2c57a327..24b24cc2 100644
--- a/src/skins/vector/css/molecules/voip/IncomingCallbox.css
+++ b/src/skins/vector/css/molecules/voip/IncomingCallbox.css
@@ -16,7 +16,7 @@ limitations under the License.
 
 .mx_IncomingCallBox {
     text-align: center;
-    border: 1px solid #a9dbf4;
+    border: 1px solid #a4a4a4;
     border-radius: 8px;
     background-color: #fff;
     position: absolute;
diff --git a/src/skins/vector/css/organisms/CreateRoom.css b/src/skins/vector/css/organisms/CreateRoom.css
index d6b1765c..578c79e6 100644
--- a/src/skins/vector/css/organisms/CreateRoom.css
+++ b/src/skins/vector/css/organisms/CreateRoom.css
@@ -15,7 +15,7 @@ limitations under the License.
 */
 
 .mx_CreateRoom {
-    width: 720px;
+    width: 960px;
     margin-left: auto;
     margin-right: auto;
     color: #4a4a4a;    
diff --git a/src/skins/vector/css/organisms/LeftPanel.css b/src/skins/vector/css/organisms/LeftPanel.css
index 0e7e077e..67f00c35 100644
--- a/src/skins/vector/css/organisms/LeftPanel.css
+++ b/src/skins/vector/css/organisms/LeftPanel.css
@@ -53,17 +53,20 @@ limitations under the License.
     -webkit-order: 3;
     order: 3;
 
-    -webkit-flex: 0 0 170px;
-    flex: 0 0 170px;
-
-    border-top: 1px solid #f3f8fa;
+    -webkit-flex: 0 0 126px;
+    flex: 0 0 126px;
 }
 
 .mx_LeftPanel .mx_BottomLeftMenu .mx_RoomTile {
-    color: #378bb4;
+    color: #454545;
 }
 
 .mx_LeftPanel .mx_BottomLeftMenu .mx_BottomLeftMenu_options {
     margin-top: 12px;
     width: 100%;
+}
+
+.mx_LeftPanel .mx_BottomLeftMenu img {
+    border-radius: 0px;
+    background-color: transparent;
 }
\ No newline at end of file
diff --git a/src/skins/vector/css/organisms/MemberList.css b/src/skins/vector/css/organisms/MemberList.css
index aab0def4..df699e64 100644
--- a/src/skins/vector/css/organisms/MemberList.css
+++ b/src/skins/vector/css/organisms/MemberList.css
@@ -16,8 +16,6 @@ limitations under the License.
 
 .mx_MemberList {
     height: 100%;
-    margin-bottom: 100px;
-    padding: 8px;
 
     -webkit-flex: 1;
     flex: 1;
@@ -39,22 +37,47 @@ limitations under the License.
 }
 
 .mx_MemberList_border {
-    border: 1px solid #a9dbf4;
     overflow-y: auto;
-    border-radius: 8px;
-    background-color: #fff;
 
     order: 1;
     -webkit-flex: 1 1 0;
     flex: 1 1 0px;
 }
 
+.mx_MemberList_invite {
+    font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif;
+    border-radius: 3px;
+    border: 1px solid #f0f0f0;
+    padding: 9px;
+    color: #454545;
+    margin-left: 3px;
+    font-size: 16px;
+    margin-bottom: 8px;
+    width: 180px;
+}
+
+.mx_MemberList_invite::-moz-placeholder {
+    color: #454545;
+    opacity: 0.5;
+}
+.mx_MessageList_invite::-webkit-input-placeholder {
+    color: #454545;
+    opacity: 0.5;
+}
+
+.mx_MemberList_invited h2 {
+    text-transform: uppercase;
+    color: #3d3b39;
+    font-weight: 600;
+    font-size: 14px;
+    padding-left: 3px;
+    padding-right: 12px;
+    margin-top: 8px;
+    margin-bottom: 4px;    
+}
+
 .mx_MemberList_wrapper {
     display: table;
     table-layout: fixed;
     width: 100%;
 }
-
-.mx_MemberList h2 {
-    margin: 14px;
-}
diff --git a/src/skins/vector/css/organisms/RightPanel.css b/src/skins/vector/css/organisms/RightPanel.css
index 30ef4726..bf473a44 100644
--- a/src/skins/vector/css/organisms/RightPanel.css
+++ b/src/skins/vector/css/organisms/RightPanel.css
@@ -33,32 +33,53 @@ limitations under the License.
     -webkit-order: 1;
     order: 1;
 
-    -webkit-flex: 0 0 66px;
-    flex: 0 0 66px;    
+    -webkit-flex: 0 0 83px;
+    flex: 0 0 83px;
 }
 
 /** Fixme - factor this out with the main header **/
 
 .mx_RightPanel_headerButtonGroup {
-    margin-top: 18px;
-    height: 48px;
-    float: right;
+    margin-top: 32px;
+    float: left;
     background-color: #fff;
-    border-radius: 48px;
-    border: 1px solid #a9dbf4;
-    margin-right: 22px;
+    margin-left: -4px;
 }
 
 .mx_RightPanel_headerButton {
     cursor: pointer;
-    height: 48px;
     display: table-cell;
     vertical-align: middle;    
-    padding-left: 8px;
-    padding-right: 8px;
+    padding-left: 15px;
+    padding-right: 15px;
+    position: relative;
 }
 
-.mx_RightPanel .mx_MemberList {
+.mx_RightPanel_headerButton_highlight {
+    position: absolute;
+    bottom: -2px;
+    left: 10px;
+    width: 25px;
+    height: 4px;
+    background-color: #76cfa6;
+}
+
+.mx_RightPanel_headerButton_badge {
+    position: absolute;
+    top: 5px;
+    left: 28px;
+    font-size: 12px;    
+    background-color: #76cfa6;
+    color: #fff;
+    font-weight: bold;
+    border-radius: 20px;
+    padding-left: 4px;
+    padding-right: 4px;
+    padding-top: 2px;
+}
+
+.mx_RightPanel .mx_MemberList,
+.mx_RightPanel .mx_MemberInfo {
     -webkit-box-ordinal-group: 2;
     -moz-box-ordinal-group: 2;
     -ms-flex-order: 2;
diff --git a/src/skins/vector/css/organisms/RoomDirectory.css b/src/skins/vector/css/organisms/RoomDirectory.css
index 21985a25..f53f0556 100644
--- a/src/skins/vector/css/organisms/RoomDirectory.css
+++ b/src/skins/vector/css/organisms/RoomDirectory.css
@@ -15,7 +15,7 @@ limitations under the License.
 */
 
 .mx_RoomDirectory {
-    width: 720px;
+    width: 960px;
     margin-left: auto;
     margin-right: auto;
     margin-bottom: 12px;
diff --git a/src/skins/vector/css/organisms/RoomList.css b/src/skins/vector/css/organisms/RoomList.css
index 21cb7812..34ebd1db 100644
--- a/src/skins/vector/css/organisms/RoomList.css
+++ b/src/skins/vector/css/organisms/RoomList.css
@@ -15,17 +15,30 @@ limitations under the License.
 */
 
 .mx_RoomList {
+    padding-top: 24px;
 }
 
+.mx_RoomList_invites,
 .mx_RoomList_recents {
-    margin-top: -12px;
     display: table;
     table-layout: fixed;
     width: 100%;
 }
 
+.mx_RoomList_expandButton {
+    margin-left: 8px;
+    cursor: pointer;
+    padding-left: 12px;
+    padding-right: 12px;
+}
+
 .mx_RoomList h2 {
-    padding-left: 16px;
-    padding-right: 16px;
-    padding-bottom: 10px;
-}
\ No newline at end of file
+    text-transform: uppercase;
+    color: #3d3b39;
+    font-weight: 600;
+    font-size: 14px;
+    padding-left: 12px;
+    padding-right: 12px;
+    margin-top: 8px;
+    margin-bottom: 4px;
+}
diff --git a/src/skins/vector/css/organisms/RoomView.css b/src/skins/vector/css/organisms/RoomView.css
index 2aab203a..d564b086 100644
--- a/src/skins/vector/css/organisms/RoomView.css
+++ b/src/skins/vector/css/organisms/RoomView.css
@@ -36,13 +36,13 @@ limitations under the License.
     -webkit-order: 1;
     order: 1;
 
-    -webkit-flex: 0 0 88px;
-    flex: 0 0 88px;
+    -webkit-flex: 0 0 83px;
+    flex: 0 0 83px;
 }
 
 .mx_RoomView_fileDropTarget {
     min-width: 0px;
-    max-width: 720px;
+    max-width: 960px;
     width: 100%;
     font-size: 20px;
     text-align: center;
@@ -61,10 +61,10 @@ limitations under the License.
     border-top-right-radius: 10px;
 
     background-color: rgba(255, 255, 255, 0.9);
-    border: 2px dashed #80cef4;
+    border: 2px #e1dddd solid;
     border-bottom: none;
     position: absolute;
-    top: 88px;
+    top: 83px;
     bottom: 0px;
     z-index: 3000;
 }
@@ -84,12 +84,12 @@ limitations under the License.
     order: 2;
 
     min-width: 0px;
-    max-width: 720px;
+    max-width: 960px;
     width: 100%;
     margin: auto;
 
     overflow: auto;
-    border-bottom: 1px solid #a8dbf3;
+    border-bottom: 1px solid #eee;
 
     -webkit-flex: 0 0 auto;
     flex: 0 0 auto;
@@ -111,7 +111,7 @@ limitations under the License.
 }
 
 .mx_RoomView_messageListWrapper {
-    max-width: 720px;
+    max-width: 960px;
     margin: auto;
 }
 
@@ -129,8 +129,9 @@ limitations under the License.
     clear: both;
     margin-top: 32px;
     margin-bottom: 8px;
+    margin-left: 54px;
     padding-bottom: 6px;
-    border-bottom: 1px solid #a8dbf3;
+    border-bottom: 1px solid #eee;
 }
 
 .mx_RoomView_invitePrompt {
@@ -141,7 +142,7 @@ limitations under the License.
     order: 2;
 
     min-width: 0px;
-    max-width: 720px;
+    max-width: 960px;
     width: 100%;
     margin: auto;
 
@@ -157,44 +158,45 @@ limitations under the License.
     order: 4;
 
     width: 100%;
-    -webkit-flex: 0 0 58px;
-    flex: 0 0 58px;
+    -webkit-flex: 0 0 36px;
+    flex: 0 0 36px;
 }
 
 .mx_RoomView_statusAreaBox {
-    max-width: 720px;
+    max-width: 960px;
     margin: auto;
-    border-top: 1px solid #a8dbf3;
+}
+
+.mx_RoomView_statusAreaBox_line {
+    border-top: 1px solid #eee;
+    margin-left: 54px;
+    height: 1px;
 }
 
 .mx_RoomView_unreadMessagesBar {
-    margin-top: 13px;
-    color: #fff;
-    font-weight: bold;
-    background-color: #ff0064;
-    border-radius: 30px;
-    height: 30px;
-    line-height: 30px;
+    color: #ff0064;
     cursor: pointer;
+    margin-top: 5px;
 }
 
 .mx_RoomView_unreadMessagesBar img {
-    padding-left: 22px;
+    padding-left: 10px;
     padding-right: 22px;
+    vertical-align: middle;
 }
 
 .mx_RoomView_typingBar {
-    margin-top: 17px;
-    margin-left: 56px;
-    color: #818794;
+    margin-top: 10px;
+    margin-left: 54px;
+    color: #4a4a4a;
+    opacity: 0.5;
 }
 
-.mx_RoomView_typingBar img {
-    padding-left: 12px;
-    padding-right: 12px;
-    margin-left: -64px;
-    margin-top: -7px;
-    float: left;    
+.mx_RoomView_typingImage {
+    display: inline;
+    margin-left: -38px;
+    margin-top: -4px;
+    float: left;
 }
 
 .mx_RoomView .mx_MessageComposer {
@@ -205,44 +207,46 @@ limitations under the License.
     order: 5;
 
     width: 100%;
-    -webkit-flex: 0 0 63px;
-    flex: 0 0 63px;
+    -webkit-flex: 0 0 70px;
+    flex: 0 0 70px;
     margin-right: 2px;
 }
 
 .mx_RoomView_uploadProgressOuter {
-    width: 100%;
-    background-color: rgba(169, 219, 244, 0.5);
     height: 4px;
+    margin-left: 54px;
+    margin-top: -1px;
 }
 
 .mx_RoomView_uploadProgressInner {
-    background-color: #80cef4;
+    background-color: #76cfa6;
     height: 4px;
 }
 
 .mx_RoomView_uploadFilename {
-    margin-top: 15px;
+    margin-top: 5px;
     margin-left: 56px;
+    opacity: 0.5;
+    color: #4a4a4a;
 }
 
 .mx_RoomView_uploadIcon {
     float: left;
-    margin-top: 6px;
-    margin-left: 5px;
+    margin-top: 1px;
+    margin-left: 14px;
 }
 
 .mx_RoomView_uploadCancel {
     float: right;
-    margin-top: 6px;
+    margin-top: 5px;
     margin-right: 10px;
 }
 
 .mx_RoomView_uploadBytes {
     float: right;    
-    opacity: 0.5;
-    margin-top: 15px;
-    margin-right: 10px;
+    margin-top: 5px;
+    margin-right: 30px;
+    color: #76cfa6;
 }
 
 .mx_RoomView_ongoingConfCallNotification {
@@ -251,5 +255,5 @@ limitations under the License.
     background-color: #ff0064;
     color: #fff;
     font-weight: bold;
-    padding: 6px;
-}
\ No newline at end of file
+    padding: 6px 0;
+}
diff --git a/src/skins/vector/css/organisms/UserSettings.css b/src/skins/vector/css/organisms/UserSettings.css
index b69399b7..2b0aca3d 100644
--- a/src/skins/vector/css/organisms/UserSettings.css
+++ b/src/skins/vector/css/organisms/UserSettings.css
@@ -15,7 +15,7 @@ limitations under the License.
 */
 
 .mx_UserSettings {
-    width: 720px;
+    width: 960px;
     margin-left: auto;
     margin-right: auto;
 }
diff --git a/src/skins/vector/css/organisms/ViewSource.css b/src/skins/vector/css/organisms/ViewSource.css
index ae61ae58..f932c9a4 100644
--- a/src/skins/vector/css/organisms/ViewSource.css
+++ b/src/skins/vector/css/organisms/ViewSource.css
@@ -1,3 +1,22 @@
+/*
+Copyright 2015 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_ViewSource pre {
     text-align: left;
+    font-size: 12px;
+    padding: 0.5em 1em 0.5em 1em;
+    word-wrap: break-word;
 }
diff --git a/src/skins/vector/css/pages/MatrixChat.css b/src/skins/vector/css/pages/MatrixChat.css
index 6fa0415a..f649aa24 100644
--- a/src/skins/vector/css/pages/MatrixChat.css
+++ b/src/skins/vector/css/pages/MatrixChat.css
@@ -69,6 +69,8 @@ limitations under the License.
     -webkit-order: 1;
     order: 1;
 
+    background-color: #eaf5f0;
+
     -webkit-flex: 0 0 230px;
     flex: 0 0 230px;
 }
@@ -87,7 +89,7 @@ limitations under the License.
 
     padding-left: 12px;
     padding-right: 12px;
-    background-color: #f3f8fa;
+    background-color: #fff;
 
     -webkit-flex: 1;
     flex: 1;
@@ -114,7 +116,6 @@ limitations under the License.
     -webkit-order: 3;
     order: 3;
 
-    background-color: #f3f8fa;
     -webkit-flex: 0 0 230px;
     flex: 0 0 230px;
 }
diff --git a/src/skins/vector/fonts/MyriadPro-Bold.woff b/src/skins/vector/fonts/MyriadPro-Bold.woff
new file mode 100644
index 00000000..f30c591f
Binary files /dev/null and b/src/skins/vector/fonts/MyriadPro-Bold.woff differ
diff --git a/src/skins/vector/fonts/MyriadPro-BoldIt.woff b/src/skins/vector/fonts/MyriadPro-BoldIt.woff
new file mode 100644
index 00000000..db605a6c
Binary files /dev/null and b/src/skins/vector/fonts/MyriadPro-BoldIt.woff differ
diff --git a/src/skins/vector/fonts/MyriadPro-It.woff b/src/skins/vector/fonts/MyriadPro-It.woff
new file mode 100644
index 00000000..9a133bcd
Binary files /dev/null and b/src/skins/vector/fonts/MyriadPro-It.woff differ
diff --git a/src/skins/vector/fonts/MyriadPro-Regular.woff b/src/skins/vector/fonts/MyriadPro-Regular.woff
new file mode 100644
index 00000000..5a95583f
Binary files /dev/null and b/src/skins/vector/fonts/MyriadPro-Regular.woff differ
diff --git a/src/skins/vector/fonts/MyriadPro-SemiBold.woff b/src/skins/vector/fonts/MyriadPro-SemiBold.woff
new file mode 100644
index 00000000..2a80f65d
Binary files /dev/null and b/src/skins/vector/fonts/MyriadPro-SemiBold.woff differ
diff --git a/src/skins/vector/fonts/MyriadPro.css b/src/skins/vector/fonts/MyriadPro.css
new file mode 100644
index 00000000..833e6828
--- /dev/null
+++ b/src/skins/vector/fonts/MyriadPro.css
@@ -0,0 +1,20 @@
+@font-face {
+  font-family: 'Myriad Pro';
+  font-style: normal;
+  font-weight: normal;
+  src: local('Myriad Pro'), local('MyriadPro'), url(MyriadPro-Regular.woff) format('woff');
+}
+
+@font-face {
+  font-family: 'Myriad Pro';
+  font-style: normal;
+  font-weight: 600;
+  src: local('Myriad Pro SemiBold'), local('MyriadPro-SemiBold'), url(MyriadPro-SemiBold.woff) format('woff');
+}
+
+@font-face {
+  font-family: 'Myriad Pro';
+  font-style: normal;
+  font-weight: bold;
+  src: local('Myriad Pro Bold'), local('MyriadPro-Bold'), url(MyriadPro-Bold.woff) format('woff');
+}
diff --git a/src/skins/vector/img/76cfa6.png b/src/skins/vector/img/76cfa6.png
new file mode 100644
index 00000000..de1ea60d
Binary files /dev/null and b/src/skins/vector/img/76cfa6.png differ
diff --git a/src/skins/vector/img/call.png b/src/skins/vector/img/call.png
new file mode 100644
index 00000000..a7805e05
Binary files /dev/null and b/src/skins/vector/img/call.png differ
diff --git a/src/skins/vector/img/cancel-black.png b/src/skins/vector/img/cancel-black.png
new file mode 100644
index 00000000..87dcfd41
Binary files /dev/null and b/src/skins/vector/img/cancel-black.png differ
diff --git a/src/skins/vector/img/cancel.png b/src/skins/vector/img/cancel.png
index c963a4b7..2bda8ff5 100644
Binary files a/src/skins/vector/img/cancel.png and b/src/skins/vector/img/cancel.png differ
diff --git a/src/skins/vector/img/chevron-left.png b/src/skins/vector/img/chevron-left.png
index 12abcc26..efb0065d 100644
Binary files a/src/skins/vector/img/chevron-left.png and b/src/skins/vector/img/chevron-left.png differ
diff --git a/src/skins/vector/img/chevron-right.png b/src/skins/vector/img/chevron-right.png
index 1fe5d347..18a4684e 100644
Binary files a/src/skins/vector/img/chevron-right.png and b/src/skins/vector/img/chevron-right.png differ
diff --git a/src/skins/vector/img/chevron.png b/src/skins/vector/img/chevron.png
index 3df8655b..81236f91 100644
Binary files a/src/skins/vector/img/chevron.png and b/src/skins/vector/img/chevron.png differ
diff --git a/src/skins/vector/img/create-big.png b/src/skins/vector/img/create-big.png
index 247b0030..b7307a11 100644
Binary files a/src/skins/vector/img/create-big.png and b/src/skins/vector/img/create-big.png differ
diff --git a/src/skins/vector/img/directory-big.png b/src/skins/vector/img/directory-big.png
index bbcb16a4..03cab69c 100644
Binary files a/src/skins/vector/img/directory-big.png and b/src/skins/vector/img/directory-big.png differ
diff --git a/src/skins/vector/img/edit.png b/src/skins/vector/img/edit.png
index 2686885f..6f373d3f 100644
Binary files a/src/skins/vector/img/edit.png and b/src/skins/vector/img/edit.png differ
diff --git a/src/skins/vector/img/fileicon.png b/src/skins/vector/img/fileicon.png
index be277a1c..af018efa 100644
Binary files a/src/skins/vector/img/fileicon.png and b/src/skins/vector/img/fileicon.png differ
diff --git a/src/skins/vector/img/files.png b/src/skins/vector/img/files.png
new file mode 100644
index 00000000..83932267
Binary files /dev/null and b/src/skins/vector/img/files.png differ
diff --git a/src/skins/vector/img/member_chevron.png b/src/skins/vector/img/member_chevron.png
new file mode 100644
index 00000000..cbbd289d
Binary files /dev/null and b/src/skins/vector/img/member_chevron.png differ
diff --git a/src/skins/vector/img/members.png b/src/skins/vector/img/members.png
index 6526f236..b5e58757 100644
Binary files a/src/skins/vector/img/members.png and b/src/skins/vector/img/members.png differ
diff --git a/src/skins/vector/img/newmessages.png b/src/skins/vector/img/newmessages.png
index e6dbeb17..a22156ab 100644
Binary files a/src/skins/vector/img/newmessages.png and b/src/skins/vector/img/newmessages.png differ
diff --git a/src/skins/vector/img/search.png b/src/skins/vector/img/search.png
index d2c99855..2f98d290 100644
Binary files a/src/skins/vector/img/search.png and b/src/skins/vector/img/search.png differ
diff --git a/src/skins/vector/img/selected.png b/src/skins/vector/img/selected.png
new file mode 100644
index 00000000..8931cba7
Binary files /dev/null and b/src/skins/vector/img/selected.png differ
diff --git a/src/skins/vector/img/settings-big.png b/src/skins/vector/img/settings-big.png
index 3be13bc7..cb2e0a62 100644
Binary files a/src/skins/vector/img/settings-big.png and b/src/skins/vector/img/settings-big.png differ
diff --git a/src/skins/vector/img/settings.png b/src/skins/vector/img/settings.png
index 445a3909..264b3c9b 100644
Binary files a/src/skins/vector/img/settings.png and b/src/skins/vector/img/settings.png differ
diff --git a/src/skins/vector/img/trans.png b/src/skins/vector/img/trans.png
new file mode 100644
index 00000000..8ba2310a
Binary files /dev/null and b/src/skins/vector/img/trans.png differ
diff --git a/src/skins/vector/img/upload-big.png b/src/skins/vector/img/upload-big.png
index 7754f587..c11c0c45 100644
Binary files a/src/skins/vector/img/upload-big.png and b/src/skins/vector/img/upload-big.png differ
diff --git a/src/skins/vector/img/upload.png b/src/skins/vector/img/upload.png
index 428501f0..7457bcd0 100644
Binary files a/src/skins/vector/img/upload.png and b/src/skins/vector/img/upload.png differ
diff --git a/src/skins/vector/skindex.js b/src/skins/vector/skindex.js
index 8dba10cf..e715656c 100644
--- a/src/skins/vector/skindex.js
+++ b/src/skins/vector/skindex.js
@@ -23,9 +23,6 @@ limitations under the License.
 
 var skin = {};
 
-skin['atoms.create_room.CreateRoomButton'] = require('./views/atoms/create_room/CreateRoomButton');
-skin['atoms.create_room.Presets'] = require('./views/atoms/create_room/Presets');
-skin['atoms.create_room.RoomAlias'] = require('./views/atoms/create_room/RoomAlias');
 skin['atoms.EditableText'] = require('./views/atoms/EditableText');
 skin['atoms.EnableNotificationsButton'] = require('./views/atoms/EnableNotificationsButton');
 skin['atoms.ImageView'] = require('./views/atoms/ImageView');
@@ -33,6 +30,9 @@ skin['atoms.LogoutButton'] = require('./views/atoms/LogoutButton');
 skin['atoms.MemberAvatar'] = require('./views/atoms/MemberAvatar');
 skin['atoms.MessageTimestamp'] = require('./views/atoms/MessageTimestamp');
 skin['atoms.RoomAvatar'] = require('./views/atoms/RoomAvatar');
+skin['atoms.create_room.CreateRoomButton'] = require('./views/atoms/create_room/CreateRoomButton');
+skin['atoms.create_room.Presets'] = require('./views/atoms/create_room/Presets');
+skin['atoms.create_room.RoomAlias'] = require('./views/atoms/create_room/RoomAlias');
 skin['atoms.voip.VideoFeed'] = require('./views/atoms/voip/VideoFeed');
 skin['molecules.BottomLeftMenu'] = require('./views/molecules/BottomLeftMenu');
 skin['molecules.BottomLeftMenuTile'] = require('./views/molecules/BottomLeftMenuTile');
@@ -42,18 +42,18 @@ skin['molecules.ChangePassword'] = require('./views/molecules/ChangePassword');
 skin['molecules.DateSeparator'] = require('./views/molecules/DateSeparator');
 skin['molecules.EventAsTextTile'] = require('./views/molecules/EventAsTextTile');
 skin['molecules.EventTile'] = require('./views/molecules/EventTile');
-skin['molecules.MatrixToolbar'] = require('./views/molecules/MatrixToolbar');
-skin['molecules.MemberInfo'] = require('./views/molecules/MemberInfo');
-skin['molecules.MemberTile'] = require('./views/molecules/MemberTile');
 skin['molecules.MEmoteTile'] = require('./views/molecules/MEmoteTile');
-skin['molecules.MessageComposer'] = require('./views/molecules/MessageComposer');
-skin['molecules.MessageContextMenu'] = require('./views/molecules/MessageContextMenu');
-skin['molecules.MessageTile'] = require('./views/molecules/MessageTile');
 skin['molecules.MFileTile'] = require('./views/molecules/MFileTile');
 skin['molecules.MImageTile'] = require('./views/molecules/MImageTile');
 skin['molecules.MNoticeTile'] = require('./views/molecules/MNoticeTile');
 skin['molecules.MRoomMemberTile'] = require('./views/molecules/MRoomMemberTile');
 skin['molecules.MTextTile'] = require('./views/molecules/MTextTile');
+skin['molecules.MatrixToolbar'] = require('./views/molecules/MatrixToolbar');
+skin['molecules.MemberInfo'] = require('./views/molecules/MemberInfo');
+skin['molecules.MemberTile'] = require('./views/molecules/MemberTile');
+skin['molecules.MessageComposer'] = require('./views/molecules/MessageComposer');
+skin['molecules.MessageContextMenu'] = require('./views/molecules/MessageContextMenu');
+skin['molecules.MessageTile'] = require('./views/molecules/MessageTile');
 skin['molecules.ProgressBar'] = require('./views/molecules/ProgressBar');
 skin['molecules.RoomCreate'] = require('./views/molecules/RoomCreate');
 skin['molecules.RoomDropTarget'] = require('./views/molecules/RoomDropTarget');
@@ -61,6 +61,7 @@ skin['molecules.RoomHeader'] = require('./views/molecules/RoomHeader');
 skin['molecules.RoomSettings'] = require('./views/molecules/RoomSettings');
 skin['molecules.RoomTile'] = require('./views/molecules/RoomTile');
 skin['molecules.RoomTooltip'] = require('./views/molecules/RoomTooltip');
+skin['molecules.SearchBar'] = require('./views/molecules/SearchBar');
 skin['molecules.SenderProfile'] = require('./views/molecules/SenderProfile');
 skin['molecules.ServerConfig'] = require('./views/molecules/ServerConfig');
 skin['molecules.UnknownMessageTile'] = require('./views/molecules/UnknownMessageTile');
diff --git a/src/skins/vector/views/atoms/ImageView.js b/src/skins/vector/views/atoms/ImageView.js
index 676348c0..a842f7c8 100644
--- a/src/skins/vector/views/atoms/ImageView.js
+++ b/src/skins/vector/views/atoms/ImageView.js
@@ -18,10 +18,19 @@ limitations under the License.
 
 var React = require('react');
 
+var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
+
+var DateUtils = require('../../../../DateUtils');
+var filesize = require('filesize');
+
 module.exports = React.createClass({
     displayName: 'ImageView',
 
-    // XXX: keyboard shortcuts for managing dialogs should be done by the modal dialog base class omehow, surely...
+    propTypes: {
+        onFinished: React.PropTypes.func.isRequired
+    },
+
+    // XXX: keyboard shortcuts for managing dialogs should be done by the modal dialog base class somehow, surely...
     componentDidMount: function() {
         document.addEventListener("keydown", this.onKeyDown);
     },
@@ -38,10 +47,29 @@ module.exports = React.createClass({
         }
     },
 
+    onRedactClick: function() {
+        var self = this;
+        MatrixClientPeg.get().redactEvent(
+            this.props.mxEvent.getRoomId(), this.props.mxEvent.getId()
+        ).done(function() {
+            if (self.props.onFinished) self.props.onFinished();
+        }, function(e) {
+            var ErrorDialog = sdk.getComponent("organisms.ErrorDialog");
+            // display error message stating you couldn't delete this.
+            var code = e.errcode || e.statusCode;
+            Modal.createDialog(ErrorDialog, {
+                title: "Error",
+                description: "You cannot delete this image. (" + code + ")"
+            });
+        });
+    },
+
     render: function() {
 
-        // XXX: can't we just do max-width: 80%, max-height: 80% on the CSS?
-        
+/*
+        // In theory max-width: 80%, max-height: 80% on the CSS should work
+        // but in practice, it doesn't, so do it manually:
+
         var width = this.props.width || 500;
         var height = this.props.height || 500;
 
@@ -65,9 +93,55 @@ module.exports = React.createClass({
             width: displayWidth,
             height: displayHeight
         };
+*/
+        var style, res;
+
+        if (this.props.width && this.props.height) {
+            style = {
+                width: this.props.width,
+                height: this.props.height,
+            };
+            res = ", " + style.width + "x" + style.height + "px";
+        }
 
         return (
-            <img className="mx_ImageView" src={this.props.src} style={style} />
+            <div className="mx_ImageView">
+                <div className="mx_ImageView_lhs">
+                </div>
+                <div className="mx_ImageView_content">
+                    <img src={this.props.src} style={style}/>
+                    <div className="mx_ImageView_labelWrapper">
+                        <div className="mx_ImageView_label">
+                            <div className="mx_ImageView_shim">
+                            </div>
+                            <div className="mx_ImageView_name">
+                                { this.props.mxEvent.getContent().body }
+                            </div>
+                            <div className="mx_ImageView_metadata">
+                                Uploaded on { DateUtils.formatDate(new Date(this.props.mxEvent.getTs())) } by { this.props.mxEvent.getSender() }
+                            </div>
+                            <a className="mx_ImageView_link" href={ this.props.src } target="_blank">
+                                <div className="mx_ImageView_download">
+                                        Download this file<br/>
+                                        <span className="mx_ImageView_size">({ filesize(this.props.mxEvent.getContent().info.size) }{ res })</span>
+                                </div>
+                            </a>
+                            <div className="mx_ImageView_button">
+                                <a className="mx_ImageView_link" href={ this.props.src } target="_blank">
+                                    View full screen
+                                </a>
+                            </div>
+                            <div className="mx_ImageView_button" onClick={this.onRedactClick}>
+                                Redact
+                            </div>
+                            <div className="mx_ImageView_shim">
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div className="mx_ImageView_rhs">
+                </div>
+            </div>
         );
     }
 });
diff --git a/src/skins/vector/views/atoms/MessageTimestamp.js b/src/skins/vector/views/atoms/MessageTimestamp.js
index 98cfe4a1..5795e556 100644
--- a/src/skins/vector/views/atoms/MessageTimestamp.js
+++ b/src/skins/vector/views/atoms/MessageTimestamp.js
@@ -17,40 +17,16 @@ limitations under the License.
 'use strict';
 
 var React = require('react');
-
-var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
-var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+var DateUtils = require('../../../../DateUtils');
 
 module.exports = React.createClass({
     displayName: 'MessageTimestamp',
 
-    formatDate: function(date) {
-        // date.toLocaleTimeString is completely system dependent.
-        // just go 24h for now
-        function pad(n) {
-            return (n < 10 ? '0' : '') + n;
-        }
-
-        var now = new Date();
-        if (date.toDateString() === now.toDateString()) {
-            return pad(date.getHours()) + ':' + pad(date.getMinutes());
-        }
-        else if (now.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
-            return days[date.getDay()] + " " + pad(date.getHours()) + ':' + pad(date.getMinutes());
-        }
-        else if (now.getFullYear() === date.getFullYear()) {
-            return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + pad(date.getHours()) + ':' + pad(date.getMinutes());
-        }
-        else {
-            return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + date.getFullYear() + " " + pad(date.getHours()) + ':' + pad(date.getMinutes());
-        }
-    },
-
     render: function() {
         var date = new Date(this.props.ts);
         return (
             <span className="mx_MessageTimestamp">
-                { this.formatDate(date) }
+                { DateUtils.formatDate(date) }
             </span>
         );
     },
diff --git a/src/skins/vector/views/atoms/RoomAvatar.js b/src/skins/vector/views/atoms/RoomAvatar.js
index 3b5d4634..a1d87f7f 100644
--- a/src/skins/vector/views/atoms/RoomAvatar.js
+++ b/src/skins/vector/views/atoms/RoomAvatar.js
@@ -33,7 +33,7 @@ module.exports = React.createClass({
     },
 
     getFallbackAvatar: function() {
-        var images = [ '80cef4', '50e2c2', 'f4c371' ];
+        var images = [ '76cfa6', '50e2c2', 'f4c371' ];
         var total = 0;
         for (var i = 0; i < this.props.room.roomId.length; ++i) {
             total += this.props.room.roomId.charCodeAt(i);
diff --git a/src/skins/vector/views/molecules/BottomLeftMenuTile.js b/src/skins/vector/views/molecules/BottomLeftMenuTile.js
index 2644769c..8c28058d 100644
--- a/src/skins/vector/views/molecules/BottomLeftMenuTile.js
+++ b/src/skins/vector/views/molecules/BottomLeftMenuTile.js
@@ -48,7 +48,7 @@ module.exports = React.createClass({
         return (
             <div className="mx_RoomTile" onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onClick={this.props.onClick}>
                 <div className="mx_RoomTile_avatar">
-                    <img src={ this.props.img } width="36" height="36"/>
+                    <img src={ this.props.img } width="24" height="24"/>
                 </div>
                 { label }
             </div>
diff --git a/src/skins/vector/views/molecules/EventTile.js b/src/skins/vector/views/molecules/EventTile.js
index b92ab18b..6c2f948c 100644
--- a/src/skins/vector/views/molecules/EventTile.js
+++ b/src/skins/vector/views/molecules/EventTile.js
@@ -30,6 +30,7 @@ var eventTileTypes = {
     'm.call.invite' : 'molecules.EventAsTextTile',
     'm.call.answer' : 'molecules.EventAsTextTile',
     'm.call.hangup' : 'molecules.EventAsTextTile',
+    'm.room.name'   : 'molecules.EventAsTextTile',
     'm.room.topic'  : 'molecules.EventAsTextTile',
 };
 
@@ -88,12 +89,13 @@ module.exports = React.createClass({
             mx_EventTile_highlight: this.shouldHighlight(),
             mx_EventTile_continuation: this.props.continuation,
             mx_EventTile_last: this.props.last,
-            menu: this.state.menu
+            mx_EventTile_contextual: this.props.contextual,
+            menu: this.state.menu,
         });
         var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} />
         var editButton = (
             <input
-                type="image" src="img/edit.png" alt="Edit"
+                type="image" src="img/edit.png" alt="Edit" width="14" height="14"
                 className="mx_EventTile_editButton" onClick={this.onEditClicked}
             />
         );
@@ -108,7 +110,7 @@ module.exports = React.createClass({
             if (this.props.mxEvent.sender) {
                 avatar = (
                     <div className="mx_EventTile_avatar">
-                        <MemberAvatar member={this.props.mxEvent.sender} />
+                        <MemberAvatar member={this.props.mxEvent.sender} width={24} height={24} />
                     </div>
                 );
             }
@@ -120,10 +122,10 @@ module.exports = React.createClass({
             <div className={classes}>
                 { avatar }
                 { sender }
-                <div>
+                <div className="mx_EventTile_line">
                     { timestamp }
                     { editButton }
-                    <EventTileType mxEvent={this.props.mxEvent} />
+                    <EventTileType mxEvent={this.props.mxEvent} searchTerm={this.props.searchTerm} />
                 </div>
             </div>
         );
diff --git a/src/skins/vector/views/molecules/MImageTile.js b/src/skins/vector/views/molecules/MImageTile.js
index ed61a390..0667dabd 100644
--- a/src/skins/vector/views/molecules/MImageTile.js
+++ b/src/skins/vector/views/molecules/MImageTile.js
@@ -57,8 +57,9 @@ module.exports = React.createClass({
             Modal.createDialog(ImageView, {
                 src: httpUrl,
                 width: content.info.w,
-                height: content.info.h
-            });
+                height: content.info.h,
+                mxEvent: this.props.mxEvent,
+            }, "mx_Dialog_lightbox");
         }
     },
 
@@ -67,7 +68,7 @@ module.exports = React.createClass({
         var cli = MatrixClientPeg.get();
 
         var thumbHeight = null;
-        if (content.info) thumbHeight = this.thumbHeight(content.info.w, content.info.h, 320, 240);
+        if (content.info) thumbHeight = this.thumbHeight(content.info.w, content.info.h, 480, 360);
 
         var imgStyle = {};
         if (thumbHeight) imgStyle['height'] = thumbHeight;
@@ -75,7 +76,7 @@ module.exports = React.createClass({
         return (
             <span className="mx_MImageTile">
                 <a href={cli.mxcUrlToHttp(content.url)} onClick={ this.onClick }>
-                    <img className="mx_MImageTile_thumbnail" src={cli.mxcUrlToHttp(content.url, 320, 240)} alt={content.body} style={imgStyle} />
+                    <img className="mx_MImageTile_thumbnail" src={cli.mxcUrlToHttp(content.url, 480, 360)} alt={content.body} style={imgStyle} />
                 </a>
                 <div className="mx_MImageTile_download">
                     <a href={cli.mxcUrlToHttp(content.url)} target="_blank">
diff --git a/src/skins/vector/views/molecules/MNoticeTile.js b/src/skins/vector/views/molecules/MNoticeTile.js
index aa886127..a0cedb1d 100644
--- a/src/skins/vector/views/molecules/MNoticeTile.js
+++ b/src/skins/vector/views/molecules/MNoticeTile.js
@@ -17,18 +17,71 @@ limitations under the License.
 'use strict';
 
 var React = require('react');
+var sanitizeHtml = require('sanitize-html');
 
 var MNoticeTileController = require('matrix-react-sdk/lib/controllers/molecules/MNoticeTile')
 
+var allowedAttributes = sanitizeHtml.defaults.allowedAttributes;
+allowedAttributes['font'] = ['color'];
+var sanitizeHtmlParams = {
+    allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'font' ]),
+    allowedAttributes: allowedAttributes,
+};
+
 module.exports = React.createClass({
     displayName: 'MNoticeTile',
     mixins: [MNoticeTileController],
 
+    // FIXME: this entire class is copy-pasted from MTextTile :(        
     render: function() {
         var content = this.props.mxEvent.getContent();
+        var originalBody = content.body;
+        var body;
+
+        if (this.props.searchTerm) {
+            var lastOffset = 0;
+            var bodyList = [];
+            var k = 0;
+            var offset;
+
+            // XXX: rather than searching for the search term in the body,
+            // we should be looking at the match delimiters returned by the FTS engine
+            if (content.format === "org.matrix.custom.html") {
+                var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
+                var safeSearchTerm = sanitizeHtml(this.props.searchTerm, sanitizeHtmlParams);
+                while ((offset = safeBody.indexOf(safeSearchTerm, lastOffset)) >= 0) {
+                    // FIXME: we need to apply the search highlighting to only the text elements of HTML, which means
+                    // hooking into the sanitizer parser rather than treating it as a string.  Otherwise
+                    // the act of highlighting a <b/> or whatever will break the HTML badly.
+                    bodyList.push(<span key={ k++ } dangerouslySetInnerHTML={{ __html: safeBody.substring(lastOffset, offset) }} />);
+                    bodyList.push(<span key={ k++ } dangerouslySetInnerHTML={{ __html: safeSearchTerm }} className="mx_MessageTile_searchHighlight" />);
+                    lastOffset = offset + safeSearchTerm.length;
+                }
+                bodyList.push(<span key={ k++ } dangerouslySetInnerHTML={{ __html: safeBody.substring(lastOffset) }} />);
+            }
+            else {
+                while ((offset = originalBody.indexOf(this.props.searchTerm, lastOffset)) >= 0) {
+                    bodyList.push(<span key={ k++ } >{ originalBody.substring(lastOffset, offset) }</span>);
+                    bodyList.push(<span key={ k++ } className="mx_MessageTile_searchHighlight">{ this.props.searchTerm }</span>);
+                    lastOffset = offset + this.props.searchTerm.length;
+                }
+                bodyList.push(<span key={ k++ }>{ originalBody.substring(lastOffset) }</span>);
+            }
+            body = bodyList;
+        }
+        else {
+            if (content.format === "org.matrix.custom.html") {
+                var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
+                body = <span dangerouslySetInnerHTML={{ __html: safeBody }} />;
+            }
+            else {
+                body = originalBody;
+            }
+        }
+
         return (
             <span ref="content" className="mx_MNoticeTile mx_MessageTile_content">
-                {content.body}
+                { body }
             </span>
         );
     },
diff --git a/src/skins/vector/views/molecules/MTextTile.js b/src/skins/vector/views/molecules/MTextTile.js
index 50555f94..12bafa37 100644
--- a/src/skins/vector/views/molecules/MTextTile.js
+++ b/src/skins/vector/views/molecules/MTextTile.js
@@ -17,18 +17,71 @@ limitations under the License.
 'use strict';
 
 var React = require('react');
+var sanitizeHtml = require('sanitize-html');
 
 var MTextTileController = require('matrix-react-sdk/lib/controllers/molecules/MTextTile')
 
+var allowedAttributes = sanitizeHtml.defaults.allowedAttributes;
+allowedAttributes['font'] = ['color'];
+var sanitizeHtmlParams = {
+    allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'font' ]),
+    allowedAttributes: allowedAttributes,
+};
+
 module.exports = React.createClass({
     displayName: 'MTextTile',
     mixins: [MTextTileController],
 
+    // FIXME: this entire class is copy-pasted from MTextTile :(        
     render: function() {
         var content = this.props.mxEvent.getContent();
+        var originalBody = content.body;
+        var body;
+
+        if (this.props.searchTerm) {
+            var lastOffset = 0;
+            var bodyList = [];
+            var k = 0;
+            var offset;
+
+            // XXX: rather than searching for the search term in the body,
+            // we should be looking at the match delimiters returned by the FTS engine
+            if (content.format === "org.matrix.custom.html") {
+                var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
+                var safeSearchTerm = sanitizeHtml(this.props.searchTerm, sanitizeHtmlParams);
+                while ((offset = safeBody.indexOf(safeSearchTerm, lastOffset)) >= 0) {
+                    // FIXME: we need to apply the search highlighting to only the text elements of HTML, which means
+                    // hooking into the sanitizer parser rather than treating it as a string.  Otherwise
+                    // the act of highlighting a <b/> or whatever will break the HTML badly.
+                    bodyList.push(<span key={ k++ } dangerouslySetInnerHTML={{ __html: safeBody.substring(lastOffset, offset) }} />);
+                    bodyList.push(<span key={ k++ } dangerouslySetInnerHTML={{ __html: safeSearchTerm }} className="mx_MessageTile_searchHighlight" />);
+                    lastOffset = offset + safeSearchTerm.length;
+                }
+                bodyList.push(<span key={ k++ } dangerouslySetInnerHTML={{ __html: safeBody.substring(lastOffset) }} />);
+            }
+            else {
+                while ((offset = originalBody.indexOf(this.props.searchTerm, lastOffset)) >= 0) {
+                    bodyList.push(<span key={ k++ } >{ originalBody.substring(lastOffset, offset) }</span>);
+                    bodyList.push(<span key={ k++ } className="mx_MessageTile_searchHighlight">{ this.props.searchTerm }</span>);
+                    lastOffset = offset + this.props.searchTerm.length;
+                }
+                bodyList.push(<span key={ k++ }>{ originalBody.substring(lastOffset) }</span>);
+            }
+            body = bodyList;
+        }
+        else {
+            if (content.format === "org.matrix.custom.html") {
+                var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
+                body = <span dangerouslySetInnerHTML={{ __html: safeBody }} />;
+            }
+            else {
+                body = originalBody;
+            }
+        }
+
         return (
             <span ref="content" className="mx_MTextTile mx_MessageTile_content">
-                {content.body}
+                { body }
             </span>
         );
     },
diff --git a/src/skins/vector/views/molecules/MemberInfo.js b/src/skins/vector/views/molecules/MemberInfo.js
index a2a3874a..5f8e806d 100644
--- a/src/skins/vector/views/molecules/MemberInfo.js
+++ b/src/skins/vector/views/molecules/MemberInfo.js
@@ -20,19 +20,30 @@ var React = require('react');
 var Loader = require("../atoms/Spinner");
 
 var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
+var sdk = require('matrix-react-sdk')
+var dis = require('matrix-react-sdk/lib/dispatcher');
 var MemberInfoController = require('matrix-react-sdk/lib/controllers/molecules/MemberInfo')
 
+// FIXME: this should probably be an organism, to match with MemberList, not a molecule
+
 module.exports = React.createClass({
     displayName: 'MemberInfo',
     mixins: [MemberInfoController],
 
+    onCancel: function(e) {
+        dis.dispatch({
+            action: "view_user",
+            member: null
+        });
+    },
+
     render: function() {
         var interactButton, kickButton, banButton, muteButton, giveModButton, spinner;
         if (this.props.member.userId === MatrixClientPeg.get().credentials.userId) {
-            interactButton = <div className="mx_ContextualMenu_field" onClick={this.onLeaveClick}>Leave room</div>;
+            interactButton = <div className="mx_MemberInfo_field" onClick={this.onLeaveClick}>Leave room</div>;
         }
         else {
-            interactButton = <div className="mx_ContextualMenu_field" onClick={this.onChatClick}>Start chat</div>;
+            interactButton = <div className="mx_MemberInfo_field" onClick={this.onChatClick}>Start chat</div>;
         }
 
         if (this.state.creatingRoom) {
@@ -40,36 +51,50 @@ module.exports = React.createClass({
         }
 
         if (this.state.can.kick) {
-            kickButton = <div className="mx_ContextualMenu_field" onClick={this.onKick}>
+            kickButton = <div className="mx_MemberInfo_field" onClick={this.onKick}>
                 Kick
             </div>;
         }
         if (this.state.can.ban) {
-            banButton = <div className="mx_ContextualMenu_field" onClick={this.onBan}>
+            banButton = <div className="mx_MemberInfo_field" onClick={this.onBan}>
                 Ban
             </div>;
         }
         if (this.state.can.mute) {
             var muteLabel = this.state.muted ? "Unmute" : "Mute";
-            muteButton = <div className="mx_ContextualMenu_field" onClick={this.onMuteToggle}>
+            muteButton = <div className="mx_MemberInfo_field" onClick={this.onMuteToggle}>
                 {muteLabel}
             </div>;
         }
         if (this.state.can.modifyLevel) {
             var giveOpLabel = this.state.isTargetMod ? "Revoke Mod" : "Make Mod";
-            giveModButton = <div className="mx_ContextualMenu_field" onClick={this.onModToggle}>
+            giveModButton = <div className="mx_MemberInfo_field" onClick={this.onModToggle}>
                 {giveOpLabel}
             </div>
         }
 
+        var MemberAvatar = sdk.getComponent('atoms.MemberAvatar');
         return (
-            <div>
-                {interactButton}
-                {muteButton}
-                {kickButton}
-                {banButton}
-                {giveModButton}
-                {spinner}
+            <div className="mx_MemberInfo">
+                <img className="mx_MemberInfo_cancel" src="img/cancel-black.png" width="18" height="18" onClick={this.onCancel}/>
+                <div className="mx_MemberInfo_avatar">
+                    <MemberAvatar member={this.props.member} width={48} height={48} />
+                </div>
+                <h2>{ this.props.member.name }</h2>
+                <div className="mx_MemberInfo_profileField">
+                    { this.props.member.userId }
+                </div>
+                <div className="mx_MemberInfo_profileField">
+                    power: { this.props.member.powerLevelNorm }%
+                </div>
+                <div className="mx_MemberInfo_buttons">
+                    {interactButton}
+                    {muteButton}
+                    {kickButton}
+                    {banButton}
+                    {giveModButton}
+                    {spinner}
+                </div>
             </div>
         );
     }
diff --git a/src/skins/vector/views/molecules/MemberTile.js b/src/skins/vector/views/molecules/MemberTile.js
index 4c34fcb7..25ba3db9 100644
--- a/src/skins/vector/views/molecules/MemberTile.js
+++ b/src/skins/vector/views/molecules/MemberTile.js
@@ -20,7 +20,7 @@ var React = require('react');
 
 var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
 var sdk = require('matrix-react-sdk')
-var ContextualMenu = require('../../../../ContextualMenu');
+var dis = require('matrix-react-sdk/lib/dispatcher');
 var MemberTileController = require('matrix-react-sdk/lib/controllers/molecules/MemberTile')
 
 // The Lato WOFF doesn't include sensible combining diacritics, so Chrome chokes on rendering them.
@@ -58,16 +58,9 @@ module.exports = React.createClass({
     },
 
     onClick: function(e) {
-        var self = this;
-        self.setState({ 'menu': true });
-        var MemberInfo = sdk.getComponent('molecules.MemberInfo');
-        ContextualMenu.createMenu(MemberInfo, {
-            member: self.props.member,
-            right: window.innerWidth - e.pageX,
-            top: e.pageY,
-            onFinished: function() {
-                self.setState({ 'menu': false });
-            }
+        dis.dispatch({
+            action: 'view_user',
+            member: this.props.member,
         });
     },
 
@@ -119,10 +112,10 @@ module.exports = React.createClass({
         var isMyUser = MatrixClientPeg.get().credentials.userId == this.props.member.userId;
 
         var power;
-        if (this.props.member && this.props.member.powerLevelNorm > 0) {
-            var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png";
-            power = <img src={ img } className="mx_MemberTile_power" width="48" height="48" alt=""/>;
-        }
+        // if (this.props.member && this.props.member.powerLevelNorm > 0) {
+        //     var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png";
+        //     power = <img src={ img } className="mx_MemberTile_power" width="44" height="44" alt=""/>;
+        // }
         var presenceClass = "mx_MemberTile_offline";
         var mainClassName = "mx_MemberTile ";
         if (this.props.member.user) {
@@ -134,13 +127,13 @@ module.exports = React.createClass({
             }
         }
         mainClassName += presenceClass;
-        if (this.state.hover || this.state.menu) {
+        if (this.state.hover) {
             mainClassName += " mx_MemberTile_hover";
         }
 
         var name = this.props.member.name;
         // if (isMyUser) name += " (me)"; // this does nothing other than introduce line wrapping and pain
-        var leave = isMyUser ? <img className="mx_MemberTile_leave" src="img/delete.png" width="10" height="10" onClick={this.onLeaveClick}/> : null;
+        //var leave = isMyUser ? <img className="mx_MemberTile_leave" src="img/delete.png" width="10" height="10" onClick={this.onLeaveClick}/> : null;
 
         var nameClass = "mx_MemberTile_name";
         if (zalgo.test(name)) {
@@ -148,7 +141,7 @@ module.exports = React.createClass({
         }
 
         var nameEl;
-        if (this.state.hover || this.state.menu) {
+        if (this.state.hover) {
             var presence;
             // FIXME: make presence data update whenever User.presence changes...
             var active = this.props.member.user ? ((Date.now() - (this.props.member.user.lastPresenceTs - this.props.member.user.lastActiveAgo)) || -1) : -1;
@@ -161,8 +154,8 @@ module.exports = React.createClass({
 
             nameEl =
                 <div className="mx_MemberTile_details">
-                    { leave }
-                    <div className="mx_MemberTile_userId">{ this.props.member.userId }</div>
+                    <img className="mx_MemberTile_chevron" src="img/member_chevron.png" width="8" height="12"/>
+                    <div className="mx_MemberTile_userId">{ name }</div>
                     { presence }
                 </div>
         }
@@ -177,7 +170,7 @@ module.exports = React.createClass({
         return (
             <div className={mainClassName} title={ this.getPowerLabel() } onClick={ this.onClick } onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave }>
                 <div className="mx_MemberTile_avatar">
-                    <MemberAvatar member={this.props.member} />
+                    <MemberAvatar member={this.props.member} width={36} height={36} />
                      { power }
                 </div>
                 { nameEl }
diff --git a/src/skins/vector/views/molecules/MessageComposer.js b/src/skins/vector/views/molecules/MessageComposer.js
index c94cade5..25f69bda 100644
--- a/src/skins/vector/views/molecules/MessageComposer.js
+++ b/src/skins/vector/views/molecules/MessageComposer.js
@@ -22,6 +22,7 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
 var MessageComposerController = require('matrix-react-sdk/lib/controllers/molecules/MessageComposer')
 
 var sdk = require('matrix-react-sdk')
+var dis = require('matrix-react-sdk/lib/dispatcher')
 
 module.exports = React.createClass({
     displayName: 'MessageComposer',
@@ -40,6 +41,14 @@ module.exports = React.createClass({
         this.refs.uploadInput.getDOMNode().value = null;
     },
 
+    onCallClick: function(ev) {
+        dis.dispatch({
+            action: 'place_call',
+            type: ev.shiftKey ? "screensharing" : "video",
+            room_id: this.props.room.roomId
+        });
+    },
+
     render: function() {
         var me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
         var uploadInputStyle = {display: 'none'};
@@ -49,15 +58,18 @@ module.exports = React.createClass({
                 <div className="mx_MessageComposer_wrapper">
                     <div className="mx_MessageComposer_row">
                         <div className="mx_MessageComposer_avatar">
-                            <MemberAvatar member={me} />
+                            <MemberAvatar member={me} width={24} height={24} />
                         </div>
                         <div className="mx_MessageComposer_input">
-                            <textarea ref="textarea" onKeyDown={this.onKeyDown} placeholder="Type a message" />
+                            <textarea ref="textarea" onKeyDown={this.onKeyDown} placeholder="Type a message..." />
                         </div>
                         <div className="mx_MessageComposer_upload" onClick={this.onUploadClick}>
-                            <img src="img/upload.png" width="32" height="32"/>
+                            <img src="img/upload.png" width="17" height="22"/>
                             <input type="file" style={uploadInputStyle} ref="uploadInput" onChange={this.onUploadFileSelected} />
                         </div>
+                        <div className="mx_MessageComposer_call" onClick={this.onCallClick}>
+                            <img src="img/call.png" width="28" height="20"/>
+                        </div>
                     </div>
                 </div>
             </div>
diff --git a/src/skins/vector/views/molecules/MessageContextMenu.js b/src/skins/vector/views/molecules/MessageContextMenu.js
index 249d9a34..995c2c4b 100644
--- a/src/skins/vector/views/molecules/MessageContextMenu.js
+++ b/src/skins/vector/views/molecules/MessageContextMenu.js
@@ -84,7 +84,7 @@ module.exports = React.createClass({
         else {
             redactButton = (
                 <div className="mx_ContextualMenu_field" onClick={this.onRedactClick}>
-                    Delete
+                    Redact
                 </div>
             );
         }
diff --git a/src/skins/vector/views/molecules/MessageTile.js b/src/skins/vector/views/molecules/MessageTile.js
index f30fee92..6ea44413 100644
--- a/src/skins/vector/views/molecules/MessageTile.js
+++ b/src/skins/vector/views/molecules/MessageTile.js
@@ -50,6 +50,6 @@ module.exports = React.createClass({
             TileType = tileTypes[msgtype];
         }
 
-        return <TileType mxEvent={this.props.mxEvent} />;
+        return <TileType mxEvent={this.props.mxEvent} searchTerm={this.props.searchTerm} />;
     },
 });
diff --git a/src/skins/vector/views/molecules/RoomHeader.js b/src/skins/vector/views/molecules/RoomHeader.js
index d3f9119a..7f45fd42 100644
--- a/src/skins/vector/views/molecules/RoomHeader.js
+++ b/src/skins/vector/views/molecules/RoomHeader.js
@@ -41,7 +41,7 @@ module.exports = React.createClass({
     onFullscreenClick: function() {
         dis.dispatch({action: 'video_fullscreen', fullscreen: true}, true);
     },
-
+    
     render: function() {
         var EditableText = sdk.getComponent("atoms.EditableText");
         var RoomAvatar = sdk.getComponent('atoms.RoomAvatar');
@@ -59,7 +59,6 @@ module.exports = React.createClass({
             var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
 
             var call_buttons;
-            var zoom_button;
             if (this.state && this.state.call_state != 'ended') {
                 //var muteVideoButton;
                 var activeCall = (
@@ -111,16 +110,15 @@ module.exports = React.createClass({
                 cancel_button = <div className="mx_RoomHeader_textButton" onClick={this.props.onCancelClick}>Cancel</div>
                 save_button = <div className="mx_RoomHeader_textButton" onClick={this.props.onSaveClick}>Save Changes</div>
             } else {
+                // <EditableText label={this.props.room.name} initialValue={actual_name} placeHolder="Name" onValueChanged={this.onNameChange} />
                 name =
-                    <div className="mx_RoomHeader_name">
-                        <EditableText label={this.props.room.name} initialValue={actual_name} placeHolder="Name" onValueChanged={this.onNameChange} />
+                    <div className="mx_RoomHeader_name" onClick={this.props.onSettingsClick}>
+                        <div className="mx_RoomHeader_nametext">{ this.props.room.name }</div>
+                        <div className="mx_RoomHeader_settingsButton">
+                            <img src="img/settings.png" width="12" height="12"/>
+                        </div>
                     </div>
                 if (topic) topic_el = <div className="mx_RoomHeader_topic" title={topic.getContent().topic}>{ topic.getContent().topic }</div>;
-                settings_button = (
-                    <div className="mx_RoomHeader_button" onClick={this.props.onSettingsClick}>
-                        <img src="img/settings.png" width="32" height="32"/>
-                    </div>
-                );
             }
 
             var roomAvatar = null;
@@ -130,12 +128,23 @@ module.exports = React.createClass({
                 );
             }
 
-            if (activeCall && activeCall.type == "video") {
-                zoom_button = (
-                    <div className="mx_RoomHeader_button" onClick={this.onFullscreenClick}>
-                        <img src="img/zoom.png" title="Fullscreen" alt="Fullscreen" width="32" height="32" style={{ 'marginTop': '3px' }}/>
-                    </div>
-                );
+            var zoom_button, video_button, voice_button;
+            if (activeCall) {
+                if (activeCall.type == "video") {
+                    zoom_button = (
+                        <div className="mx_RoomHeader_button" onClick={this.onFullscreenClick}>
+                            <img src="img/zoom.png" title="Fullscreen" alt="Fullscreen" width="32" height="32" style={{ 'marginTop': '-5px' }}/>
+                        </div>
+                    );
+                }
+                video_button = 
+                        <div className="mx_RoomHeader_button mx_RoomHeader_video" onClick={activeCall && activeCall.type === "video" ? this.onMuteVideoClick : this.onVideoClick}>
+                            <img src="img/video.png" title="Video call" alt="Video call" width="32" height="32" style={{ 'marginTop': '-8px' }}/>
+                        </div>;
+                voice_button =
+                        <div className="mx_RoomHeader_button mx_RoomHeader_voice" onClick={activeCall ? this.onMuteAudioClick : this.onVoiceClick}>
+                            <img src="img/voip.png" title="VoIP call" alt="VoIP call" width="32" height="32" style={{ 'marginTop': '-8px' }}/>
+                        </div>;
             }
 
             header =
@@ -153,16 +162,11 @@ module.exports = React.createClass({
                     {cancel_button}
                     {save_button}
                     <div className="mx_RoomHeader_rightRow">
-                        { settings_button }
+                        { video_button }
+                        { voice_button }
                         { zoom_button }
-                        <div className="mx_RoomHeader_button mx_RoomHeader_search">
-                            <img src="img/search.png" title="Search" alt="Search" width="32" height="32"/>
-                        </div>
-                        <div className="mx_RoomHeader_button mx_RoomHeader_video" onClick={activeCall && activeCall.type === "video" ? this.onMuteVideoClick : this.onVideoClick}>
-                            <img src="img/video.png" title="Video call" alt="Video call" width="32" height="32"/>
-                        </div>
-                        <div className="mx_RoomHeader_button mx_RoomHeader_voice" onClick={activeCall ? this.onMuteAudioClick : this.onVoiceClick}>
-                            <img src="img/voip.png" title="VoIP call" alt="VoIP call" width="32" height="32"/>
+                        <div className="mx_RoomHeader_button">
+                            <img src="img/search.png" title="Search" alt="Search" width="21" height="19" onClick={this.props.onSearchClick}/>
                         </div>
                     </div>
                 </div>
diff --git a/src/skins/vector/views/molecules/RoomTile.js b/src/skins/vector/views/molecules/RoomTile.js
index 39e7b43c..82616b5a 100644
--- a/src/skins/vector/views/molecules/RoomTile.js
+++ b/src/skins/vector/views/molecules/RoomTile.js
@@ -50,7 +50,16 @@ module.exports = React.createClass({
             'mx_RoomTile_highlight': this.props.highlight,
             'mx_RoomTile_invited': this.props.room.currentState.members[myUserId].membership == 'invite'
         });
-        var name = this.props.room.name.replace(":", ":\u200b");
+
+        var name;
+        if (this.props.isInvite) {
+            name = this.props.room.getMember(MatrixClientPeg.get().credentials.userId).events.member.getSender();
+        }
+        else {
+            name = this.props.room.name;
+        }
+
+        name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon
         var badge;
         if (this.props.highlight) {
             badge = <div className="mx_RoomTile_badge"/>;
@@ -73,7 +82,8 @@ module.exports = React.createClass({
 
         var label;
         if (!this.props.collapsed) {
-            label = <div className="mx_RoomTile_name">{name}</div>;
+            var className = 'mx_RoomTile_name' + (this.props.isInvite ? ' mx_RoomTile_invite' : '');
+            label = <div className={ className }>{name}</div>;
         }
         else if (this.state.hover) {
             var RoomTooltip = sdk.getComponent("molecules.RoomTooltip");
@@ -84,7 +94,7 @@ module.exports = React.createClass({
         return (
             <div className={classes} onClick={this.onClick} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
                 <div className="mx_RoomTile_avatar">
-                    <RoomAvatar room={this.props.room} />
+                    <RoomAvatar room={this.props.room} width="24" height="24" />
                     { badge }
                 </div>
                 { label }
diff --git a/src/skins/vector/views/molecules/SearchBar.js b/src/skins/vector/views/molecules/SearchBar.js
new file mode 100644
index 00000000..d31e24b4
--- /dev/null
+++ b/src/skins/vector/views/molecules/SearchBar.js
@@ -0,0 +1,56 @@
+/*
+Copyright 2015 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.
+*/
+
+'use strict';
+
+var React = require('react');
+var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
+var sdk = require('matrix-react-sdk');
+
+module.exports = React.createClass({
+    displayName: 'SearchBar',
+
+    getInitialState: function() {
+        return ({
+            scope: 'Room'
+        });
+    },
+
+    onThisRoomClick: function() {
+        this.setState({ scope: 'Room' });
+    },
+
+    onAllRoomsClick: function() {
+        this.setState({ scope: 'All' });
+    },
+
+    onSearchChange: function(e) {
+        if (e.keyCode === 13) { // on enter...
+            this.props.onSearch(this.refs.search_term.getDOMNode().value, this.state.scope);
+        }
+    },
+    
+    render: function() {
+        return (
+            <div className="mx_SearchBar">
+                <input ref="search_term" className="mx_SearchBar_input" type="text" autoFocus={true} placeholder="Search..." onKeyDown={this.onSearchChange}/>
+                <div className={"mx_SearchBar_button" + (this.state.scope !== 'Room' ? " mx_SearchBar_unselected" : "")} onClick={this.onThisRoomClick}>This Room</div>
+                <div className={"mx_SearchBar_button" + (this.state.scope !== 'All' ? " mx_SearchBar_unselected" : "")} onClick={this.onAllRoomsClick}>All Rooms</div>
+                <img className="mx_SearchBar_cancel" src="img/cancel-black.png" width="18" height="18" onClick={this.props.onCancelClick} />
+            </div>
+        );
+    }
+});
diff --git a/src/skins/vector/views/organisms/LeftPanel.js b/src/skins/vector/views/organisms/LeftPanel.js
index a57f7a0a..ec25f934 100644
--- a/src/skins/vector/views/organisms/LeftPanel.js
+++ b/src/skins/vector/views/organisms/LeftPanel.js
@@ -40,7 +40,8 @@ module.exports = React.createClass({
             classes += " collapsed";
         }
         else {
-            collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/>   
+            // Hide the collapse button until we work out how to display it in the new skin
+            // collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/>   
         }
 
         return (
diff --git a/src/skins/vector/views/organisms/MemberList.js b/src/skins/vector/views/organisms/MemberList.js
index 08f4e45c..ba7bc010 100644
--- a/src/skins/vector/views/organisms/MemberList.js
+++ b/src/skins/vector/views/organisms/MemberList.js
@@ -30,7 +30,6 @@ module.exports = React.createClass({
     mixins: [MemberListController],
 
     getInitialState: function() {
-        return { editing: false };
     },
 
     memberSort: function(userIdA, userIdB) {
@@ -71,43 +70,21 @@ module.exports = React.createClass({
         });
     },
 
-    onPopulateInvite: function(inputText, shouldSubmit) {
-        // reset back to placeholder
-        this.refs.invite.setValue("Invite", false, true);
-        this.setState({ editing: false });
-        if (!shouldSubmit) {
-            return; // enter key wasn't pressed
-        }
-        this.onInvite(inputText);
-    },
-
-    onClickInvite: function(ev) {
-        this.setState({ editing: true });
-        this.refs.invite.onClickDiv();
-        ev.stopPropagation();
-        ev.preventDefault();
+    onPopulateInvite: function(e) {
+        this.onInvite(this.refs.invite.getDOMNode().value);
+        e.preventDefault();
     },
 
     inviteTile: function() {
-        var classes = classNames({
-            mx_MemberTile: true,
-            mx_MemberTile_inviteTile: true,
-            mx_MemberTile_inviteEditing: this.state.editing,
-        });
-
-        var EditableText = sdk.getComponent("atoms.EditableText");
         if (this.state.inviting) {
             return (
                 <Loader />
             );
         } else {
             return (
-                <div className={ classes } onClick={ this.onClickInvite } >
-                    <div className="mx_MemberTile_avatar"><img src="img/create-big.png" width="40" height="40" alt=""/></div>
-                    <div className="mx_MemberTile_name">
-                        <EditableText ref="invite" label="Invite" placeHolder="@user:domain.com" initialValue="" onValueChanged={this.onPopulateInvite}/>
-                    </div>
-                </div>
+                <form onSubmit={this.onPopulateInvite}>
+                    <input className="mx_MemberList_invite" ref="invite" placeholder="Invite another user"/>
+                </form>
             );
         }
     },
@@ -117,7 +94,7 @@ module.exports = React.createClass({
         var invitedMemberTiles = this.makeMemberTiles('invite');
         if (invitedMemberTiles.length > 0) {
             invitedSection = (
-                <div>
+                <div className="mx_MemberList_invited">
                     <h2>Invited</h2>
                     <div className="mx_MemberList_wrapper">
                         {invitedMemberTiles}
@@ -127,18 +104,14 @@ module.exports = React.createClass({
         }
         return (
             <div className="mx_MemberList">
-                <div className="mx_MemberList_chevron">
-                    <img src="img/chevron.png" width="24" height="13"/>
-                </div>
                 <div className="mx_MemberList_border">
+                    {this.inviteTile()}
                     <div>
-                        <h2>Members</h2>
                         <div className="mx_MemberList_wrapper">
                             {this.makeMemberTiles('join')}
                         </div>
                     </div>
                     {invitedSection}
-                    {this.inviteTile()}
                 </div>
             </div>
         );
diff --git a/src/skins/vector/views/organisms/RightPanel.js b/src/skins/vector/views/organisms/RightPanel.js
index 6d9dc743..feebcfeb 100644
--- a/src/skins/vector/views/organisms/RightPanel.js
+++ b/src/skins/vector/views/organisms/RightPanel.js
@@ -19,6 +19,7 @@ limitations under the License.
 var React = require('react');
 var sdk = require('matrix-react-sdk')
 var dis = require('matrix-react-sdk/lib/dispatcher');
+var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
 
 module.exports = React.createClass({
     displayName: 'RightPanel',
@@ -26,6 +27,20 @@ module.exports = React.createClass({
     Phase : {
         MemberList: 'MemberList',
         FileList: 'FileList',
+        MemberInfo: 'MemberInfo',
+    },
+
+    componentWillMount: function() {
+        this.dispatcherRef = dis.register(this.onAction);
+        var cli = MatrixClientPeg.get();
+        cli.on("RoomState.members", this.onRoomStateMember);
+    },
+
+    componentWillUnmount: function() {
+        dis.unregister(this.dispatcherRef);        
+        if (MatrixClientPeg.get()) {
+            MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
+        }
     },
 
     getInitialState: function() {
@@ -48,25 +63,85 @@ module.exports = React.createClass({
         }
     },
 
+    onRoomStateMember: function(ev, state, member) {
+        // redraw the badge on the membership list
+        if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) {
+            this.forceUpdate();
+        }
+    },
+
+    onAction: function(payload) {
+        if (payload.action === "view_user") {
+            if (payload.member) {
+                this.setState({
+                    phase: this.Phase.MemberInfo,
+                    member: payload.member,
+                });
+            }
+            else {
+                this.setState({
+                    phase: this.Phase.MemberList
+                });
+            }
+        }
+        if (payload.action === "view_room") {
+            if (this.state.phase === this.Phase.MemberInfo) {
+                this.setState({
+                    phase: this.Phase.MemberList
+                });
+            }
+        }
+    },
+
     render: function() {
         var MemberList = sdk.getComponent('organisms.MemberList');
         var buttonGroup;
         var panel;
 
+        var filesHighlight;
+        var membersHighlight;
+        if (!this.props.collapsed) {
+            if (this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) {
+                membersHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
+            }
+            else if (this.state.phase == this.Phase.FileList) {
+                filesHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
+            }
+        }
+
+        var membersBadge;
+        if ((this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) && this.props.roomId) {
+            var cli = MatrixClientPeg.get();
+            var room = cli.getRoom(this.props.roomId);
+            if (room) {
+                membersBadge = <div className="mx_RightPanel_headerButton_badge">{ room.getJoinedMembers().length }</div>;
+            }
+        }
+
         if (this.props.roomId) {
             buttonGroup =
                     <div className="mx_RightPanel_headerButtonGroup">
-                        <div className="mx_RightPanel_headerButton mx_RightPanel_filebutton">
-                            <img src="img/file.png" width="32" height="32" title="Files" alt="Files"/>
-                        </div>
                         <div className="mx_RightPanel_headerButton" onClick={ this.onMemberListButtonClick }>
-                            <img src="img/members.png" width="32" height="32" title="Members" alt="Members"/>
+                            <img src="img/members.png" width="17" height="22" title="Members" alt="Members"/>
+                            { membersBadge }
+                            { membersHighlight }
+                        </div>
+                        <div className="mx_RightPanel_headerButton mx_RightPanel_filebutton">
+                            <img src="img/files.png" width="17" height="22" title="Files" alt="Files"/>
+                            { filesHighlight }
                         </div>
                     </div>;
 
-            if (!this.props.collapsed && this.state.phase == this.Phase.MemberList) {
-                panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
+            if (!this.props.collapsed) {
+                if(this.state.phase == this.Phase.MemberList) {
+                    panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
+                }
+                else if(this.state.phase == this.Phase.MemberInfo) {
+                    var MemberInfo = sdk.getComponent('molecules.MemberInfo');
+                    panel = <MemberInfo roomId={this.props.roomId} member={this.state.member} key={this.props.roomId} />
+                }
             }
+
         }
 
         var classes = "mx_RightPanel";
diff --git a/src/skins/vector/views/organisms/RoomDirectory.js b/src/skins/vector/views/organisms/RoomDirectory.js
index 5f5717c8..90c5dd57 100644
--- a/src/skins/vector/views/organisms/RoomDirectory.js
+++ b/src/skins/vector/views/organisms/RoomDirectory.js
@@ -69,6 +69,7 @@ module.exports = React.createClass({
             });
         }, function(err) {
             console.error("Failed to join room: %s", JSON.stringify(err));
+            var ErrorDialog = sdk.getComponent("organisms.ErrorDialog");
             Modal.createDialog(ErrorDialog, {
                 title: "Failed to join room",
                 description: err.message
diff --git a/src/skins/vector/views/organisms/RoomList.js b/src/skins/vector/views/organisms/RoomList.js
index dd8840e5..dc958a4e 100644
--- a/src/skins/vector/views/organisms/RoomList.js
+++ b/src/skins/vector/views/organisms/RoomList.js
@@ -41,22 +41,38 @@ module.exports = React.createClass({
             callElement = <CallView className="mx_MatrixChat_callView"/>
         }
 
-        var recentsLabel = this.props.collapsed ? 
-                           <img style={{cursor: 'pointer'}} onClick={ this.onShowClick } src="img/menu.png" width="27" height="20" alt=">"/> :
-                           "Recents";
+        var expandButton = this.props.collapsed ? 
+                           <img className="mx_RoomList_expandButton" onClick={ this.onShowClick } src="img/menu.png" width="20" alt=">"/> :
+                           null;
+
+        var invitesLabel = this.props.collapsed ? null : "Invites";
+        var recentsLabel = this.props.collapsed ? null : "Recent";
+
+        var invites;
+        if (this.state.inviteList.length) {
+            invites = <div>
+                        <h2 className="mx_RoomList_invitesLabel">{ invitesLabel }</h2>
+                        <div className="mx_RoomList_invites">
+                            {this.makeRoomTiles(this.state.inviteList, true)}
+                        </div>
+                      </div>
+        }
 
         return (
             <div className="mx_RoomList" onScroll={this._repositionTooltip}>
-                {callElement}
-                <h2 className="mx_RoomList_favourites_label">Favourites</h2>
+                { expandButton }
+                { callElement }
+                <h2 className="mx_RoomList_favouritesLabel">Favourites</h2>
                 <RoomDropTarget text="Drop here to favourite"/>
 
-                <h2 className="mx_RoomList_recents_label">{ recentsLabel }</h2>
+                { invites }
+
+                <h2 className="mx_RoomList_recentsLabel">{ recentsLabel }</h2>
                 <div className="mx_RoomList_recents">
-                    {this.makeRoomTiles()}
+                    {this.makeRoomTiles(this.state.roomList, false)}
                 </div>
 
-                <h2 className="mx_RoomList_archive_label">Archive</h2>
+                <h2 className="mx_RoomList_archiveLabel">Archive</h2>
                 <RoomDropTarget text="Drop here to archive"/>
             </div>
         );
diff --git a/src/skins/vector/views/organisms/RoomView.js b/src/skins/vector/views/organisms/RoomView.js
index f62eb3c3..0a2d2411 100644
--- a/src/skins/vector/views/organisms/RoomView.js
+++ b/src/skins/vector/views/organisms/RoomView.js
@@ -63,6 +63,10 @@ module.exports = React.createClass({
         this.setState(this.getInitialState());
     },
 
+    onSearchClick: function() {
+        this.setState({ searching: true });
+    },
+
     onConferenceNotificationClick: function() {
         dis.dispatch({
             action: 'place_call',
@@ -89,6 +93,7 @@ module.exports = React.createClass({
         var MessageComposer = sdk.getComponent('molecules.MessageComposer');
         var CallView = sdk.getComponent("molecules.voip.CallView");
         var RoomSettings = sdk.getComponent("molecules.RoomSettings");
+        var SearchBar = sdk.getComponent("molecules.SearchBar");
 
         if (!this.state.room) {
             if (this.props.roomId) {
@@ -159,8 +164,8 @@ module.exports = React.createClass({
                         <div className="mx_RoomView_uploadProgressOuter">
                             <div className="mx_RoomView_uploadProgressInner" style={innerProgressStyle}></div>
                         </div>
-                        <img className="mx_RoomView_uploadIcon" src="img/fileicon.png" width="40" height="40"/>
-                        <img className="mx_RoomView_uploadCancel" src="img/cancel.png" width="40" height="40"/>
+                        <img className="mx_RoomView_uploadIcon" src="img/fileicon.png" width="17" height="22"/>
+                        <img className="mx_RoomView_uploadCancel" src="img/cancel.png" width="18" height="18"/>
                         <div className="mx_RoomView_uploadBytes">
                             { uploadedSize } / { totalSize }
                         </div>
@@ -175,7 +180,7 @@ module.exports = React.createClass({
                 if (unreadMsgs) {
                     statusBar = (
                         <div className="mx_RoomView_unreadMessagesBar" onClick={ this.scrollToBottom }>
-                            <img src="img/newmessages.png" width="10" height="12" alt=""/>
+                            <img src="img/newmessages.png" width="24" height="24" alt=""/>
                             {unreadMsgs}
                         </div>
                     );
@@ -183,19 +188,22 @@ module.exports = React.createClass({
                 else if (typingString) {
                     statusBar = (
                         <div className="mx_RoomView_typingBar">
-                            <img src="img/typing.png" width="40" height="40" alt=""/>
+                            <div className="mx_RoomView_typingImage">...</div>
                             {typingString}
                         </div>
                     );
                 }
             }
 
-            var roomEdit = null;
+            var aux = null;
             if (this.state.editingRoomSettings) {
-                roomEdit = <RoomSettings ref="room_settings" onSaveClick={this.onSaveClick} room={this.state.room} />;
+                aux = <RoomSettings ref="room_settings" onSaveClick={this.onSaveClick} room={this.state.room} />;
             }
-            if (this.state.uploadingRoomSettings) {
-                roomEdit = <Loader/>;
+            else if (this.state.uploadingRoomSettings) {
+                aux = <Loader/>;
+            }
+            else if (this.state.searching) {
+                aux = <SearchBar ref="search_bar" onCancelClick={this.onCancelClick} onSearch={this.onSearch}/>;
             }
 
             var conferenceCallNotification = null;
@@ -211,7 +219,7 @@ module.exports = React.createClass({
             if (this.state.draggingFile) {
                 fileDropTarget = <div className="mx_RoomView_fileDropTarget">
                                     <div className="mx_RoomView_fileDropTargetLabel">
-                                        <img src="img/upload-big.png" width="46" height="61" alt="Drop File Here"/><br/>
+                                        <img src="img/upload-big.png" width="43" height="57" alt="Drop File Here"/><br/>
                                         Drop File Here
                                     </div>
                                  </div>;
@@ -219,12 +227,12 @@ module.exports = React.createClass({
 
             return (
                 <div className="mx_RoomView">
-                    <RoomHeader ref="header" room={this.state.room} editing={this.state.editingRoomSettings}
+                    <RoomHeader ref="header" room={this.state.room} editing={this.state.editingRoomSettings} onSearchClick={this.onSearchClick}
                         onSettingsClick={this.onSettingsClick} onSaveClick={this.onSaveClick} onCancelClick={this.onCancelClick} />
                     <div className="mx_RoomView_auxPanel">
                         <CallView room={this.state.room}/>
                         { conferenceCallNotification }
-                        { roomEdit }
+                        { aux }
                     </div>
                     <div ref="messageWrapper" className="mx_RoomView_messagePanel" onScroll={ this.onMessageListScroll }>
                         <div className="mx_RoomView_messageListWrapper">
@@ -238,6 +246,7 @@ module.exports = React.createClass({
                     </div>
                     <div className="mx_RoomView_statusArea">
                         <div className="mx_RoomView_statusAreaBox">
+                            <div className="mx_RoomView_statusAreaBox_line"></div>
                             {statusBar}
                         </div>
                     </div>
diff --git a/src/skins/vector/views/organisms/ViewSource.js b/src/skins/vector/views/organisms/ViewSource.js
index a00cfc85..371223d4 100644
--- a/src/skins/vector/views/organisms/ViewSource.js
+++ b/src/skins/vector/views/organisms/ViewSource.js
@@ -21,6 +21,26 @@ var React = require('react');
 module.exports = React.createClass({
     displayName: 'ViewSource',
 
+    propTypes: {
+        onFinished: React.PropTypes.func.isRequired
+    },
+
+    componentDidMount: function() {
+        document.addEventListener("keydown", this.onKeyDown);
+    },
+
+    componentWillUnmount: function() {
+        document.removeEventListener("keydown", this.onKeyDown);
+    },
+
+    onKeyDown: function(ev) {
+        if (ev.keyCode == 27) { // escape
+            ev.stopPropagation();
+            ev.preventDefault();
+            this.props.onFinished();
+        }
+    },
+    
     render: function() {
         return (
             <div className="mx_ViewSource">
diff --git a/vector/index.html b/vector/index.html
index 2985994b..d893523e 100644
--- a/vector/index.html
+++ b/vector/index.html
@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8">
     <title>Vector</title>
-    <link href='fonts/Lato.css' rel='stylesheet' type='text/css'>
+    <link href='fonts/MyriadPro.css' rel='stylesheet' type='text/css'>
     <link rel="apple-touch-icon" sizes="57x57" href="/icons/apple-touch-icon-57x57.png">
     <link rel="apple-touch-icon" sizes="60x60" href="/icons/apple-touch-icon-60x60.png">
     <link rel="apple-touch-icon" sizes="72x72" href="/icons/apple-touch-icon-72x72.png">