diff --git a/gui/components/BoldLabel.qml b/gui/components/BoldLabel.qml
index 6c6c3c34378a82e1990f54b16c26215cdba0e25c..d4a6ba391d87bf5e1a2a036dae936adc65c229cf 100644
--- a/gui/components/BoldLabel.qml
+++ b/gui/components/BoldLabel.qml
@@ -4,18 +4,15 @@ import "../themes/themes.js" as Theme
 import "../themes"
 
 Label {
-    FontLoader {
-        id: boldFont
-        source: "qrc:/oxanium-bold.ttf"
+    color: "black"
+
+    font {
+        pixelSize: Theme.fontSize * 1.5
+        family: boldFont.name
+        bold: true
     }
 
-    font.pixelSize: Theme.fontSize * 1.55555
-    //font.family: boldFont.name
-    font.bold: true
-    //color: Theme.fontColorDark
-    color: "black"
     text: parent.text
-    //wrapMode: Text.WordWrap
     Accessible.name: text
     Accessible.role: Accessible.StaticText
 }
diff --git a/gui/components/ErrorBox.qml b/gui/components/ErrorBox.qml
new file mode 100644
index 0000000000000000000000000000000000000000..40c12d062fb01562fc1745dc9f3860fb8cae6870
--- /dev/null
+++ b/gui/components/ErrorBox.qml
@@ -0,0 +1,33 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtGraphicalEffects 1.0
+import "../themes/themes.js" as Theme
+
+Item {
+    id: errorBox
+    width: parent.width
+    property var errorText: ""
+    anchors.horizontalCenter: parent.horizontalCenter
+    anchors.top: connectionImage.bottom
+
+    // TODO alert icon, by type
+
+    Rectangle {
+
+        id: labelWrapper
+        color: "transparent"
+        height: label.paintedHeight + Theme.windowMargin
+        width: parent.width
+        anchors.verticalCenter: parent.verticalCenter
+
+        Label {
+            id: label
+            width: labelWrapper.width - Theme.windowMargin
+            anchors.centerIn: parent
+            text: errorBox.errorText //+ " " + "<b><u>" + alertLinkText + "</b></u>"
+            horizontalAlignment: Text.AlignHCenter
+            wrapMode: Text.Wrap
+            font.pixelSize: Theme.fontSizeSmall
+         }
+    }
+}
diff --git a/gui/components/InitErrors.qml b/gui/components/InitErrors.qml
new file mode 100644
index 0000000000000000000000000000000000000000..2859168c9b3d9135243e4fe2030dd4ec45b1cbae
--- /dev/null
+++ b/gui/components/InitErrors.qml
@@ -0,0 +1,49 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtGraphicalEffects 1.0
+
+ErrorBox {
+
+    state: "noerror"
+
+    states: [
+        State {
+            name: "noerror"
+            when: root.error == ""
+            PropertyChanges {
+                target: splashSpinner
+                visible: true
+            }
+            PropertyChanges {
+                target: splashErrorBox
+                visible: false
+            }
+        },
+        State {
+            name: "nohelpers"
+            when: root.error == "nohelpers"
+            PropertyChanges {
+                target: splashSpinner
+                visible: false
+            }
+            PropertyChanges {
+                target: splashErrorBox
+                errorText: qsTr("Could not find helpers. Please check your installation")
+                visible: true 
+            }
+        },
+        State {
+            name: "nopolkit"
+            when: root.error == "nopolkit"
+            PropertyChanges {
+                target: splashSpinner
+                visible: false
+            }
+            PropertyChanges {
+                target: splashErrorBox
+                errorText: qsTr("Could not find polkit agent.")
+                visible: true 
+            }
+        }
+    ]
+}
diff --git a/gui/components/LightLabel.qml b/gui/components/LightLabel.qml
index 78f82b65d97131f3c16927d1ddfa10460bad6b50..ea723c795d7abf00fcb1209941fdee1909c86a0a 100644
--- a/gui/components/LightLabel.qml
+++ b/gui/components/LightLabel.qml
@@ -11,7 +11,6 @@ Text {
 
     horizontalAlignment: Text.AlignHCenter
     verticalAlignment: Text.AlignVCenter
-    //lineHeightMode: Text.FixedHeight
     wrapMode: Text.Wrap
 
     Accessible.role: Accessible.StaticText
diff --git a/gui/components/MainView.qml b/gui/components/MainView.qml
index 7ce723dbc84896897cadf1fbc187d506e4b18dac..1918c7f15ffbc087a435b2f8bd697a947ece8910 100644
--- a/gui/components/MainView.qml
+++ b/gui/components/MainView.qml
@@ -26,6 +26,10 @@ Page {
             delegate: ItemDelegate {
                 width: parent.width
                 text: model.text
+                visible: {
+                    if (isDonationService) {return true}
+                    return model.text != qsTr("Donate")
+                }
                 highlighted: ListView.isCurrentItem
                 icon.color: "transparent"
                 icon.source: model.icon
diff --git a/gui/components/Splash.qml b/gui/components/Splash.qml
index b4944947144a03edb46c701826eb894b50b7e7a4..6bdd3ab433ae5f814c2c72fa303ea98b61ca9bd1 100644
--- a/gui/components/Splash.qml
+++ b/gui/components/Splash.qml
@@ -5,6 +5,7 @@ import QtGraphicalEffects 1.0
 Page {
     id: splash
     property int timeoutInterval: 1600
+    property alias errors: splashErrorBox
 
     Column {
         width: parent.width * 0.8
@@ -24,7 +25,13 @@ Page {
             fillMode: Image.PreserveAspectFit
         }
 
-        Spinner {}
+        Spinner {
+            id: splashSpinner
+        }
+
+        InitErrors {
+            id: splashErrorBox
+        }
     }
 
     Timer {
@@ -39,10 +46,10 @@ Page {
     }
 
     function loadMainViewWhenReady() {
-        console.debug("ready?")
+        if (root.error != "") {
+            return
+        }
         if (ctx && ctx.isReady) {
-            console.debug("ready?", ctx.isReady)
-            // FIXME check errors == None
             loader.source = "MainView.qml"
         } else {
             delay(100, loadMainViewWhenReady)
diff --git a/gui/components/StatusBox.qml b/gui/components/StatusBox.qml
index fa24cd89faf4ac51e0ed75581c7b99fbfba490fd..a20b93076e874a082e4f8a0d775069af1ed7d22f 100644
--- a/gui/components/StatusBox.qml
+++ b/gui/components/StatusBox.qml
@@ -19,27 +19,33 @@ Item {
 
     Rectangle {
         id: statusBoxBackground
-        anchors.fill: parent
-        anchors.margins: 20
-        anchors.bottomMargin: 30
         height: 300
         radius: 10
         color: Theme.bgColor
-        border.color: Theme.accentOff
-        border.width: 2
         antialiasing: true
+        anchors {
+            fill: parent
+            margins: 20
+            bottomMargin: 30
+        }
+        border {
+            color: Theme.accentOff
+            width: 2
+        }
     }
 
     ToolButton {
         id: settingsButton
         objectName: "settingsButton"
+        font.pixelSize: Qt.application.font.pixelSize * 1.2
         opacity: 1
 
-        font.pixelSize: Qt.application.font.pixelSize * 1.6
-        anchors.top: parent.top
-        anchors.left: parent.left
-        anchors.topMargin: Theme.windowMargin + 10
-        anchors.leftMargin: Theme.windowMargin + 10
+        anchors {
+            top: parent.top
+            left: parent.left
+            topMargin: Theme.windowMargin + 10
+            leftMargin: Theme.windowMargin + 10
+        }
 
         onClicked: {
             if (stackView.depth > 1) {
@@ -51,75 +57,78 @@ Item {
 
         Icon {
             id: settingsImage
-            width: 24
-            height: 24
-            // TODO move arrow left to toolbar top
+            width: 16
+            height: 16
+            anchors.centerIn: settingsButton
             source: stackView.depth
                     > 1 ? "../resources/arrow-left.svg" : "../resources/gear-fill.svg"
-            anchors.centerIn: settingsButton
         }
     }
 
-    Column {
-        id: col
-        anchors.centerIn: parent
-        anchors.topMargin: 24
-        width: parent.width * 0.8
-
+    Rectangle {
+        id: statusLabelWrapper
+        height: 45
+        anchors {
+            top: statusBoxBackground.top
+            topMargin: 40
+            horizontalCenter: parent.horizontalCenter
+        }
         BoldLabel {
             id: connectionState
-            text: ""
+            anchors.top: parent.top
             anchors.horizontalCenter: parent.horizontalCenter
             horizontalAlignment: Text.AlignHCenter
+            text: ""
         }
+    }
+
+    Column {
+        id: col
+        width: parent.width * 0.8
+        anchors.horizontalCenter: parent.horizontalCenter
 
         VerticalSpacer {
             id: spacerPreImg
-            visible: false
-            height: 40
+            visible: true
+            height: 150
         }
 
         Image {
             id: connectionImage
-            height: 200
+            height: 160
             source: "../resources/spy.gif"
+            anchors.horizontalCenter: parent.horizontalCenter
             fillMode: Image.PreserveAspectFit
         }
 
         VerticalSpacer {
             id: spacerPostImg
-            visible: false
-            height: 35
+            visible: true
+            height: 30
         }
 
         MaterialButton {
             id: toggleVPN
+            spacing: 8
+
             anchors.horizontalCenter: parent.horizontalCenter
             Layout.alignment: Qt.AlignBottom
-            font.capitalization: Font.Capitalize
-            spacing: 8
+
+            font {
+                capitalization: Font.Capitalize
+                family: lightFont.name
+                bold: false
+            }
 
             onClicked: {
                 if (vpn.state === "on") {
-                    console.debug("should turn off")
                     backend.switchOff()
                 } else if (vpn.state === "off") {
-                    console.debug("should turn on")
                     backend.switchOn()
                 } else {
                     console.debug("unknown state")
                 }
             }
-
-
-            /*
-             XXX this hijacks click events, so better no pointing for now.
-            MouseArea {
-                anchors.fill: toggleVPN
-                hoverEnabled: true
-                cursorShape: !hoverEnabled ? Qt.ForbiddenCursor : Qt.PointingHandCursor
-            }
-            */
         }
     }
 }
diff --git a/gui/components/VPNState.qml b/gui/components/VPNState.qml
index 8856ad4a1075ff84e9a5fb0cde9ff23e731f89c8..9d443ceba349775c581d2482caf42403447afa8e 100644
--- a/gui/components/VPNState.qml
+++ b/gui/components/VPNState.qml
@@ -4,15 +4,21 @@ import QtQuick.Controls 2.12
 import "../themes/themes.js" as Theme
 
 StateGroup {
+    property var initializing: "initializing"
+    property var off: "off"
+    property var on: "on"
+    property var starting: "starting"
+    property var stopping: "stopping"
+    property var failed: "failed"
 
-    state: ctx ? ctx.status : "off"
+    state: ctx ? ctx.status : vpnStates.off
 
     states: [
         State {
-            name: "initializing"
+            name: initializing
         },
         State {
-            name: "off"
+            name: off
             PropertyChanges {
                 target: connectionState
                 text: qsTr("Connection\nUnsecured")
@@ -24,10 +30,6 @@ StateGroup {
             PropertyChanges {
                 target: connectionImage
                 source: "../resources/spy.gif"
-                //anchors.right: parent.right
-                //anchors.rightMargin: -8
-                // XXX need to nulify horizontalcenter somehow,
-                // it gets fixed to parent.center
             }
             PropertyChanges {
                 target: toggleVPN
@@ -42,16 +44,14 @@ StateGroup {
                 text: toHuman("off")
             }
             StateChangeScript {
-                script: {
-
-                }
+                script: {}
             }
         },
         State {
-            name: "on"
+            name: on
             PropertyChanges {
                 target: connectionState
-                text: qsTr("Connection\nSecure")
+                text: qsTr("Connection\nSecured")
             }
             PropertyChanges {
                 target: statusBoxBackground
@@ -60,17 +60,6 @@ StateGroup {
             PropertyChanges {
                 target: connectionImage
                 source: "../resources/riseup-icon.svg"
-                // TODO need to offset the logo or increase the image
-                // to fixed height
-                height: 120
-            }
-            PropertyChanges {
-                target: spacerPreImg
-                visible: true
-            }
-            PropertyChanges {
-                target: spacerPostImg
-                visible: true
             }
             PropertyChanges {
                 target: toggleVPN
@@ -86,20 +75,11 @@ StateGroup {
                 text: toHuman("on")
             }
             StateChangeScript {
-                script: {
-
-                    // TODO check donation
-                    //if (needsDonate && !shownDonate) {
-                    //    donate.visible = true;
-                    //    shownDonate = true;
-                    //    backend.donateSeen();
-                    //}
-                }
+                script: {}
             }
         },
         State {
-            name: "starting"
-            //when: toggleVPN.pressed == true
+            name: starting
             PropertyChanges {
                 target: connectionState
                 text: qsTr("Connecting")
@@ -127,13 +107,11 @@ StateGroup {
                 text: toHuman("connecting")
             }
             StateChangeScript {
-                script: {
-
-                }
+                script: {}
             }
         },
         State {
-            name: "stopping"
+            name: stopping
             PropertyChanges {
                 target: connectionState
                 text: "Switching\nOff"
@@ -142,6 +120,12 @@ StateGroup {
                 target: statusBoxBackground
                 border.color: Theme.accentConnecting
             }
+            PropertyChanges {
+                // ?? is this image correct?
+                target: connectionImage
+                source: "../resources/birds.svg"
+                anchors.horizontalCenter: parent.horizontalCenter
+            }
             PropertyChanges {
                 target: systray
                 tooltip: toHuman("stopping")
@@ -153,23 +137,39 @@ StateGroup {
             }
         },
         State {
-            name: "failed"
-            // TODO
+            name: failed
         }
     ]
-
-
-    /*
-    transitions: Transition {
-        from: "off"
-        to: "starting"
-        reversible: true
-
-        ParallelAnimation {
-            ColorAnimation { duration: 500 }
+    transitions: [
+        Transition {
+            to: on
+            ColorAnimation {
+                target: statusBoxBackground
+                duration: 500
+            }
+        },
+        Transition {
+            to: off
+            ColorAnimation {
+                target: statusBoxBackground
+                duration: 500
+            }
+        },
+        Transition {
+            to: starting
+            ColorAnimation {
+                target: statusBoxBackground
+                duration: 500
+            }
+        },
+        Transition {
+            to: stopping
+            ColorAnimation {
+                target: statusBoxBackground
+                duration: 500
+            }
         }
-    }
-    */
+    ]
     function toHuman(st) {
         switch (st) {
         case "off":
diff --git a/gui/gui.qrc b/gui/gui.qrc
index dde4c8fd1ddb8d54bd7e3ecabed2af96e617a908..c794ef1d8160e8c8c0c2e07da19621171fbf3110 100644
--- a/gui/gui.qrc
+++ b/gui/gui.qrc
@@ -3,6 +3,7 @@
 
         <file>main.qml</file>
 
+        <!-- gui components -->
         <file>themes/themes.js</file>
         <file>components/MainView.qml</file>
         <file>components/Splash.qml</file>
@@ -23,6 +24,10 @@
         <file>components/Icon.qml</file>
         <file>components/MaterialButton.qml</file>
         <file>components/VPNState.qml</file>
+        <file>components/InitErrors.qml</file>
+        <file>components/ErrorBox.qml</file>
+
+        <!-- resources, assets -->
         <file>resources/icon-noshield.svg</file>
         <file>resources/location.svg</file>
         <file>resources/settings.svg</file>
@@ -43,8 +48,13 @@
         <file>resources/riseup-icon.svg</file>
         <file>resources/spy.gif</file>
         <file>resources/quit.svg</file>
+        <file>resources/alert.svg</file>
+
+        <!-- fonts -->
+        <file alias="montserrat-light.ttf">resources/fonts/Montserrat-Regular.ttf</file>
+        <file alias="montserrat-bold.ttf">resources/fonts/Montserrat-SemiBold.ttf</file>
 
-        <!-- old, to remove -->
+        <!-- begin, to remove -->
         <file>qml/VpnState.qml</file>
         <file>qml/AboutDialog.qml</file>
         <file>qml/DonateDialog.qml</file>
@@ -57,7 +67,7 @@
         <file>qml/VPNSwitch.qml</file>
         <file>qml/BridgesItem.qml</file>
         <file>qml/logic.js</file>
-        <!-- to remove -->
+        <!-- end, to remove -->
 
         <file>assets/icon/png/black/vpn_off.png</file>
         <file>assets/icon/png/black/vpn_on.png</file>
diff --git a/gui/main.qml b/gui/main.qml
index 16677a27fcb8476a6e68722f8dad97d73f2be834..f847377e0a2da7006f38b7afaba2e10ef49cc3b6 100644
--- a/gui/main.qml
+++ b/gui/main.qml
@@ -1,21 +1,23 @@
+
+
 /*
  TODO (ui rewrite)
  - [x] add systray
  - [x] systray status
  - [x] splash screen
- - [ ] splash delay/transitions
- - [ ] nested states
- - [ ] splash init errors
- - [ ] font: monserrat
- - [ ] donation dialog
- - [ ] add gateway to systray
- - [ ] control actions from systray
+ - [x] splash delay/transitions
+ - [x] font: monserrat
+ - [x] nested states
+ - [x] splash init errors
  - [ ] minimize/hide from systray
- - [ ] parse ctx flags (need dialog, etc)
  - [ ] gateway selector
  - [ ] bridges
+ - [ ] control actions from systray
+ - [ ] add gateway to systray
+ - [ ] donation dialog
+ - [ ] parse ctx flags (need dialog, etc)
+ - [ ] udp support
 */
-
 import QtQuick 2.0
 import QtQuick.Controls 2.4
 import QtQuick.Dialogs 1.2
@@ -40,6 +42,9 @@ ApplicationWindow {
     Material.accent: Material.Green
 
     property var ctx
+    property var error: ""
+    property bool isDonationService: false
+    property bool showDonationReminder: false
 
     property var icons: {
         "off": "qrc:/assets/icon/png/white/vpn_off.png",
@@ -48,64 +53,77 @@ ApplicationWindow {
         "blocked": "qrc:/assets/icon/png/white/vpn_blocked.png"
     }
 
+    FontLoader {
+        id: lightFont
+        source: "qrc:/montserrat-light.ttf"
+    }
+
+    FontLoader {
+        id: boldFont
+        source: "qrc:/montserrat-bold.ttf"
+    }
+
+    font.family: lightFont.name
+
     Loader {
-	id: loader
-	asynchronous: true
-	anchors.fill: parent
+        id: loader
+        asynchronous: true
+        anchors.fill: parent
     }
 
     Systray {
-	id: systray
+        id: systray
     }
 
+
     Connections {
-	target: jsonModel
-	function onDataChanged() {
-	    ctx = JSON.parse(jsonModel.getJson())
+        target: jsonModel
+        function onDataChanged() {
+            let j = jsonModel.getJson()
             if (qmlDebug) {
-                console.debug(jsonModel.getJson())
+                console.debug(j)
             }
-
-	    // FIXME -- use nested state machines for all these cases.
-
-	    //gwSelector.model = Object.keys(ctx.locations)
-
-	    /*
-	    if (ctx.donateDialog == 'true') {
-		Logic.setNeedsDonate(true);
-	    }
-	    if (ctx.loginDialog == 'true') {
-		console.debug(jsonModel.getJson())
-		console.debug("DEBUG: should display login")
-		login.visible = true
-	    }
-	    if (ctx.loginOk == 'true') {
-		loginOk.visible = true
-	    }
-	    if (ctx.errors) {
-		login.visible = false
-		if (ctx.errors == "nohelpers") {
-		    showInitFailure(
-				qsTr("Could not find helpers. Please check your installation"))
-		} else if (ctx.errors == "nopolkit") {
-		    showInitFailure(qsTr("Could not find polkit agent."))
-		} else {
-		    showInitFailure()
-		}
-	    }
-	    if (ctx.donateURL) {
-		donateItem.visible = true
-	    }
-
-	    if (ctx.status == "on") {
-		gwNextConnectionText.visible = false
-		gwReconnectText.visible = false
-	    }
-	    */
-	}
+            ctx = JSON.parse(j)
+            if (ctx.errors) {
+                console.debug("errors, setting root.error")
+                root.error = ctx.errors
+            } else {
+                root.error = ""
+            }
+            if (ctx.donateURL) {
+                isDonationService = true;
+            }
+            if (ctx.donateDialog == 'true') {
+                showDonationReminder = true;
+            }
+            //gwSelector.model = Object.keys(ctx.locations)
+            // TODO check donation
+            //if (needsDonate && !shownDonate) {
+            //    donate.visible = true;
+            //    shownDonate = true;
+            //    // move this to onClick of "close" for widget
+            //    backend.donateSeen();
+            //}
+            // TODO refactor donate widget into main view (with close window!)
+            //if (ctx.status == "on") {
+            //    gwNextConnectionText.visible = false
+            //    gwReconnectText.visible = false
+            // when: vpn.status == "on"
+            //}
+
+            /*
+            TODO libraries need login 
+            if (ctx.loginDialog == 'true') {
+                login.visible = true
+            }
+            if (ctx.loginOk == 'true') {
+                loginOk.visible = true
+            }
+            */
+        }
     }
 
-    onSceneGraphError: function(error, msg) {
+    onSceneGraphError: function (error, msg) {
         console.debug("ERROR while initializing scene")
         console.debug(msg)
     }
diff --git a/gui/resources/alert.svg b/gui/resources/alert.svg
new file mode 100644
index 0000000000000000000000000000000000000000..cd178ebb0de174ad2913261ac010c7eee0a0176a
--- /dev/null
+++ b/gui/resources/alert.svg
@@ -0,0 +1,4 @@
+<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
+  <path fill="#494c4e" d="M12 2l10 20H2L12 2m0-2c-.758 0-1.45.428-1.79 1.106l-10 20c-.31.62-.276 1.356.09 1.946.363.59 1.007.948 1.7.948h20c.693 0 1.337-.36 1.7-.95.365-.59.4-1.325.09-1.945l-10-20C13.45.428 12.756 0 12 0z"/>
+  <path fill="#494c4e" d="M12 20c-.832 0-1.507-.672-1.507-1.5S11.168 17 12 17s1.507.672 1.507 1.5S12.832 20 12 20zm.985-4.806c-.093.47-.505.806-.985.806s-.892-.337-.985-.806l-.996-5c-.06-.293.017-.598.208-.83.19-.23.476-.364.776-.364h1.99c.302 0 .587.134.777.365.192.23.27.536.21.83l-.995 5z"/>
+</svg>
diff --git a/gui/resources/fonts/Montserrat-Regular.ttf b/gui/resources/fonts/Montserrat-Regular.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..8d443d5d56ac36091e9689cd5d1b1948d9124545
Binary files /dev/null and b/gui/resources/fonts/Montserrat-Regular.ttf differ
diff --git a/gui/resources/fonts/Montserrat-SemiBold.ttf b/gui/resources/fonts/Montserrat-SemiBold.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..f8a43f2b203054676b64e38e2b78af5468c39b6d
Binary files /dev/null and b/gui/resources/fonts/Montserrat-SemiBold.ttf differ