diff --git a/frontend/index.html b/frontend/index.html
new file mode 100644
index 0000000..0ecae7f
--- /dev/null
+++ b/frontend/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ FabledCurator
+
+
+
+
+
+
+
+
+
diff --git a/frontend/package.json b/frontend/package.json
new file mode 100644
index 0000000..32e9f00
--- /dev/null
+++ b/frontend/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "fabledcurator-frontend",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview",
+ "check": "vue-tsc --noEmit"
+ },
+ "dependencies": {
+ "vue": "^3.4.0",
+ "vue-router": "^4.3.0",
+ "pinia": "^2.1.0",
+ "vuetify": "^3.5.0",
+ "@mdi/font": "^7.4.0"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^5.0.0",
+ "vite": "^5.2.0",
+ "vue-tsc": "^2.0.0",
+ "vite-plugin-vuetify": "^2.0.0",
+ "sass": "^1.71.0"
+ }
+}
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
new file mode 100644
index 0000000..4c51eaf
--- /dev/null
+++ b/frontend/src/App.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/main.js b/frontend/src/main.js
new file mode 100644
index 0000000..0882de9
--- /dev/null
+++ b/frontend/src/main.js
@@ -0,0 +1,26 @@
+import { createApp } from 'vue'
+import { createPinia } from 'pinia'
+import { createVuetify } from 'vuetify'
+import 'vuetify/styles'
+import '@mdi/font/css/materialdesignicons.css'
+
+import App from './App.vue'
+import router from './router.js'
+import { fabledCuratorTheme } from './theme/vuetify-theme.js'
+
+const vuetify = createVuetify({
+ theme: {
+ defaultTheme: 'fabledCurator',
+ themes: { fabledCurator: fabledCuratorTheme }
+ },
+ defaults: {
+ // FabledDesignSystem: pill shape for buttons
+ VBtn: { rounded: 'pill' }
+ }
+})
+
+createApp(App)
+ .use(createPinia())
+ .use(router)
+ .use(vuetify)
+ .mount('#app')
diff --git a/frontend/src/theme/fabled-tokens.js b/frontend/src/theme/fabled-tokens.js
new file mode 100644
index 0000000..4102088
--- /dev/null
+++ b/frontend/src/theme/fabled-tokens.js
@@ -0,0 +1,41 @@
+// FabledDesignSystem tokens — mirrored from FabledDesignSystem-new/design-system.md.
+// Do not hand-edit hexes; update the source-of-truth doc and re-mirror here.
+
+export const surfaces = {
+ obsidian: '#14171A', // page background
+ iron: '#1E2228', // cards
+ slate: '#2C313A', // hovered surfaces
+ pewter: '#3F4651' // borders, ghost outlines
+}
+
+export const text = {
+ parchment: '#E8E4D8', // primary on dark
+ vellum: '#C2BFB4', // secondary
+ ash: '#9C9A92' // tertiary
+}
+
+export const action = {
+ moss: '#4A5D3F', // primary action
+ bronze: '#8B7355', // secondary action
+ pewter: '#3F4651', // tertiary/ghost
+ destructive: '#6B2118' // delete/irreversible
+}
+
+export const semantic = {
+ success: '#4A5D3F',
+ warning: '#8B6F1E',
+ error: '#C04A1F',
+ info: '#3D5A6E'
+}
+
+// Per-app signature accent. Curator's accent was added to FabledDesignSystem
+// during FC-1 (2026-05-14). Aged amber — manuscript ink, curated archive.
+export const accent = {
+ curator: '#A87338'
+}
+
+export const typography = {
+ display: 'Fraunces, Georgia, serif',
+ body: 'Inter, system-ui, sans-serif',
+ mono: '"JetBrains Mono", monospace'
+}
diff --git a/frontend/src/theme/vuetify-theme.js b/frontend/src/theme/vuetify-theme.js
new file mode 100644
index 0000000..2211e75
--- /dev/null
+++ b/frontend/src/theme/vuetify-theme.js
@@ -0,0 +1,29 @@
+import { surfaces, text, action, semantic, accent } from './fabled-tokens.js'
+
+export const fabledCuratorTheme = {
+ dark: true,
+ colors: {
+ background: surfaces.obsidian,
+ surface: surfaces.iron,
+ 'surface-bright': surfaces.slate,
+ 'surface-light': surfaces.pewter,
+
+ primary: action.moss,
+ secondary: action.bronze,
+ tertiary: action.pewter,
+
+ 'on-background': text.parchment,
+ 'on-surface': text.parchment,
+ 'on-primary': text.parchment,
+ 'on-secondary': text.parchment,
+
+ success: semantic.success,
+ warning: semantic.warning,
+ error: semantic.error,
+ info: semantic.info,
+
+ // Curator signature accent — used for nav-active state, wordmark, selection.
+ // Not on action buttons (see design-system.md "Accent usage rules").
+ accent: accent.curator
+ }
+}
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
new file mode 100644
index 0000000..b506803
--- /dev/null
+++ b/frontend/vite.config.js
@@ -0,0 +1,23 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import vuetify from 'vite-plugin-vuetify'
+
+export default defineConfig({
+ plugins: [
+ vue(),
+ vuetify({ autoImport: true })
+ ],
+ build: {
+ outDir: 'dist',
+ emptyOutDir: true,
+ sourcemap: false
+ },
+ server: {
+ port: 5173,
+ proxy: {
+ // Dev server proxies API to local Quart
+ '/api': 'http://localhost:8080',
+ '/ws': { target: 'ws://localhost:8080', ws: true }
+ }
+ }
+})