diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e9e30dc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:22-alpine AS builder +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY . . +RUN npm run build + +FROM nginx:alpine +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/src/assets/main.css b/src/assets/main.css index 5a08fe7..dce250f 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -1,32 +1,288 @@ @import "tailwindcss"; +@import 'https://fonts.googleapis.com/css2?family=Press+Start+2P&family=Silkscreen:wght@400;700&display=swap'; @theme { - --color-olive: #5B7440; - --color-olive-dark: #4A5F34; - --color-olive-light: #7A9B57; - --color-olive-pale: #A8C686; - --color-beige: #E8DCC8; - --color-beige-light: #F5EFE0; - --color-beige-dark: #C4B89A; - --color-orange: #E8813A; - --color-orange-light: #F4A460; - --color-orange-dark: #C0652A; - --font-pixel: "Press Start 2P", sans-serif; - --font-body: "Silkscreen", sans-serif; + --color-primary: #5B7440; + --color-primary-light: #7A9B57; + --color-primary-pale: #A8C686; + --color-accent: #E8813A; + --color-accent-light: #F4A460; + --color-accent-dark: #C0652A; + --color-surface: #E8DCC8; + --color-surface-raised: #F5EFE0; + --color-surface-sunken: #C4B89A; + --color-error: #C0392B; + --color-error-light: #E74C3C; + --color-error-dark: #922B21; + --color-white: #FAFAF5; + --color-off-white: #F0EDE4; + --font-display: 'Press Start 2P', monospace; + --font-body: 'Silkscreen', sans-serif; } -@layer base { - * { - image-rendering: pixelated; - } - - body { - font-family: var(--font-body); - transition: background-color 0.2s ease, color 0.2s ease; - } - - h1, h2, h3, h4, h5, h6 { - font-family: var(--font-pixel); - line-height: 2; - } +/* ============ BRAND OVERRIDES ============ */ +[data-brand="founderflow"] { + --color-primary: #2B4EE6; + --color-primary-light: #5475F0; + --color-primary-pale: #A0B2F8; + --color-accent: #F5C518; + --color-accent-light: #F9D75A; + --color-accent-dark: #C49A0A; } +[data-brand="founderflow"][data-theme="dark"] { + --color-primary: #5475F0; + --color-accent: #F5C518; +} + +[data-brand="neuropilot"] { + --color-primary: #4B6FA5; + --color-primary-light: #6B8BBF; + --color-primary-pale: #A8BDD8; + --color-accent: #6BAF9F; + --color-accent-light: #8EC5B9; + --color-accent-dark: #4A8070; + --color-error: #7A4A5A; + --color-error-light: #9B6678; + --color-error-dark: #5C3344; +} +[data-brand="neuropilot"][data-theme="dark"] { + --color-primary: #6B8BBF; + --color-accent: #8EC5B9; + --color-error: #9B6678; +} + +/* ============ DARK THEME ============ */ +[data-theme="dark"] { + --color-surface: #3A3528; + --color-surface-raised: #2E2A20; + --color-surface-sunken: #4A4336; + --color-error: #E74C3C; + --color-error-light: #FF6B6B; + --color-error-dark: #C0392B; + --color-white: #1A1814; + --color-off-white: #232019; +} + +/* ============ GLOBAL BASE ============ */ +* { margin: 0; padding: 0; box-sizing: border-box; border-radius: 0 !important; } + +html { font-size: 16px; } + +body { + font-family: var(--font-body); + background: var(--color-surface-raised); + color: var(--color-surface-sunken); + transition: background 0.2s ease, color 0.2s ease; + line-height: 2; +} +[data-theme="dark"] body { background: var(--color-white); color: #d4ccb8; } + +img, canvas, svg { image-rendering: pixelated; image-rendering: -moz-crisp-edges; } + +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-display); + line-height: 1.6; + color: var(--color-primary); +} +h1 { font-size: 14px; } +@media (min-width: 480px) { h1 { font-size: 16px; } } +@media (min-width: 768px) { h1 { font-size: 18px; } h2 { font-size: 14px; } } + +p, li, span { line-height: 2; } + +a { color: var(--color-accent); text-decoration: none; } +a:hover { color: var(--color-accent-light); } + +/* ============ CONTAINER ============ */ +.container { width: 100%; padding: 16px; margin: 0 auto; } +@media (min-width: 768px) { .container { padding: 24px; } } +@media (min-width: 1024px) { .container { max-width: 960px; } } +@media (min-width: 1280px) { .container { max-width: 1120px; } } + +/* ============ HEADER ============ */ +header { + background: var(--color-surface); + border-bottom: 4px solid var(--color-primary); + position: sticky; top: 0; z-index: 50; + padding: 24px 0; +} +[data-theme="dark"] header { background: var(--color-surface-sunken); } + +.header-inner { + max-width: 960px; margin: 0 auto; padding: 0 24px; + display: flex; justify-content: space-between; + align-items: center; flex-wrap: wrap; gap: 12px; +} +@media (max-width: 479px) { + .header-inner { flex-direction: column; align-items: flex-start; padding: 0 16px; gap: 8px; } +} + +/* ============ PIXEL BUTTON ============ */ +.pixel-btn { + font-family: 'Press Start 2P', monospace; + font-size: 9px; padding: 10px 16px; + border: 3px solid var(--color-primary); + background: var(--color-surface); + color: var(--color-primary); + cursor: pointer; user-select: none; + box-shadow: 3px 3px 0 var(--color-primary); + transition: all 0.1s; + display: inline-flex; align-items: center; justify-content: center; gap: 8px; + min-width: 44px; min-height: 44px; +} +.pixel-btn:hover { transform: translate(1px, 1px); box-shadow: 2px 2px 0 var(--color-primary); } +.pixel-btn:active { transform: translate(3px, 3px); box-shadow: none; } +.pixel-btn.primary { + background: var(--color-accent); color: var(--color-white); + border-color: var(--color-accent-dark); box-shadow: 3px 3px 0 var(--color-accent-dark); +} +.pixel-btn.primary:hover { box-shadow: 2px 2px 0 var(--color-accent-dark); } +.pixel-btn.primary:active { box-shadow: none; } +.pixel-btn:disabled { + color: var(--color-surface-sunken); border-color: var(--color-surface-sunken); + box-shadow: none; cursor: not-allowed; transform: none; +} +[data-theme="dark"] .pixel-btn { box-shadow: 3px 3px 0 rgba(255,255,255,0.1); } +[data-theme="dark"] .pixel-btn:hover { box-shadow: 2px 2px 0 rgba(255,255,255,0.1); } + +/* ============ CARD ============ */ +.pixel-card { + border: 4px solid var(--color-primary); + padding: 20px; background: var(--color-surface-raised); + position: relative; +} +.pixel-card::after { + content: ''; position: absolute; + top: 4px; left: 4px; right: -4px; bottom: -4px; + border: 2px solid var(--color-surface-sunken); z-index: -1; +} +@media (max-width: 479px) { + .pixel-card { padding: 16px; } + .pixel-card::after { display: none; } +} + +/* ============ INPUT ============ */ +.pixel-input { + font-family: 'Silkscreen', sans-serif; + font-size: 16px; /* prevents iOS zoom */ + border: 3px solid var(--color-primary); + padding: 12px; width: 100%; display: block; + margin-top: 8px; background: var(--color-surface-raised); + outline: none; color: inherit; min-height: 44px; +} +.pixel-input:focus { border-color: var(--color-accent); box-shadow: 2px 2px 0 var(--color-accent); } +.pixel-input.error { border-color: var(--color-error); box-shadow: 2px 2px 0 var(--color-error-dark); } +.pixel-input:disabled { + border-color: var(--color-surface-sunken); background: var(--color-surface); + color: var(--color-surface-sunken); cursor: not-allowed; +} + +/* ============ BADGE ============ */ +.pixel-badge { + display: inline-block; padding: 4px 10px; + font-family: 'Press Start 2P', monospace; + font-size: 7px; border: 2px solid; margin: 4px 4px 4px 0; +} +.badge-success { border-color: var(--color-primary); color: var(--color-primary); } +.badge-warning { border-color: var(--color-accent); color: var(--color-accent); } +.badge-info { border-color: var(--color-primary-pale); color: var(--color-primary-pale); } +.badge-error { border-color: var(--color-error); color: var(--color-error); } +[data-theme="dark"] .badge-success { color: #a8d88e; border-color: #a8d88e; } +[data-theme="dark"] .badge-warning { color: var(--color-accent-light); border-color: var(--color-accent-light); } +[data-theme="dark"] .badge-info { color: var(--color-primary-light); border-color: var(--color-primary-light); } +[data-theme="dark"] .badge-error { color: var(--color-error-light); border-color: var(--color-error-light); } + +/* ============ PROGRESS ============ */ +.pixel-progress { + height: 20px; background: var(--color-surface-raised); + border: 3px solid var(--color-primary); overflow: hidden; margin-top: 8px; +} +.pixel-progress-bar { height: 100%; background: var(--color-primary); transition: width 0.3s; } +.pixel-progress.warning .pixel-progress-bar { background: var(--color-accent); } +.pixel-progress.error .pixel-progress-bar { background: var(--color-error); } + +/* ============ DIVIDER ============ */ +.pixel-divider { + height: 4px; margin: 24px 0; + background: repeating-linear-gradient( + 90deg, var(--color-primary) 0px, var(--color-primary) 8px, + transparent 8px, transparent 16px + ); +} + +/* ============ SECTION ============ */ +.section { + background: var(--color-surface); padding: 20px; + margin-bottom: 40px; position: relative; +} +[data-theme="dark"] .section { background: var(--color-surface-sunken); } +.section::before { + content: ''; position: absolute; + top: 8px; left: 8px; right: -8px; bottom: -8px; + border: 3px solid var(--color-surface-sunken); z-index: -1; +} +[data-theme="dark"] .section::before { border-color: rgba(255,255,255,0.05); } +@media (min-width: 768px) { .section { padding: 28px; } } +@media (min-width: 1024px) { .section { padding: 32px; } } +@media (max-width: 479px) { .section::before { display: none; } } + +/* ============ PIXEL BORDER ============ */ +.pixel-border { + border: 4px solid var(--color-primary); + box-shadow: + 4px 4px 0 var(--color-primary), + -2px -2px 0 var(--color-surface-sunken), + 2px -2px 0 var(--color-surface-sunken), + -2px 2px 0 var(--color-surface-sunken); +} +[data-theme="dark"] .pixel-border { + box-shadow: 4px 4px 0 var(--color-primary), -2px -2px 0 rgba(255,255,255,0.05); +} +@media (max-width: 479px) { .pixel-border { box-shadow: 3px 3px 0 var(--color-primary); } } + +/* ============ BOTTOM TAB BAR (Mobile only) ============ */ +.tab-bar { + position: fixed; bottom: 0; left: 0; right: 0; + height: 64px; background: var(--color-surface); + border-top: 4px solid var(--color-primary); + display: flex; align-items: stretch; z-index: 100; + box-shadow: 0 -3px 0 var(--color-primary); +} +@media (min-width: 768px) { .tab-bar { display: none; } } +@media (max-width: 767px) { .page-content { padding-bottom: 72px; } } + +.tab-item { + flex: 1; display: flex; flex-direction: column; + align-items: center; justify-content: center; + gap: 4px; color: var(--color-surface-sunken); + text-decoration: none; padding: 8px 4px; + border-right: 2px solid var(--color-surface-sunken); + transition: background 0.1s; + min-width: 44px; min-height: 44px; +} +.tab-item:last-child { border-right: none; } +.tab-item:active { background: var(--color-surface-raised); } +.tab-item.active { + color: var(--color-primary); background: var(--color-surface-raised); + border-top: 3px solid var(--color-accent); margin-top: -4px; +} +.tab-icon { width: 24px; height: 24px; image-rendering: pixelated; flex-shrink: 0; } +.tab-label { + font-family: 'Press Start 2P', monospace; + font-size: 7px; line-height: 1; white-space: nowrap; + overflow: hidden; text-overflow: ellipsis; max-width: 56px; +} + +[data-theme="dark"] .tab-bar { + background: var(--color-surface-sunken); + box-shadow: 0 -3px 0 var(--color-primary); +} +[data-theme="dark"] .tab-item.active { background: var(--color-surface); } + +/* NeuroPilot variant */ +[data-brand="neuropilot"] .tab-item { border-right-color: transparent; } + +/* ============ LANGUAGE TOGGLE ============ */ +.lang-de { display: inline; } .lang-en { display: none; } +[data-lang="en"] .lang-de { display: none; } +[data-lang="en"] .lang-en { display: inline; } diff --git a/src/components/Header.vue b/src/components/Header.vue index 3e89c44..7d9f9ce 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -1,61 +1,78 @@ - -