diff --git a/mosogepsch/src/jsMain/kotlin/Main.kt b/mosogepsch/src/jsMain/kotlin/Main.kt
index 81161f936458879e230e28976760685541618959..b9548d96e7ad1f633928d8f40c86f4a2e73337da 100644
--- a/mosogepsch/src/jsMain/kotlin/Main.kt
+++ b/mosogepsch/src/jsMain/kotlin/Main.kt
@@ -4,6 +4,8 @@ import app.softwork.bootstrapcompose.Color
 import components.*
 import kotlinx.browser.localStorage
 import kotlinx.browser.window
+import localization.Hungarian
+import localization.LocalLang
 import org.jetbrains.compose.web.css.*
 import org.jetbrains.compose.web.dom.*
 import org.jetbrains.compose.web.renderComposable
@@ -23,11 +25,12 @@ fun main() {
         ?: window.matchMedia("(prefers-color-scheme: dark)").matches
 
     var mosogepStyle by mutableStateOf(Style(dark))
+    val lang = Hungarian()
     renderComposable(rootElementId = "root") {
         Style(mosogepStyle)
         Style(CardStyle)
         Style(FloorStyle)
-        CompositionLocalProvider(LocalStyle provides mosogepStyle) {
+        CompositionLocalProvider(LocalStyle provides mosogepStyle, LocalLang provides lang) {
             Header {
                 Navbar(
                     attrs = {
@@ -66,7 +69,7 @@ fun main() {
             Footer(
                 attrs = { classes("mt-auto", mosogepStyle.footer) }
             ) {
-                Container { credits() }
+                credits()
             }
         }
     }
diff --git a/mosogepsch/src/jsMain/kotlin/api/Types.kt b/mosogepsch/src/jsMain/kotlin/api/Types.kt
index a8dae54dcb3b345b7e837695fd3ad2cbf7e563dc..effaf42f689649bba57592ca09f0615c053307c6 100644
--- a/mosogepsch/src/jsMain/kotlin/api/Types.kt
+++ b/mosogepsch/src/jsMain/kotlin/api/Types.kt
@@ -43,5 +43,5 @@ object UnixDateSerializer : KSerializer<Instant> {
 
     override fun serialize(encoder: Encoder, value: Instant) = encoder.encodeLong(value.epochSeconds)
 
-    override fun deserialize(decoder: Decoder): Instant = Instant.fromEpochSeconds(decoder.decodeLong())
+    override fun deserialize(decoder: Decoder): Instant = Instant.fromEpochMilliseconds(decoder.decodeLong())
 }
\ No newline at end of file
diff --git a/mosogepsch/src/jsMain/kotlin/components/Content.kt b/mosogepsch/src/jsMain/kotlin/components/Content.kt
index fdb03083b44fa631d400642a1675825884fb6eb4..c64aa22844ee8d9bf324bda9c77f801eea47482a 100644
--- a/mosogepsch/src/jsMain/kotlin/components/Content.kt
+++ b/mosogepsch/src/jsMain/kotlin/components/Content.kt
@@ -5,6 +5,7 @@ import api.Api
 import api.Machine
 import app.softwork.bootstrapcompose.Container
 import org.jetbrains.compose.web.css.*
+import org.jetbrains.compose.web.dom.Div
 
 @Composable
 fun content() {
@@ -17,6 +18,7 @@ fun content() {
             flexWrap(FlexWrap.Wrap)
             justifyContent(JustifyContent.Center)
             paddingTop(1.em)
+            paddingBottom(12.em)
         }
     }) {
         var machine by remember { mutableStateOf<Machine?>(null) }
diff --git a/mosogepsch/src/jsMain/kotlin/components/Credits.kt b/mosogepsch/src/jsMain/kotlin/components/Credits.kt
index 20e524ce2f29e9f5948c661c543122c3faacc368..e1874aaeafefd1349e1a9ae337840db5623bbc78 100644
--- a/mosogepsch/src/jsMain/kotlin/components/Credits.kt
+++ b/mosogepsch/src/jsMain/kotlin/components/Credits.kt
@@ -17,6 +17,7 @@ fun credits() {
     P(attrs = {
         style {
             textAlign("center")
+            margin(0.px)
         }
     }) {
         Text("Made by KSZK and SEM")
diff --git a/mosogepsch/src/jsMain/kotlin/components/Floor.kt b/mosogepsch/src/jsMain/kotlin/components/Floor.kt
index f29c3202b81856b4875d6357218f62a0376b71d2..51a0a8770e498ade13d1d8e806f12b51cd22f743 100644
--- a/mosogepsch/src/jsMain/kotlin/components/Floor.kt
+++ b/mosogepsch/src/jsMain/kotlin/components/Floor.kt
@@ -6,6 +6,9 @@ import api.Floor
 import api.Machine
 import api.MachineKind
 import api.MachineStatus
+import localization.LocalLang
+import localization.machineKind
+import localization.machineStatus
 import org.jetbrains.compose.web.css.*
 import org.jetbrains.compose.web.dom.*
 import styles.ColorPair
@@ -30,11 +33,13 @@ object FloorStyle: StyleSheet() {
 
     val floorNum by style {
         minWidth(2.75.ch)
+        marginBottom(0.px)
         textAlign("right")
     }
 
     val machine by style {
         flexGrow(1)
+        cursor("pointer")
     }
 
     val absCnt by style {
@@ -59,18 +64,27 @@ object FloorStyle: StyleSheet() {
         property("transition", "${styles.Style.baseTransition}, max-height 0.75s")
     }
     val underflowCard by style {
-        flexDirection(FlexDirection.Column)
+        justifyContent(JustifyContent.SpaceBetween)
+        flexDirection(FlexDirection.Row)
+        gap(1.5.em)
+        padding(1.5.em)
         margin(0.px)
         width(100.percent)
         paddingTop(5.em)
         property("transition", "${styles.Style.baseTransition}, box-shadow 0.5s")
         property("box-shadow", "0 0 1em #00000044")
     }
+    val infoDiv by style {
+        display(DisplayStyle.Flex)
+        flexDirection(FlexDirection.Column)
+        flexGrow(1)
+    }
 }
 
 @Composable
 fun floor(floor: Floor, selectedMachine: Machine?, setMachine: (Machine?)->Unit) {
 
+    val lang = LocalLang.current
     val colors = LocalStyle.current.colors
     fun MachineStatus.toColor(): ColorPair = when (this) {
         MachineStatus.Available -> ColorPair(colors.primary, colors.onPrimary)
@@ -80,7 +94,10 @@ fun floor(floor: Floor, selectedMachine: Machine?, setMachine: (Machine?)->Unit)
         MachineStatus.Available -> ColorPair(colors.primaryContainer, colors.onPrimaryContainer)
         MachineStatus.NotAvailable -> ColorPair(colors.errorContainer, colors.onErrorContainer)
     }
-    fun MachineKind.toIcon(): String { return "${this.name[0]}" }
+    fun MachineKind.toIcon(): String = when (this) {
+        MachineKind.Washer -> "washer.svg"
+        MachineKind.Dryer -> "fan.svg"
+    }
 
     val zIndex = 200 - floor.id*2
 
@@ -113,11 +130,22 @@ fun floor(floor: Floor, selectedMachine: Machine?, setMachine: (Machine?)->Unit)
                             setMachine(machine)
                         }
                     }
-                }) { H3 { Text(machine.kindOf.toIcon()) } }
+                }) {
+                    Div(
+                        attrs = {
+                            style {
+                                backgroundColor(machine.status.toColor().fg)
+                                property("mask", "url(/${machine.kindOf.toIcon()}) no-repeat center / contain")
+                                height(2.em)
+                                width(2.em)
+                            }
+                        }
+                    ) {}
+                }
             }
         }
 
-        floor.machines.forEach {
+        floor.machines.forEach { machine ->
             Div(attrs = {
                 classes(FloorStyle.absCnt)
             }) {
@@ -127,7 +155,7 @@ fun floor(floor: Floor, selectedMachine: Machine?, setMachine: (Machine?)->Unit)
                     Div(attrs = {
                         classes(FloorStyle.underflowCnt)
                         style {
-                            if (selectedMachine == it) {
+                            if (selectedMachine == machine) {
                                 maxHeight(20.em)
                             } else {
                                 maxHeight(0.px)
@@ -137,13 +165,29 @@ fun floor(floor: Floor, selectedMachine: Machine?, setMachine: (Machine?)->Unit)
                         card(attrs = {
                             classes(FloorStyle.underflowCard)
                             style {
-                                applyColorPair(it.status.toUnderColor())
-                                if (selectedMachine != it) {
+                                applyColorPair(machine.status.toUnderColor())
+                                if (selectedMachine != machine) {
                                     property("box-shadow", "none")
                                 }
                             }
                         }) {
-                            P { Text(it.status.name) }
+                            Div(
+                                attrs = {
+                                    style {
+                                        backgroundColor(machine.status.toUnderColor().fg)
+                                        property("mask", "url(/${machine.kindOf.toIcon()}) no-repeat center / contain")
+                                        height(2.em)
+                                        width(2.em)
+                                    }
+                                }
+                            ) {}
+                            Div(attrs = {
+                                classes(FloorStyle.infoDiv)
+                            }) {
+                                H5 { Text("${lang.machineKind(machine.kindOf)} ${lang.floorFormat(floor.id)}") }
+                                P { Text("${lang.lastUpdated} ${lang.formatInstant(machine.lastQueryTime)}") }
+                                P { Text(lang.machineStatus(machine.status)) }
+                            }
                         }
                     }
                 }
diff --git a/mosogepsch/src/jsMain/kotlin/components/Switch.kt b/mosogepsch/src/jsMain/kotlin/components/Switch.kt
index 7dbd297cf84bca04587dbbfedf62cbc94afb2c6e..b96df8442c3851659ba93e6899e1bc8c7e661ff0 100644
--- a/mosogepsch/src/jsMain/kotlin/components/Switch.kt
+++ b/mosogepsch/src/jsMain/kotlin/components/Switch.kt
@@ -10,11 +10,13 @@ import org.jetbrains.compose.web.dom.Div
 import org.jetbrains.compose.web.dom.Label
 import org.w3c.dom.HTMLLabelElement
 import org.w3c.dom.Text
+import styles.LocalStyle
 
 private var maxId = 0
 
 @Composable
 fun switch(label: String, value: Boolean = false, onSet: (Boolean) -> Unit) {
+    val colors = LocalStyle.current.colors
     val id = remember { "mosogep-check-${maxId++}" }
     Div(attrs = {
         classes("form-check", "form-switch")
@@ -29,6 +31,10 @@ fun switch(label: String, value: Boolean = false, onSet: (Boolean) -> Unit) {
                 classes("form-check-input")
                 id(id)
                 onChange { onSet(it.value) }
+                style {
+                    backgroundColor(if (value) colors.primary else colors.background)
+                    property("border-color", colors.primary)
+                }
             }
         )
         Label(
diff --git a/mosogepsch/src/jsMain/kotlin/localization/English.kt b/mosogepsch/src/jsMain/kotlin/localization/English.kt
new file mode 100644
index 0000000000000000000000000000000000000000..24d5163b9a2cc1e14134c2e2a4fa47b345cd312a
--- /dev/null
+++ b/mosogepsch/src/jsMain/kotlin/localization/English.kt
@@ -0,0 +1,51 @@
+package localization
+
+import androidx.compose.runtime.compositionLocalOf
+import api.Floor
+import api.MachineKind
+import api.MachineStatus
+import kotlinx.datetime.*
+import kotlin.time.Duration
+
+@OptIn(kotlin.time.ExperimentalTime::class)
+abstract class Localization {
+    open val washer = "Washer"
+    open val dryer = "Dryer"
+
+    open val available = "Currently available"
+    open val notAvailable = "Currently in use"
+
+    open val lastUpdated = "Last updated"
+    open val daysAgo = "days ago"
+
+    protected open fun timeFormat(dateTime: LocalDateTime): String = "at ${dateTime.hour.padded()}:${dateTime.minute.padded()}"
+
+    open fun floorFormat(floor: Int) = "on floor $floor"
+
+    fun formatInstant(instant: Instant): String {
+        val tz = TimeZone.currentSystemDefault()
+        val dateTime = instant.toLocalDateTime(tz)
+        val now = Clock.System.now()
+        val diff = now - instant
+        println(diff.toString())
+        if (diff < Duration.Companion.days(1)) {
+            return timeFormat(dateTime)
+        }
+        return "${diff.inWholeDays} $daysAgo"
+    }
+}
+
+class English: Localization()
+
+fun Localization.machineKind(kind: MachineKind): String = when(kind) {
+    MachineKind.Washer -> washer
+    MachineKind.Dryer -> dryer
+}
+fun Localization.machineStatus(status: MachineStatus): String = when(status) {
+    MachineStatus.Available -> available
+    MachineStatus.NotAvailable -> notAvailable
+}
+
+val LocalLang = compositionLocalOf { Hungarian() }
+
+fun Int.padded() = this.toString().padStart(2, '0')
\ No newline at end of file
diff --git a/mosogepsch/src/jsMain/kotlin/localization/Hungarian.kt b/mosogepsch/src/jsMain/kotlin/localization/Hungarian.kt
new file mode 100644
index 0000000000000000000000000000000000000000..12b632d5dc5bda4a801d9f120f5a28ef75226e6f
--- /dev/null
+++ b/mosogepsch/src/jsMain/kotlin/localization/Hungarian.kt
@@ -0,0 +1,24 @@
+package localization
+
+import kotlinx.datetime.LocalDateTime
+
+class Hungarian: Localization() {
+    override val washer = "Mosógép"
+    override val dryer = "Szárító"
+
+    override val available = "Jelenleg szabad"
+    override val notAvailable = "Jelenleg használatban"
+
+    override val lastUpdated = "Utoljára frissítve"
+    override val daysAgo = "napja"
+
+    override fun timeFormat(dateTime: LocalDateTime): String = "${dateTime.hour.padded()}:${dateTime.minute.padded()}-kor"
+    override fun floorFormat(floor: Int): String {
+        val nevelo = when(floor) {
+            1, 5 -> "az"
+            else -> "a"
+        }
+        return "$nevelo $floor. emeleten"
+    }
+
+}
\ No newline at end of file
diff --git a/mosogepsch/src/jsMain/kotlin/styles/Color.kt b/mosogepsch/src/jsMain/kotlin/styles/Color.kt
index 27fbe0d6482e2175488740b99b83bd733a53b0ac..e2eaee3ddd216bddc374961e49a72e50cc6fb1ce 100644
--- a/mosogepsch/src/jsMain/kotlin/styles/Color.kt
+++ b/mosogepsch/src/jsMain/kotlin/styles/Color.kt
@@ -4,7 +4,6 @@ import org.jetbrains.compose.web.css.CSSColorValue
 import org.jetbrains.compose.web.css.Color
 
 fun color(hex: Long): CSSColorValue {
-    println(hex.toString())
     val hexStr = hex.toString(16).padStart(6, '0')
     return Color("#$hexStr")
 }
diff --git a/mosogepsch/src/jsMain/kotlin/styles/Style.kt b/mosogepsch/src/jsMain/kotlin/styles/Style.kt
index f18c646d3ea8f761887a5dc287920ac2eda04f55..3e276ca302037f7c6ae5a77bd2a8bf09e82a6516 100644
--- a/mosogepsch/src/jsMain/kotlin/styles/Style.kt
+++ b/mosogepsch/src/jsMain/kotlin/styles/Style.kt
@@ -3,6 +3,7 @@ package styles
 
 import androidx.compose.runtime.compositionLocalOf
 import org.jetbrains.compose.web.css.*
+import org.jetbrains.compose.web.css.keywords.auto
 
 class Style(val dark: Boolean = false): StyleSheet() {
     val colors = if (dark) DarkThemeColors else LightThemeColors
@@ -16,10 +17,11 @@ class Style(val dark: Boolean = false): StyleSheet() {
         "html, body, #root" {
             position(Position.Relative)
             height(100.percent)
-            overflowY("hidden")
+            display(DisplayStyle.Flex)
+            flexDirection(FlexDirection.Column)
         }
-        "h1, h2, h3, h4, h5, h6" {
-            marginBottom(0.px)
+        "#root" {
+            overflowY("auto")
         }
         "*" {
             property("transition", baseTransition)
@@ -27,18 +29,15 @@ class Style(val dark: Boolean = false): StyleSheet() {
     }
 
     val content by style {
-        overflow("auto")
-        height(100.percent)
-        paddingBottom(footHeight * 2)
+        flexGrow(1)
     }
     val footer by style {
-        position(Position.Absolute)
-        bottom(0.px)
         width(100.percent)
         height(footHeight)
         lineHeight(footHeight)
         backgroundColor(colors.surface)
         color(colors.onSurface)
+        flexGrow(0)
         property("z-index", 2000)
     }
 }
diff --git a/mosogepsch/src/jsMain/resources/fan.svg b/mosogepsch/src/jsMain/resources/fan.svg
new file mode 100644
index 0000000000000000000000000000000000000000..748d5ab88a92e78ebc8a7854db744ebd54de854e
--- /dev/null
+++ b/mosogepsch/src/jsMain/resources/fan.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M352.57 128c-28.09 0-54.09 4.52-77.06 12.86l12.41-123.11C289 7.31 279.81-1.18 269.33.13 189.63 10.13 128 77.64 128 159.43c0 28.09 4.52 54.09 12.86 77.06L17.75 224.08C7.31 223-1.18 232.19.13 242.67c10 79.7 77.51 141.33 159.3 141.33 28.09 0 54.09-4.52 77.06-12.86l-12.41 123.11c-1.05 10.43 8.11 18.93 18.59 17.62 79.7-10 141.33-77.51 141.33-159.3 0-28.09-4.52-54.09-12.86-77.06l123.11 12.41c10.44 1.05 18.93-8.11 17.62-18.59-10-79.7-77.51-141.33-159.3-141.33zM256 288a32 32 0 1 1 32-32 32 32 0 0 1-32 32z"/></svg>
\ No newline at end of file
diff --git a/mosogepsch/src/jsMain/resources/washer.svg b/mosogepsch/src/jsMain/resources/washer.svg
new file mode 100644
index 0000000000000000000000000000000000000000..c5bb6d64cbe3552cb48fcf61a790aa6addd90227
--- /dev/null
+++ b/mosogepsch/src/jsMain/resources/washer.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M9.17 16.83c1.56 1.56 4.1 1.56 5.66 0 1.56-1.56 1.56-4.1 0-5.66l-5.66 5.66zM18 2.01L6 2c-1.11 0-2 .89-2 2v16c0 1.11.89 2 2 2h12c1.11 0 2-.89 2-2V4c0-1.11-.89-1.99-2-1.99zM10 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM7 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm5 16c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6z"/></svg>
\ No newline at end of file