diff --git a/src/cljs/athens/events/remote.cljs b/src/cljs/athens/events/remote.cljs
index 1c6fac5185..4e65e78317 100644
--- a/src/cljs/athens/events/remote.cljs
+++ b/src/cljs/athens/events/remote.cljs
@@ -307,3 +307,11 @@
                            ;; Remove the server event after everything is done.
                            true
                            (into [[:remote/clear-server-event event]]))]]})))
+
+;; Subs
+
+(rf/reg-sub
+  :remote/event-sync-memory-log
+  (fn [db _]
+    (when-let [event-sync (:remote/event-sync db)]
+      (event-sync/stage-log event-sync :memory))))
diff --git a/src/cljs/athens/router.cljs b/src/cljs/athens/router.cljs
index ebc2a84d9d..3943195fe3 100644
--- a/src/cljs/athens/router.cljs
+++ b/src/cljs/athens/router.cljs
@@ -156,6 +156,7 @@
 (def routes
   ["/"
    ["" {:name :home}]
+   ["quick-capture" {:name :quickcapture}]
    ["settings" {:name :settings}]
    ["pages" {:name :pages}]
    ["page-t/:title" {:name :page-by-title}]
diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs
index 7b7652a74f..8c1a546b9d 100644
--- a/src/cljs/athens/views.cljs
+++ b/src/cljs/athens/views.cljs
@@ -13,8 +13,10 @@
     [athens.views.app-toolbar :as app-toolbar]
     [athens.views.athena :refer [athena-component]]
     [athens.views.help :refer [help-popup]]
+    [athens.views.hoc.perf-mon :as perf-mon]
     [athens.views.left-sidebar :as left-sidebar]
     [athens.views.pages.core :as pages]
+    [athens.views.pages.quick-capture :as quick-capture]
     [athens.views.pages.settings :as settings]
     [athens.views.right-sidebar.core :as right-sidebar]
     [re-frame.core :as rf]))
@@ -34,6 +36,7 @@
   []
   (let [loading        (rf/subscribe [:loading?])
         modal          (rf/subscribe [:modal])
+        route-name (rf/subscribe [:current-route/name])
         right-sidebar-open? (rf/subscribe [:right-sidebar/open])
         right-sidebar-width (rf/subscribe [:right-sidebar/width])
         settings-open? (rf/subscribe [:settings/open?])]
@@ -42,52 +45,57 @@
                    (zoom))
        [:> ChakraProvider {:theme theme,
                            :bg "background.basement"}
-        [:> ContextMenuProvider
-         [:> LayoutProvider
-          [help-popup]
-          [alert]
-          [athena-component]
-          (cond
-            (and @loading @modal) [db-modal/window]
+        [:> LayoutProvider
+         [:> ContextMenuProvider
+          (if
+           (= @route-name :quickcapture)
+            [perf-mon/hoc-perfmon-no-new-tx {:span-name "quick-capture"}
+             [:f> quick-capture/quick-capture]]
+            [:<>
+             [help-popup]
+             [alert]
+             [athena-component]
+             (cond
+               (and @loading @modal) [db-modal/window]
 
-            @loading
-            [:> Center {:height "100vh"}
-             [:> Flex {:width 28
-                       :flexDirection "column"
-                       :gap 2
-                       :color "foreground.secondary"
-                       :borderRadius "lg"
-                       :placeItems "center"
-                       :placeContent "center"
-                       :height 28}
-              [:> Spinner {:size "xl"}]]]
+               @loading
+               [:> Center {:height "100vh"}
+                [:> Flex {:width 28
+                          :flexDirection "column"
+                          :gap 2
+                          :color "foreground.secondary"
+                          :borderRadius "lg"
+                          :placeItems "center"
+                          :placeContent "center"
+                          :height 28}
+                 [:> Spinner {:size "xl"}]]]
 
-            :else [:<>
-                   (when @modal
-                     [db-modal/window])
-                   (when @settings-open?
-                     [settings/page])
-                   [:> VStack {:overscrollBehavior "contain"
-                               :id "main-layout"
-                               :spacing 0
-                               :overflowY "auto"
-                               :height "100vh"
-                               :bg "background.floor"
-                               :transitionDuration "fast"
-                               :transitionProperty "background"
-                               :transitionTimingFunction "ease-in-out"
-                               :align "stretch"
-                               :position "relative"}
-                    [app-toolbar/app-toolbar]
-                    [:> HStack {:overscrollBehavior "contain"
-                                :align "stretch"
-                                :spacing 0
-                                :flex 1}
-                     [left-sidebar/left-sidebar]
-                     [:> MainContent {:rightSidebarWidth @right-sidebar-width
-                                      :isRightSidebarOpen @right-sidebar-open?}
-                      [pages/view]]
-                     [:> RightSidebarResizeControl {:rightSidebarWidth @right-sidebar-width
-                                                    :isRightSidebarOpen @right-sidebar-open?
-                                                    :onResizeSidebar #(rf/dispatch [:right-sidebar/set-width %])}]
-                     [right-sidebar/right-sidebar]]]])]]]])))
+               :else [:<>
+                      (when @modal
+                        [db-modal/window])
+                      (when @settings-open?
+                        [settings/page])
+                      [:> VStack {:overscrollBehavior "contain"
+                                  :id "main-layout"
+                                  :spacing 0
+                                  :overflowY "auto"
+                                  :height "100vh"
+                                  :bg "background.floor"
+                                  :transitionDuration "fast"
+                                  :transitionProperty "background"
+                                  :transitionTimingFunction "ease-in-out"
+                                  :align "stretch"
+                                  :position "relative"}
+                       [app-toolbar/app-toolbar]
+                       [:> HStack {:overscrollBehavior "contain"
+                                   :align "stretch"
+                                   :spacing 0
+                                   :flex 1}
+                        [left-sidebar/left-sidebar]
+                        [:> MainContent {:rightSidebarWidth @right-sidebar-width
+                                         :isRightSidebarOpen @right-sidebar-open?}
+                         [pages/view]]
+                        [:> RightSidebarResizeControl {:rightSidebarWidth @right-sidebar-width
+                                                       :isRightSidebarOpen @right-sidebar-open?
+                                                       :onResizeSidebar #(rf/dispatch [:right-sidebar/set-width %])}]
+                        [right-sidebar/right-sidebar]]]])])]]]])))
diff --git a/src/cljs/athens/views/pages/core.cljs b/src/cljs/athens/views/pages/core.cljs
index 8c39b43c09..a0ba996607 100644
--- a/src/cljs/athens/views/pages/core.cljs
+++ b/src/cljs/athens/views/pages/core.cljs
@@ -6,6 +6,7 @@
     [athens.views.pages.daily-notes :as daily-notes]
     [athens.views.pages.graph :as graph]
     [athens.views.pages.page :as page]
+    [athens.views.pages.quick-capture :as quick-capture]
     [re-frame.core :as rf]))
 
 
@@ -20,6 +21,8 @@
                        :title "Reconnecting to server..."})))
     [:<>
      (case @route-name
+       :quickcapture [perf-mon/hoc-perfmon-no-new-tx {:span-name "quick-capture"}
+                      [quick-capture/quick-capture]]
        :pages         [perf-mon/hoc-perfmon-no-new-tx {:span-name "pages/all-pages"}
                        [all-pages/page]]
        :page          [perf-mon/hoc-perfmon {:span-name "pages/page"}
diff --git a/src/cljs/athens/views/pages/quick_capture.cljs b/src/cljs/athens/views/pages/quick_capture.cljs
new file mode 100644
index 0000000000..2029b1e214
--- /dev/null
+++ b/src/cljs/athens/views/pages/quick_capture.cljs
@@ -0,0 +1,71 @@
+(ns athens.views.pages.quick-capture
+  (:require
+    [athens.common-events.graph.ops    :as graph-ops]
+    [athens.common.utils               :as utils]
+    [athens.dates                      :as dates]
+    [athens.electron.db-menu.core      :refer [db-menu]]
+    [clojure.data                      :as data]
+    ["@chakra-ui/react"                :refer [Button]]
+    ["/components/Quick/QuickCapture"  :refer [QuickCapture]]
+    ["react"                           :as react]
+    [reagent.core                      :as r]
+    [re-frame.core                     :as rf]))
+
+
+(defn quick-capture
+  []
+  (let [[notes setNotes] (react/useState [])
+        [lastSyncTime, setLastSyncTime] (react/useState nil)
+        memory-log @(rf/subscribe [:remote/event-sync-memory-log])
+        unsynced-uids (->> memory-log
+                           (map #(-> % second :event/op :op/consequences first :op/args :block/uid))
+                           (filter some?)
+                           set)
+        unsynced-uids-notes (->> notes
+                                 (filter #(-> % :isSaved false?))
+                                 (map :uid)
+                                 set)
+        mock-sync (fn [notes]
+                    (prn notes)
+                    (setNotes [])
+                    (setLastSyncTime (js/Date.now)))
+        mock-add-item (fn [string]
+                        ;; Send via reframe.
+                        (rf/dispatch [:properties/update-in [:node/title (:title (dates/get-day))]
+                                      ["last-qc-message"]
+                                      ;; TODO: need to support first/last, and deep path positions
+                                      #_["Quick Capture" current-username :last]
+                                      (fn [db uid]
+                                        (let [new-note (merge {:string string :timestamp (js/Date.now) :uid uid}
+                                                              (when-not memory-log {:isSaved true}))]
+                                          ;; Save on local comp state.
+                                          (setNotes (conj notes new-note))
+                                          ;; Save on graph.
+                                          [(graph-ops/build-block-save-op db uid string)]))]))]
+
+    (when memory-log
+      (let [[a b] (data/diff unsynced-uids unsynced-uids-notes)]
+        (when (or a b)
+          (println notes a b)
+          (setNotes (map (fn [{:keys [uid] :as x}]
+                           (cond
+                             (and a (a uid)) (assoc x :isSaved false)
+                             (and b (b uid)) (assoc x :isSaved true)
+                             :else x))
+                         notes)))))
+
+    [:<> [:> QuickCapture {:dbMenu (r/as-element [db-menu])
+                           :notes notes
+                           :lastSyncTime lastSyncTime
+                           :onAddItem mock-add-item
+                           :newEventId utils/gen-event-id}]
+     [:> Button {:position "fixed"
+                 :variant "text"
+                 :size "xs"
+                 :left "50%"
+                 :top 5
+                 :transform "translateX(-50%)"
+                 :onClick mock-sync} "mock update"]]))
+
+;; state
+;; unsaved changes
\ No newline at end of file
diff --git a/src/js/components/Quick/QuickCapture.tsx b/src/js/components/Quick/QuickCapture.tsx
new file mode 100644
index 0000000000..5d60114214
--- /dev/null
+++ b/src/js/components/Quick/QuickCapture.tsx
@@ -0,0 +1,221 @@
+import React from 'react'
+import { AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, Box, Button, FormControl, HStack, Text, Textarea, VStack } from "@chakra-ui/react"
+import { CheckmarkCircleFillIcon } from '@/Icons/Icons'
+import { AnimatePresence, motion } from 'framer-motion'
+
+const FloatingInput = (props) => {
+  const { onSubmit } = props
+  const [string, setString] = React.useState("")
+  const inputRef = React.useRef(null)
+
+  const handleSubmit = (e) => {
+    if (string.length) {
+      e.preventDefault()
+      onSubmit(string)
+      setString("")
+      inputRef.current.focus()
+    }
+  }
+
+  React.useEffect(() => {
+    inputRef.current.focus()
+  }, [])
+
+  return <HStack
+    mt="auto"
+    flex="0 0 auto"
+    position="sticky"
+    inset={0}
+    py={4}
+    top="auto"
+    align="center"
+    justifyContent="center"
+  >
+    <FormControl
+      width="100%"
+      flex="0 1 auto"
+    >
+      <Textarea
+        ref={inputRef}
+        height="20vh"
+        borderRadius="lg"
+        resize="none"
+        placeholder="Tap to begin writing"
+        border="none"
+        outline="none"
+        shadow="page"
+        _focus={{
+          outline: "none",
+          shadow: "page",
+        }}
+        background="background.attic"
+        enterkeyhint="send"
+        onKeyDown={(e) => {
+          if (e.key === "Enter") {
+            handleSubmit(e)
+          }
+        }}
+        value={string}
+        onChange={e => setString(e.target.value)}
+      />
+    </FormControl>
+  </HStack>
+}
+
+const QueuedNote = (props) => {
+  const { string, timestamp, isSaved } = props;
+  const itemRef = React.useRef(null)
+
+  React.useLayoutEffect(() => {
+    if (itemRef.current) {
+      itemRef.current.scrollIntoView({ behavior: "smooth", block: "start" })
+    }
+  }, [])
+
+  return (<VStack
+    flex="0 0 auto"
+    ref={itemRef}
+    layout
+    as={motion.div}
+    initial={{
+      opacity: 0,
+      height: 0,
+      y: "20vh",
+    }}
+    animate={{
+      opacity: 1,
+      height: "auto",
+      y: 0,
+    }}
+    exit={{
+      opacity: 0,
+      height: 0,
+      y: -200,
+      scale: 0.5,
+    }}
+    spacing={0}
+    alignSelf="stretch"
+  >
+    <VStack
+      borderRadius="lg"
+      spacing={1}
+      alignSelf="stretch"
+      align="stretch"
+      overflow="hidden"
+      background="background.upper"
+      px={4}
+      py={3}
+    >
+      <HStack
+        fontSize="xs"
+        color="foreground.secondary"
+        justifyContent="space-between"
+      >
+        <Text>{new Date(timestamp).toLocaleDateString()}</Text>
+        <Text
+          display="inline-flex"
+          gap={1}
+          alignItems="center"
+        >
+          {isSaved ? (
+            <>Saved <CheckmarkCircleFillIcon /></>) : "Waiting to save"}</Text>
+      </HStack>
+      <Text>{string}</Text></VStack>
+  </VStack>);
+}
+
+const Message = ({ children, ...props }) => <Text
+  layout
+  as={motion.p}
+  fontSize="sm"
+  textAlign="center"
+  color="foreground.secondary"
+  exit={{
+    opacity: 0,
+    height: 0,
+  }}
+  {...props}
+>{children}</Text>;
+
+export const QuickCapture = ({ dbMenu, notes, onAddItem, lastSyncTime }) => {
+  const [isSwitchDialogOpen, setIsSwitchDialogOpen] = React.useState(false);
+  const containerRef = React.useRef(null)
+  const confirmationCancelRef = React.useRef(null)
+
+  return <>
+    <style>
+      {`
+        html, body {
+          height: 100%;
+          width: 100%;
+          position: fixed;
+          overflow: hidden;
+          margin: 0;
+          padding: 0;
+        }
+      `}
+    </style>
+    <VStack
+      align="stretch"
+      backgroundAttachment="fixed"
+      pt={4}
+      overflow="hidden"
+      height="100dvh"
+      width="100vw"
+      position="relative"
+      justifyContent="flex-end"
+      sx={{
+        maskImage: "linear-gradient(to bottom, #00000000 1rem, #000000ff 3rem, #000000ff 100%)"
+      }}
+    >
+      <VStack
+        align="stretch"
+        maxHeight="100%"
+        pt={10}
+        px={4}
+        bg="linear-gradient(to bottom, #00000000 50%, #00000011)"
+        ref={containerRef}
+        overflowY="scroll"
+        overscrollBehaviorY='contain'
+      >
+        <AnimatePresence initial={true}>
+          {(notes.length) && <Message key="today">Today</Message>}
+          {lastSyncTime && <Message key="lastsynced">Last synced: {new Date(lastSyncTime).toLocaleDateString()}</Message>}
+          {notes.length && notes.map((note, index) => <QueuedNote key={note.timestamp} {...note} />)}
+          {!(notes.length || lastSyncTime) && <Message key="placeholder">Save a message to today's Daily Notes</Message>}
+          <FloatingInput onSubmit={onAddItem} />
+        </AnimatePresence>
+      </VStack>
+    </VStack>
+    <HStack position="fixed" justifyContent="space-between" inset={3} bottom="auto" as={motion.div}>
+      {dbMenu}
+      <Button
+        borderRadius="full"
+        onClick={() => setIsSwitchDialogOpen(true)}
+        size="sm"
+        sx={{
+          backdropFilter: "blur(10px)",
+        }}
+      >Switch to Athens</Button>
+    </HStack>
+    <AlertDialog
+      size="sm"
+      isOpen={isSwitchDialogOpen}
+      onClose={() => setIsSwitchDialogOpen(false)}
+      leastDestructiveRef={confirmationCancelRef}
+    >
+      <AlertDialogOverlay />
+      <AlertDialogContent py={3}>
+        <AlertDialogHeader py={1}>Switch to Athens?</AlertDialogHeader>
+        <AlertDialogBody py={1}>
+          <Text>Notes that have not been synced will be lost.</Text>
+        </AlertDialogBody>
+        <AlertDialogFooter py={1}>
+          <Button variant="secondary" ref={confirmationCancelRef} onClick={() => setIsSwitchDialogOpen(false)}>Go back</Button>
+          <Button variant="secondary" colorScheme="destructive" onClick={() => setIsSwitchDialogOpen(false)}>Switch to Athens</Button>
+        </AlertDialogFooter>
+      </AlertDialogContent>
+
+    </AlertDialog>
+  </>
+}
\ No newline at end of file
diff --git a/src/js/theme/theme.js b/src/js/theme/theme.js
index 6d4ebf9028..83248cf1ce 100644
--- a/src/js/theme/theme.js
+++ b/src/js/theme/theme.js
@@ -524,9 +524,12 @@ const components = {
       },
       dialog: {
         shadow: "dialog",
-        border: "1px solid",
-        borderColor: 'separator.divider',
-        bg: 'background.upper'
+        border: "none",
+        maxWidth: 'calc(100% - 2rem)',
+        maxHeight: 'calc(100% - 2rem)',
+        overflow: 'auto',
+        margin: "auto",
+        bg: 'background.upper',
       }
     }
   },