diff --git a/frontend/.gitignore b/frontend/.gitignore
index cd68f14..2fbe504 100644
--- a/frontend/.gitignore
+++ b/frontend/.gitignore
@@ -37,3 +37,4 @@ __screenshots__/
# Vite
*.timestamp-*-*.mjs
+.rodney/
diff --git a/frontend/index.html b/frontend/index.html
index 9e5fc8f..09d1b1b 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -1,10 +1,9 @@
-
+
-
- Vite App
+ fete
diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico
deleted file mode 100644
index df36fcf..0000000
Binary files a/frontend/public/favicon.ico and /dev/null differ
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 7905b05..c80ecb7 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -1,85 +1,9 @@
-
-
-
-
-
-
-
-
-
- Home
- About
-
-
-
-
-
+
+
+
-
+
diff --git a/frontend/src/assets/base.css b/frontend/src/assets/base.css
deleted file mode 100644
index 8816868..0000000
--- a/frontend/src/assets/base.css
+++ /dev/null
@@ -1,86 +0,0 @@
-/* color palette from */
-:root {
- --vt-c-white: #ffffff;
- --vt-c-white-soft: #f8f8f8;
- --vt-c-white-mute: #f2f2f2;
-
- --vt-c-black: #181818;
- --vt-c-black-soft: #222222;
- --vt-c-black-mute: #282828;
-
- --vt-c-indigo: #2c3e50;
-
- --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
- --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
- --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
- --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
-
- --vt-c-text-light-1: var(--vt-c-indigo);
- --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
- --vt-c-text-dark-1: var(--vt-c-white);
- --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
-}
-
-/* semantic color variables for this project */
-:root {
- --color-background: var(--vt-c-white);
- --color-background-soft: var(--vt-c-white-soft);
- --color-background-mute: var(--vt-c-white-mute);
-
- --color-border: var(--vt-c-divider-light-2);
- --color-border-hover: var(--vt-c-divider-light-1);
-
- --color-heading: var(--vt-c-text-light-1);
- --color-text: var(--vt-c-text-light-1);
-
- --section-gap: 160px;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --color-background: var(--vt-c-black);
- --color-background-soft: var(--vt-c-black-soft);
- --color-background-mute: var(--vt-c-black-mute);
-
- --color-border: var(--vt-c-divider-dark-2);
- --color-border-hover: var(--vt-c-divider-dark-1);
-
- --color-heading: var(--vt-c-text-dark-1);
- --color-text: var(--vt-c-text-dark-2);
- }
-}
-
-*,
-*::before,
-*::after {
- box-sizing: border-box;
- margin: 0;
- font-weight: normal;
-}
-
-body {
- min-height: 100vh;
- color: var(--color-text);
- background: var(--color-background);
- transition:
- color 0.5s,
- background-color 0.5s;
- line-height: 1.6;
- font-family:
- Inter,
- -apple-system,
- BlinkMacSystemFont,
- 'Segoe UI',
- Roboto,
- Oxygen,
- Ubuntu,
- Cantarell,
- 'Fira Sans',
- 'Droid Sans',
- 'Helvetica Neue',
- sans-serif;
- font-size: 15px;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
diff --git a/frontend/src/assets/fonts/Sora-Variable.woff2 b/frontend/src/assets/fonts/Sora-Variable.woff2
new file mode 100644
index 0000000..ec8ecca
Binary files /dev/null and b/frontend/src/assets/fonts/Sora-Variable.woff2 differ
diff --git a/frontend/src/assets/logo.svg b/frontend/src/assets/logo.svg
deleted file mode 100644
index 7565660..0000000
--- a/frontend/src/assets/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css
index 36fb845..62440ad 100644
--- a/frontend/src/assets/main.css
+++ b/frontend/src/assets/main.css
@@ -1,35 +1,181 @@
-@import './base.css';
+@font-face {
+ font-family: 'Sora';
+ src: url('@/assets/fonts/Sora-Variable.woff2') format('woff2');
+ font-weight: 100 800;
+ font-display: swap;
+ font-style: normal;
+}
+
+:root {
+ /* Colors: Electric Dusk */
+ --color-gradient-start: #f06292;
+ --color-gradient-mid: #ab47bc;
+ --color-gradient-end: #5c6bc0;
+ --color-accent: #ff7043;
+ --color-text: #1c1c1e;
+ --color-text-on-gradient: #ffffff;
+ --color-surface: #fff5f8;
+ --color-card: #ffffff;
+
+ /* Gradient */
+ --gradient-primary: linear-gradient(135deg, #f06292 0%, #ab47bc 50%, #5c6bc0 100%);
+
+ /* Spacing */
+ --spacing-xs: 0.5rem;
+ --spacing-sm: 0.75rem;
+ --spacing-md: 1rem;
+ --spacing-lg: 1.2rem;
+ --spacing-xl: 1.5rem;
+ --spacing-2xl: 2rem;
+
+ /* Borders */
+ --radius-card: 14px;
+ --radius-button: 14px;
+
+ /* Shadows */
+ --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.1);
+ --shadow-button: 0 2px 8px rgba(0, 0, 0, 0.15);
+
+ /* Layout */
+ --content-max-width: 480px;
+ --content-padding: 1.2rem;
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+
+html {
+ font-family: 'Sora', system-ui, -apple-system, sans-serif;
+ font-size: 16px;
+ line-height: 1.5;
+ color: var(--color-text);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+body {
+ min-height: 100vh;
+ background: var(--gradient-primary);
+}
#app {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- font-weight: normal;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
}
-a,
-.green {
+.app-container {
+ width: 100%;
+ max-width: var(--content-max-width);
+ min-height: 100vh;
+ padding: var(--content-padding);
+ display: flex;
+ flex-direction: column;
+}
+
+/* Card-style form fields */
+.form-field {
+ background: var(--color-card);
+ border: none;
+ border-radius: var(--radius-card);
+ padding: var(--spacing-md) var(--spacing-md);
+ box-shadow: var(--shadow-card);
+ width: 100%;
+ font-family: inherit;
+ font-size: 0.95rem;
+ font-weight: 400;
+ color: var(--color-text);
+ outline: none;
+ transition: box-shadow 0.2s ease;
+}
+
+.form-field:focus {
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.18);
+}
+
+.form-field::placeholder {
+ color: #999;
+ font-weight: 400;
+}
+
+textarea.form-field {
+ resize: vertical;
+ min-height: 5rem;
+}
+
+/* Form group (label + input) */
+.form-group {
+ display: flex;
+ flex-direction: column;
+ gap: 0.35rem;
+}
+
+.form-label {
+ font-size: 0.85rem;
+ font-weight: 700;
+ color: var(--color-text-on-gradient);
+ padding-left: 0.25rem;
+}
+
+/* Primary action button */
+.btn-primary {
+ display: block;
+ width: 100%;
+ padding: var(--spacing-md) var(--spacing-lg);
+ background: var(--color-accent);
+ color: var(--color-text);
+ border: none;
+ border-radius: var(--radius-button);
+ font-family: inherit;
+ font-size: 1rem;
+ font-weight: 700;
+ cursor: pointer;
+ box-shadow: var(--shadow-button);
+ transition: opacity 0.2s ease, transform 0.1s ease;
+ text-align: center;
text-decoration: none;
- color: hsla(160, 100%, 37%, 1);
- transition: 0.4s;
- padding: 3px;
}
-@media (hover: hover) {
- a:hover {
- background-color: hsla(160, 100%, 37%, 0.2);
- }
+.btn-primary:hover {
+ opacity: 0.92;
}
-@media (min-width: 1024px) {
- body {
- display: flex;
- place-items: center;
- }
-
- #app {
- display: grid;
- grid-template-columns: 1fr 1fr;
- padding: 0 2rem;
- }
+.btn-primary:active {
+ transform: scale(0.98);
+}
+
+.btn-primary:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+}
+
+/* Error message */
+.field-error {
+ color: #fff;
+ font-size: 0.875rem;
+ font-weight: 600;
+ padding-left: 0.25rem;
+}
+
+/* Utility */
+.text-center {
+ text-align: center;
+}
+
+.visually-hidden {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
}
diff --git a/frontend/src/components/HelloWorld.vue b/frontend/src/components/HelloWorld.vue
deleted file mode 100644
index d174cf8..0000000
--- a/frontend/src/components/HelloWorld.vue
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
{{ msg }}
-
- You’ve successfully created a project with
- Vite +
- Vue 3 . What's next?
-
-
-
-
-
diff --git a/frontend/src/components/TheWelcome.vue b/frontend/src/components/TheWelcome.vue
deleted file mode 100644
index 8b731d9..0000000
--- a/frontend/src/components/TheWelcome.vue
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
-
-
-
-
-
- Documentation
-
- Vue’s
- official documentation
- provides you with all information you need to get started.
-
-
-
-
-
-
- Tooling
-
- This project is served and bundled with
- Vite . The
- recommended IDE setup is
- VSCode
- +
- Vue - Official . If you need to test your components and web pages, check out
- Vitest
- and
- Cypress
- /
- Playwright .
-
-
-
- More instructions are available in
- README.md .
-
-
-
-
-
-
- Ecosystem
-
- Get official tools and libraries for your project:
- Pinia ,
- Vue Router ,
- Vue Test Utils , and
- Vue Dev Tools . If
- you need more resources, we suggest paying
- Awesome Vue
- a visit.
-
-
-
-
-
-
- Community
-
- Got stuck? Ask your question on
- Vue Land
- (our official Discord server), or
- StackOverflow . You should also follow the official
- @vuejs.org
- Bluesky account or the
- @vuejs
- X account for latest news in the Vue world.
-
-
-
-
-
-
- Support Vue
-
- As an independent project, Vue relies on community backing for its sustainability. You can help
- us by
- becoming a sponsor .
-
-
diff --git a/frontend/src/components/WelcomeItem.vue b/frontend/src/components/WelcomeItem.vue
deleted file mode 100644
index 6d7086a..0000000
--- a/frontend/src/components/WelcomeItem.vue
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
-
diff --git a/frontend/src/components/__tests__/HelloWorld.spec.ts b/frontend/src/components/__tests__/HelloWorld.spec.ts
deleted file mode 100644
index 2533202..0000000
--- a/frontend/src/components/__tests__/HelloWorld.spec.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { describe, it, expect } from 'vitest'
-
-import { mount } from '@vue/test-utils'
-import HelloWorld from '../HelloWorld.vue'
-
-describe('HelloWorld', () => {
- it('renders properly', () => {
- const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
- expect(wrapper.text()).toContain('Hello Vitest')
- })
-})
diff --git a/frontend/src/components/icons/IconCommunity.vue b/frontend/src/components/icons/IconCommunity.vue
deleted file mode 100644
index 2dc8b05..0000000
--- a/frontend/src/components/icons/IconCommunity.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
diff --git a/frontend/src/components/icons/IconDocumentation.vue b/frontend/src/components/icons/IconDocumentation.vue
deleted file mode 100644
index 6d4791c..0000000
--- a/frontend/src/components/icons/IconDocumentation.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
diff --git a/frontend/src/components/icons/IconEcosystem.vue b/frontend/src/components/icons/IconEcosystem.vue
deleted file mode 100644
index c3a4f07..0000000
--- a/frontend/src/components/icons/IconEcosystem.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
diff --git a/frontend/src/components/icons/IconSupport.vue b/frontend/src/components/icons/IconSupport.vue
deleted file mode 100644
index 7452834..0000000
--- a/frontend/src/components/icons/IconSupport.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
diff --git a/frontend/src/components/icons/IconTooling.vue b/frontend/src/components/icons/IconTooling.vue
deleted file mode 100644
index 660598d..0000000
--- a/frontend/src/components/icons/IconTooling.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
diff --git a/frontend/src/views/AboutView.vue b/frontend/src/views/AboutView.vue
deleted file mode 100644
index 756ad2a..0000000
--- a/frontend/src/views/AboutView.vue
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
This is an about page
-
-
-
-
diff --git a/spec/design-system.md b/spec/design-system.md
new file mode 100644
index 0000000..0ccdcda
--- /dev/null
+++ b/spec/design-system.md
@@ -0,0 +1,85 @@
+# Design System
+
+This document defines the visual design language for fete. All frontend implementation must follow these specifications.
+
+## Principles
+
+- **Mobile-first / App-native feel** — not a classic website. Think installed app, not browser page.
+- **Desktop:** centered narrow column (max ~480px), gradient background fills the rest.
+- **Generous whitespace** — elements breathe, nothing cramped.
+- **WCAG AA contrast** as baseline for all color choices.
+- **Accessibility is a baseline requirement** — not an afterthought (per project statutes).
+
+## Color Palette: Electric Dusk
+
+Chosen for best balance of style, broad appeal, and accessibility.
+
+| Role | Hex | Description |
+|--------------------|-----------|--------------------|
+| Gradient Start | `#F06292` | Pink |
+| Gradient Mid | `#AB47BC` | Purple |
+| Gradient End | `#5C6BC0` | Indigo blue |
+| Accent (CTAs) | `#FF7043` | Deep orange |
+| Text (light mode) | `#1C1C1E` | Near black |
+| Text (dark mode) | `#FFFFFF` | White |
+| Surface (light) | `#FFF5F8` | Pinkish white |
+| Surface (dark) | `#1B1730` | Deep indigo-black |
+| Card (light) | `#FFFFFF` | White |
+| Card (dark) | `#2A2545` | Muted indigo |
+
+### Primary Gradient
+
+```css
+background: linear-gradient(135deg, #F06292 0%, #AB47BC 50%, #5C6BC0 100%);
+```
+
+### Usage Rules
+
+- Gradient for hero/splash areas and page backgrounds — not as direct text background for body copy.
+- Cards and content areas use solid surface colors with high-contrast text.
+- Accent color (`#FF7043`) for primary action buttons with dark text (`#1C1C1E`).
+- White text on gradient mid/end passes WCAG AA (4.82:1 and 4.86:1).
+- White text on gradient start passes AA-large (3.06:1) — use for headings 18px+ only.
+
+## Typography: Sora
+
+Contemporary geometric sans-serif with slightly rounded terminals. Modern and friendly without being childish.
+
+- **Font:** Sora
+- **License:** SIL Open Font License 1.1 (OFL)
+- **Source:** https://github.com/sora-xor/sora-font
+- **Format:** Self-hosted WOFF2. No external CDN. No Google Fonts.
+- **Weights:** 400 (Regular), 500 (Medium), 600 (SemiBold), 700 (Bold), 800 (ExtraBold)
+
+### Weight Usage
+
+| Context | Weight | Size guideline |
+|------------------|--------|-----------------|
+| Body text | 400 | 0.85–1rem |
+| Labels | 600–700| 0.8–0.9rem |
+| Headlines | 700–800| 1.2–1.6rem |
+| Buttons | 700–800| 1rem |
+| Small/meta text | 400–500| 0.75–0.85rem |
+
+## Component Patterns
+
+### Card-Style Form Fields
+
+- Rounded corners (`border-radius: 14px`)
+- Generous padding (`0.9rem 1rem`)
+- White/card-colored background on gradient pages
+- Subtle shadow (`box-shadow: 0 2px 8px rgba(0,0,0,0.1)`)
+- Bold label (font-weight 700), regular-weight input text
+
+### Buttons
+
+- Rounded corners matching card fields (`border-radius: 14px`)
+- Accent color background with dark text
+- Bold/ExtraBold weight (700–800)
+- Subtle shadow for depth
+
+### Layout
+
+- Mobile: full-width content with horizontal padding (~1.2rem)
+- Desktop: centered column, max-width ~480px, gradient background fills viewport
+- Vertical spacing between elements: ~0.75rem (compact), ~1.2rem (sections)