diff --git a/app/assets/styles/button.css b/app/assets/styles/button.css
index ebc7ca1..46e25a1 100755
--- a/app/assets/styles/button.css
+++ b/app/assets/styles/button.css
@@ -13,9 +13,51 @@
     transition: var(--transition-default);
     outline: none;
     border: none;
-    background: transparent;
+    background: var(--background);
     color: var(--color);
 
+    &.raised {
+        box-shadow: var(--box-shadow-z2);
+        padding: .5em 1.5em;
+        border-radius: var(--radius-default);
+
+        &.danger {
+            --background: var(--color-red);
+            --color: var(--color-white);
+        }
+    }
+
+    &.text {
+        --background: transparent;
+        --color: var(--color-black);
+        padding: .5em 1.5em;
+        border-radius: var(--radius-default);
+
+        &:hover {
+            --background: rgba(0, 0, 0, 0.05);
+        }
+
+        &.white {
+            --color: var(--color-white);
+        }
+
+        &.danger {
+            --color: var(--color-red);
+
+            &:hover {
+                --background: rgba(255, 0, 0, 0.1);
+            }
+        }
+    }
+
+    &.round {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        border-radius: 100%;
+        padding: .5rem;
+    }
+
     &.cta {
         background: var(--background);
         color: var(--color);
diff --git a/app/assets/styles/formInput.css b/app/assets/styles/formInput.css
index 44d228d..c207605 100755
--- a/app/assets/styles/formInput.css
+++ b/app/assets/styles/formInput.css
@@ -1,44 +1,52 @@
 .Input {
-    position: relative;
-    flex: 25% 1 0;
-    border: 2px solid var(--color-blue);
-    border-radius: var(--radius-default);
-    overflow: hidden;
-    transition: var(--transition-default);
-    outline: 0 solid var(--color-white);
+    &.error {
+        & .input-wrapper {
+            border-color: var(--color-red);
+            outline-width: 2px;
+        }
 
-    & label {
-        position: absolute;
-        left: .5rem;
-        font-size: 1.5em;
-        top: .7rem;
-        transition: var(--transition-default);
-    }
-
-    & input {
-        all: unset;
-        width: calc(100% - 1rem);
-        font-size: 1.2em;
-        padding: 1.3rem .5rem .5rem .5rem;
-        background: var(--color-white);
-
-        &[type="number"] {
-            text-align: right;
+        & span {
+            color: var(--color-red);
         }
     }
 
-    &:has(input:invalid) {
-        border-color: var(--color-red);
-        outline-width: 2px;
+    & span {
+        font-size: .65em;
     }
 
-    & input:focus,
-    & input:not(:placeholder-shown) {
-        & + label {
-            color: var(--color-main);
-            font-size: 1em;
+    & .input-wrapper {
+        position: relative;
+        flex: 25% 1 0;
+        border: 2px solid var(--color-blue);
+        border-radius: var(--radius-default);
+        overflow: hidden;
+        transition: var(--transition-default);
+        outline: 0 solid var(--color-white);
+
+        & label {
+            position: absolute;
+            font-size: .8em;
             top: .3rem;
-            right: .5rem;
+            left: .5rem;
+            transition: var(--transition-default);
+        }
+
+        & input {
+            all: unset;
+            width: calc(100% - 1rem);
+            padding: 1.3rem .5rem .5rem .5rem;
+            background: var(--color-white);
+
+            &[type="number"] {
+                text-align: right;
+            }
+        }
+
+        & input:focus,
+        & input:not(:placeholder-shown) {
+            & + label {
+                color: var(--color-main);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/app/assets/styles/general.css b/app/assets/styles/general.css
index c206ecb..f6c2d70 100755
--- a/app/assets/styles/general.css
+++ b/app/assets/styles/general.css
@@ -10,6 +10,7 @@
     --color-blue: #2e86de;
     --color-blue-dark: #1b4b7f;
     --color-grey: #c7c7c7;
+    --color-black: #333;
 
     --color-orange: #DE9C2F;
 
@@ -127,4 +128,41 @@ body {
 
 .gap-default {
     gap: 1rem;
+}
+
+.bg-blue {
+    background: var(--color-blue);
+}
+
+.bg-white {
+    background: var(--color-white);
+}
+
+.padding {
+    gap: 1rem;
+    padding: var(--padding-default);
+}
+
+dialog {
+    top: 50%;
+    left: 50%;
+    width: 100vw;
+    transform: translate(-50%, -50%);
+    border: none;
+    border-radius: var(--radius-default);
+
+    font-size: 1rem;
+
+    & header {
+        justify-content: space-between;
+        align-items: center;
+    }
+
+    & footer {
+        justify-content: space-between;
+    }
+
+    &::backdrop {
+        background: rgba(0, 0, 0, 0.5);
+    }
 }
\ No newline at end of file
diff --git a/app/assets/styles/priceCard.css b/app/assets/styles/priceCard.css
index 47acd68..9eb4269 100755
--- a/app/assets/styles/priceCard.css
+++ b/app/assets/styles/priceCard.css
@@ -11,83 +11,66 @@
         opacity: 0;
     }
 
-    &.folded {
-        grid-template-rows: auto 0fr auto;
-    }
-
     & > header {
         color: var(--color-white);
         display: flex;
         justify-content: space-between;
         align-items: center;
-        font-size: 1.3em;
+        font-size: 1.5rem;
+
+        & .icon {
+            font-size: 1.2rem;
+            cursor: pointer;
+        }
+
+        & > .name-price {
+            display: flex;
+            gap: .5rem;
+
+            & > span:nth-child(2)::before {
+                content: '•';
+                margin-right: .5rem;
+                opacity: .5;
+            }
+        }
 
         & > .Button {
             color: var(--color-white);
-            border: 2px solid var(--color-white);
         }
     }
 
-    & aside {
-        overflow: hidden;
-    }
-
-    & footer {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-
-        & > .Button.delete {
-            scale: 0;
-        }
-
-        & > .Button.deletable {
-            scale: 1;
-        }
-    }
-
-    & .padding {
-        gap: 1rem;
-        padding: var(--padding-default);
-    }
-
-    & .bg-blue {
-        background: var(--color-blue);
-    }
-
-    & .bg-white {
-        background: var(--color-white);
-    }
-
     & .wrapper {
         display: flex;
         flex-direction: row;
         width: 100%;
         gap: 1rem;
         justify-content: space-between;
+        padding-top: 0;
 
         & > * {
-            flex-basis: 25%;
-            flex-grow: 1;
+            flex-basis: 10%;
+            flex-grow: 0;
         }
 
         & > .info {
+            color: var(--color-white);
             align-items: center;
+            gap: .25rem;
 
             & > .icon {
-                color: var(--color-blue-light);
                 font-size: 2rem;
                 padding: .2rem;
             }
 
             & > .price {
-                font-size: 1.2rem;
+                display: flex;
+                align-items: center;
+                gap: .5rem;
             }
 
             & > .pro {
-                font-size: .8rem;
+                font-size: .6rem;
                 font-weight: bold;
-                color: var(--color-main-light);
             }
         }
     }
diff --git a/app/components/Pp/DeleteDialog.vue b/app/components/Pp/DeleteDialog.vue
new file mode 100644
index 0000000..dd24927
--- /dev/null
+++ b/app/components/Pp/DeleteDialog.vue
@@ -0,0 +1,39 @@
+<template>
+  <dialog
+    ref="dialog"
+    closedby="any"
+  >
+    <form method="dialog">
+      <header class="flex-row padding">
+        Wirklich löschen?
+        <PpButton class="round text">
+          <Icon name="uil:times" mode="svg" />
+        </PpButton>
+      </header>
+      <main>
+        <div class="padding flex-col">
+          <p>Bist du dir sicher, dass du diesen Eintrag löschen möchtest?</p>
+        </div>
+      </main>
+      <footer class="flex-row padding">
+          <PpButton class="text">
+            <span>Abbrechen</span>
+          </PpButton>
+        <PpButton class="danger raised" @click="$emit('delete')">
+          <span>Löschen</span>
+        </PpButton>
+      </footer>
+    </form>
+  </dialog>
+</template>
+
+<script setup lang="ts">
+type Props = {
+  currentCardIndex : number
+}
+
+defineProps<Props>()
+defineEmits(['delete'])
+
+
+</script>
\ No newline at end of file
diff --git a/app/components/Pp/FormInput.vue b/app/components/Pp/FormInput.vue
index 66c8a94..cd1ec71 100755
--- a/app/components/Pp/FormInput.vue
+++ b/app/components/Pp/FormInput.vue
@@ -1,17 +1,20 @@
 <template>
-  <div class="Input flex-col">
-    <input
+  <div class="Input">
+    <div class="input-wrapper flex-col">
+      <input
         v-model="text"
         :type="type"
-        :id="makeId()"
+        :id="id"
         :step="step"
         :min="min"
         :max="max"
         :required="required"
         placeholder=" "
         @blur="emit('blur')"
-    />
-    <label :for="makeId()">{{ label }}</label>
+      />
+      <label :for="id">{{ label }}</label>
+    </div>
+    <span v-if="message">{{ message }}</span>
   </div>
 </template>
 
@@ -22,9 +25,9 @@ type Props = {
   min ?: number
   step ?: number
   required ?: boolean
+  message ?: string
   label : string
   id : string
-  uid : string
 }
 
 const {
@@ -32,15 +35,9 @@ const {
   required = false,
   step = 0.01,
   min = 1,
-  max,
-  label,
-  id,
-  uid,
 } = defineProps<Props>()
 
 const emit = defineEmits(['blur'])
 
 const text = defineModel()
-
-const makeId = () => `${id}_${uid}`
 </script>
diff --git a/app/components/Pp/PriceCard.vue b/app/components/Pp/PriceCard.vue
index 0b495bb..7df8199 100755
--- a/app/components/Pp/PriceCard.vue
+++ b/app/components/Pp/PriceCard.vue
@@ -1,64 +1,47 @@
 <template>
-  <form
+  <article
     ref="root"
-    class="PriceCard card"
-    :class="{ folded, deleting }"
-    @submit.prevent="() => {}"
+    class="PriceCard card bg-blue"
+    :class="{ deleting }"
   >
-    <header class="padding bg-blue">
-      {{ card.name || 'Kein Name' }}
-      <PpButton
-          class="icon-button bg-main"
-          @click="folded = !folded"
-      >
-        <Icon :name="folded ? 'uil:sort' : 'uil:sorting'" mode="svg" />
-      </PpButton>
-    </header>
-    <aside>
-      <div class="input-wrapper padding bg-blue flex-col">
-        <div class="wrapper">
-          <PpFormInput v-model="card.name" label="Name" id="n" :uid="card.uuid" type="text" @blur="update" />
-          <PpFormInput v-model="card.price" label="Preis" id="p" :uid="card.uuid" type="number" :min="0.01" @blur="calculate" />
-        </div>
-        <div class="wrapper">
-          <PpFormInput v-model="card.roles" label="Rollen" id="r" :uid="card.uuid" type="number" :max="150" @blur="calculate" />
-          <PpFormInput v-model="card.sheets" label="Blätter" id="b" :uid="card.uuid" type="number" :max="500" @blur="calculate" />
-          <PpFormInput v-model="card.layers" label="Lagen" id="l" :uid="card.uuid" type="number" :max="10" @blur="calculate" />
-        </div>
+    <header class="padding">
+      <div class="name-price">
+        <span>{{ card.name || 'Kein Name' }}</span>
+        <span>{{ intl.format(+replaceComma(card.price))}}</span>
       </div>
-    </aside>
-    <main class="wrapper padding bg-white">
+      <div class="flex-row gap-default">
+        <PpButton class="icon-button" @click="update()">
+          <Icon class="icon" name="uil:pen" mode="svg" />
+        </PpButton>
+        <PpButton class="icon-button" @click="deleteCard()">
+          <Icon class="icon" name="uil:times" mode="svg" />
+        </PpButton>
+      </div>
+    </header>
+    <main class="wrapper padding">
       <div class="info flex-col">
-        <Icon class="icon" name="uil:toilet-paper" mode="svg" />
-        <span class="price">{{ intl.format(ppr) }}</span>
+        <div class="price">
+          <Icon class="icon" name="uil:toilet-paper" mode="svg" />
+          <span class="value">{{ intl.format(card.ppr) }}</span>
+        </div>
         <span class="pro">Pro 1</span>
       </div>
       <div class="info flex-col">
-        <Icon class="icon" name="uil:file-landscape" mode="svg" />
-        <span class="price">{{ intl.format(pps) }}</span>
+        <div class="price">
+          <Icon class="icon" name="uil:file-landscape" mode="svg" />
+          <span class="value">{{ intl.format(card.pps) }}</span>
+        </div>
         <span class="pro">Pro 10</span>
       </div>
       <div class="info flex-col">
-        <Icon class="icon" name="uil:layer-group" mode="svg" />
-        <span class="price">{{ intl.format(ppl) }}</span>
+        <div class="price">
+          <Icon class="icon" name="uil:layer-group" mode="svg" />
+          <span class="value">{{ intl.format(card.ppl) }}</span>
+        </div>
         <span class="pro">Pro 100</span>
       </div>
     </main>
-    <footer class="padding bg-blue flex-row">
-      <PpButton
-          class="delete"
-          :class="{ deletable }"
-          @click="deleteCard"
-      >
-        <Icon name="uil:trash" mode="svg" />
-        Entfernen
-      </PpButton>
-      <PpButton v-if="false" class="cta white">
-        <Icon name="uil:qrcode-scan" mode="svg" />
-        Scan
-      </PpButton>
-    </footer>
-  </form>
+  </article>
 </template>
 
 <script setup lang="ts">
@@ -73,43 +56,14 @@ const { card } = defineProps<Props>()
 const emit = defineEmits(['remove', 'update'])
 
 const root = ref<HTMLElement>()
-const folded = ref<boolean>(false)
 const deleting = ref<boolean>(false)
 
-const ppr = ref(card.ppr)
-const pps = ref(card.pps)
-const ppl = ref(card.ppl)
-
 const intl = Intl.NumberFormat('de-DE', {
   style: 'currency',
   currency: 'EUR',
 })
 
-const calculate = () => {
-  if (!card.price || !card.roles) return
-  ppr.value = card.price / card.roles
+const update = () => emit('update')
 
-  if (!card.sheets) {
-    update()
-    return
-  }
-  pps.value = (ppr.value / card.sheets) * 10
-
-  if(!card.layers) {
-    update()
-    return
-  }
-  ppl.value = (pps.value / card.layers) * 10
-
-  update()
-}
-
-const update = () => emit('update', { ...card, ppr: ppr.value, pps: pps.value, ppl: ppl.value })
-
-const deleteCard = async () => {
-  root.value?.addEventListener('transitionend', () => emit('remove'))
-  deleting.value = true
-}
-
-onMounted(() => folded.value = !!card.price)
+const deleteCard = () => emit('remove')
 </script>
diff --git a/app/components/Pp/PriceCardDialog.vue b/app/components/Pp/PriceCardDialog.vue
new file mode 100644
index 0000000..00dd42f
--- /dev/null
+++ b/app/components/Pp/PriceCardDialog.vue
@@ -0,0 +1,129 @@
+<template>
+  <dialog
+    ref="dialog"
+    closedby="any"
+  >
+    <form method="dialog">
+      <header class="flex-row padding">
+        {{ cardLabel }}
+        <PpButton class="round text">
+          <Icon name="uil:times" mode="svg" />
+        </PpButton>
+      </header>
+    </form>
+      <main v-if="currentCard">
+        <div class="padding flex-col">
+          <div class="flex-row gap-default">
+            <PpFormInput
+              v-model="currentCard.name"
+              id="card_name"
+              label="Name"
+              :class="{'error': !validFields.name }"
+              :message="!validFields.name ? 'Feld darf nicht leer sein.' : ''"
+            />
+            <PpFormInput
+              v-model="currentCard.price"
+              id="card_price"
+              label="Preis"
+              :class="{'error': !validFields.price }"
+              :message="!validFields.price ? 'Muss eine Zahl sein.' : ''"
+            />
+          </div>
+          <div class="flex-row gap-default">
+            <PpFormInput
+              v-model="currentCard.roles"
+              id="card_roles"
+              label="Rollen"
+              :class="{'error': !validFields.roles }"
+              :message="!validFields.roles ? 'Muss eine Ganzzahl sein.' : ''"
+            />
+            <PpFormInput
+              v-model="currentCard.sheets"
+              id="card_sheets"
+              label="Blätter"
+              :class="{'error': !validFields.sheets }"
+              :message="!validFields.sheets ? 'Muss eine Ganzzahl sein.' : ''"
+            />
+            <PpFormInput
+              v-model="currentCard.layers"
+              id="card_layers"
+              label="Lagen"
+              :class="{'error': !validFields.layers }"
+              :message="!validFields.layers ? 'Muss eine Ganzzahl sein.' : ''"
+            />
+          </div>
+        </div>
+      </main>
+      <footer class="flex-row padding">
+        <form method="dialog">
+          <PpButton class="danger text">
+            <span>Abbrechen</span>
+          </PpButton>
+        </form>
+        <PpButton class="raised" @click="validate">
+          <span>{{ cardLabel }}</span>
+        </PpButton>
+      </footer>
+  </dialog>
+</template>
+
+<script setup lang="ts">
+import type { Card } from '../../../shared/Card'
+
+type Props = {
+  currentCardIndex : number
+  currentCard ?: Card
+}
+
+const { currentCardIndex, currentCard } = defineProps<Props>()
+const emit = defineEmits(['update'])
+
+const dialog = useTemplateRef<HTMLDialogElement>('dialog')
+const cardLabel = computed(() => currentCardIndex > -1 ? 'Bearbeiten' : 'Hinzufügen')
+
+const checkPrice = () => {
+  if (!currentCard) { return false }
+  if (currentCard.price.length === 0) { return false }
+  const price = +replaceComma(currentCard.price)
+  return !isNaN(price)
+}
+
+const checkIfInteger = (toBeNumber : string) => {
+  if (toBeNumber.length === 0) { return false }
+  if (toBeNumber.includes(',') || toBeNumber.includes('.')) { return false }
+  return !isNaN(+toBeNumber)
+}
+
+const validFields = reactive({
+  name: true,
+  price: true,
+  roles: true,
+  sheets: true,
+  layers: true,
+})
+
+const validate = () => {
+  if (!currentCard) { return }
+
+  validFields.name = currentCard.name.length > 0
+  validFields.price = checkPrice()
+  validFields.roles = checkIfInteger(currentCard.roles)
+  validFields.sheets = checkIfInteger(currentCard.sheets)
+  validFields.layers = checkIfInteger(currentCard.layers)
+
+  if (Object.values(validFields).every(value => value)) {
+    emit('update')
+    dialog.value?.close()
+  }
+}
+
+onMounted(() => {
+  dialog.value?.addEventListener('close', () => {
+    validFields.name = true
+    validFields.price = true
+    validFields.roles = true
+    validFields.sheets = true
+    validFields.layers = true
+  })
+})
+</script>
\ No newline at end of file
diff --git a/app/pages/index.vue b/app/pages/index.vue
index cc1abb7..84debe6 100755
--- a/app/pages/index.vue
+++ b/app/pages/index.vue
@@ -1,4 +1,15 @@
 <template>
+  <PpDeleteDialog
+    ref="deleteModal"
+    :current-card-index="currentCardIndex"
+    @delete="removeCard(currentCardIndex)"
+  />
+  <PpPriceCardDialog
+    ref="modal"
+    :current-card="currentCard"
+    :current-card-index="currentCardIndex"
+    @update="updateCard()"
+  />
   <section class="content flex-col">
     <aside class="filter-bar">
       <PpButtonGroup
@@ -12,8 +23,8 @@
         :key="card.uuid"
         :deletable="cards.length > 1"
         :card="card"
-        @update="newCard => updateCard(newCard, index)"
-        @remove="removeCard(card)"
+        @update="openModal(false, index)"
+        @remove="openDeleteModal()"
       />
     </div>
   </section>
@@ -27,7 +38,7 @@
         aria-hidden="true"
       />
     </PpButton>
-    <PpButton class="mini-button text-white" @click="addCard">
+    <PpButton class="mini-button text-white" @click="openModal(true, -1)">
       <Icon class="icon" name="uil:plus" mode="svg" />
       <span>Hinzufügen</span>
     </PpButton>
@@ -37,17 +48,22 @@
 <script setup lang="ts">
 import type { Card } from '../../shared/Card'
 import type { Button } from '../../shared/ButtonGroup'
+import { PpPriceCardDialog, PpDeleteDialog } from '#components'
 
 const currentSort = ref(0)
 const isDirty = ref(false)
+const currentCard = ref<Card>()
+const currentCardIndex = ref<number>(-1)
+const modal = useTemplateRef<typeof PpPriceCardDialog>('modal')
+const deleteModal = useTemplateRef<typeof PpDeleteDialog>('deleteModal')
 
 const createCard = (uuid : string) : Card => ({
   uuid,
   name: '',
-  price: 0,
-  roles: 0,
-  sheets: 0,
-  layers: 0,
+  price: '',
+  roles: '',
+  sheets: '',
+  layers: '',
   ppr: 0,
   pps: 0,
   ppl: 0,
@@ -57,23 +73,51 @@ const cards = useState('cards', () => [
   createCard(crypto.randomUUID()),
 ])
 
-const addCard = () => {
-  cards.value.unshift(createCard(crypto.randomUUID()))
-  isDirty.value = true
-}
-
-const removeCard = (card : Card) => {
-  cards.value = cards.value.filter(element => element.uuid !== card.uuid)
+const addCard = (card : Card) => {
+  const price = calculate(card)
+  cards.value.unshift({ ...card, ...price })
   isDirty.value = true
   updateLocalStorage()
 }
 
-const updateCard = (card : Card, index : number) => {
-  cards.value[index] = card
+const removeCard = (index : number) => {
+  cards.value.splice(index, 1)
   isDirty.value = true
   updateLocalStorage()
 }
 
+const updateCard = () => {
+  if (currentCardIndex.value === -1) {
+    addCard(currentCard.value!)
+    return
+  }
+
+  const price = calculate(currentCard.value!)
+  const newCard = { ...currentCard.value!, ...price }
+  cards.value.splice(currentCardIndex.value, 1, newCard)
+  isDirty.value = true
+  updateLocalStorage()
+}
+
+const openModal = (createNew : boolean, index : number) => {
+  if (createNew) {
+    currentCardIndex.value = -1
+    currentCard.value = createCard(crypto.randomUUID())
+
+    modal.value?.$el.showModal()
+    return
+  }
+
+  currentCardIndex.value = index
+  currentCard.value = { ...cards.value[index]! }
+
+  modal.value?.$el.showModal()
+  return
+}
+
+const openDeleteModal = () => {
+  deleteModal.value?.$el.showModal()
+}
 
 const updateLocalStorage = () => {
   localStorage.setItem('cards', JSON.stringify(cards.value))
@@ -120,6 +164,14 @@ const sort = (index : number) => {
   isDirty.value = false
 }
 
+const calculate = (card : Card) => {
+  const ppr = +replaceComma(card.price) / +card.roles
+  const pps = (ppr / +card.sheets) * 10
+  const ppl = (pps / +card.layers) * 10
+
+  return { ppr, pps, ppl }
+}
+
 onMounted(() => {
   const cardsFromStorage = JSON.parse(localStorage.getItem('cards') ?? '[]')
   cards.value = cardsFromStorage.length !== 0 ? cardsFromStorage : cards.value
diff --git a/app/utils/number.ts b/app/utils/number.ts
new file mode 100644
index 0000000..388e4cb
--- /dev/null
+++ b/app/utils/number.ts
@@ -0,0 +1 @@
+export const replaceComma = (value: string | number) => `${value}`.replace(',', '.');
\ No newline at end of file
diff --git a/package.json b/package.json
index d90bf07..16aac4b 100755
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
     "dev:expose": "nuxt dev --host",
     "generate": "nuxt generate",
     "preview": "nuxt preview",
+    "prepare": "nuxt prepare",
     "postinstall": "nuxt prepare"
   },
   "dependencies": {
diff --git a/shared/Card.ts b/shared/Card.ts
index 4d84b22..e10e5f6 100644
--- a/shared/Card.ts
+++ b/shared/Card.ts
@@ -1,10 +1,10 @@
 export type Card = {
   uuid: string
   name: string
-  price: number
-  roles: number
-  sheets: number
-  layers: number
+  price: string
+  roles: string
+  sheets: string
+  layers: string
   ppr: number
   pps: number
   ppl: number