feat(landing): Add landing Nuxt page
This commit is contained in:
24
landing/.gitignore
vendored
Normal file
24
landing/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Nuxt dev/build outputs
|
||||||
|
.output
|
||||||
|
.data
|
||||||
|
.nuxt
|
||||||
|
.nitro
|
||||||
|
.cache
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Node dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
|
.fleet
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Local env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
1
landing/.npmrc
Normal file
1
landing/.npmrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
shamefully-hoist=true
|
||||||
1
landing/.nvmrc
Normal file
1
landing/.nvmrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
22
|
||||||
7
landing/.prettierignore
Normal file
7
landing/.prettierignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Ignore artifacts:
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
.nuxt
|
||||||
|
.output
|
||||||
|
.api-client
|
||||||
|
pnpm-lock.yaml
|
||||||
6
landing/.prettierrc
Normal file
6
landing/.prettierrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "none",
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 120
|
||||||
|
}
|
||||||
75
landing/README.md
Normal file
75
landing/README.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# Nuxt Minimal Starter
|
||||||
|
|
||||||
|
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Make sure to install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Server
|
||||||
|
|
||||||
|
Start the development server on `http://localhost:3000`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm dev
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production
|
||||||
|
|
||||||
|
Build the application for production:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm build
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Locally preview production build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run preview
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm preview
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn preview
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||||
98
landing/app/app.config.ts
Normal file
98
landing/app/app.config.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
export default defineAppConfig({
|
||||||
|
ui: {
|
||||||
|
// Primary color for the app - Teal
|
||||||
|
colors: {
|
||||||
|
primary: 'primary',
|
||||||
|
neutral: 'slate',
|
||||||
|
success: 'success',
|
||||||
|
warning: 'warning',
|
||||||
|
error: 'red'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Button customizations
|
||||||
|
button: {
|
||||||
|
defaultVariants: {
|
||||||
|
size: 'lg'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Card customizations with enhanced hover states
|
||||||
|
card: {
|
||||||
|
slots: {
|
||||||
|
root: 'rounded-2xl overflow-hidden transition-all duration-300'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Page Hero customizations for landing page
|
||||||
|
pageHero: {
|
||||||
|
slots: {
|
||||||
|
root: 'relative isolate overflow-hidden',
|
||||||
|
title: 'font-heading text-5xl sm:text-6xl lg:text-7xl text-pretty tracking-tight font-bold text-highlighted',
|
||||||
|
description: 'text-lg sm:text-xl text-muted max-w-3xl'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Page Section customizations
|
||||||
|
pageSection: {
|
||||||
|
slots: {
|
||||||
|
title: 'font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-highlighted',
|
||||||
|
description: 'text-base sm:text-lg text-muted'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Page Feature customizations
|
||||||
|
pageFeature: {
|
||||||
|
slots: {
|
||||||
|
title: 'text-lg font-semibold text-highlighted',
|
||||||
|
description: 'text-base text-muted'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Page Card customizations
|
||||||
|
pageCard: {
|
||||||
|
slots: {
|
||||||
|
root: 'rounded-2xl transition-all duration-300',
|
||||||
|
title: 'text-lg font-semibold text-highlighted',
|
||||||
|
description: 'text-base text-muted'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Page CTA customizations
|
||||||
|
pageCTA: {
|
||||||
|
slots: {
|
||||||
|
title: 'font-heading text-3xl sm:text-4xl text-pretty tracking-tight font-bold',
|
||||||
|
description: 'text-base sm:text-lg'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Header customizations - transparent with blur
|
||||||
|
header: {
|
||||||
|
slots: {
|
||||||
|
root: 'bg-white/80 dark:bg-gray-950/80 backdrop-blur-xl border-b border-gray-200/50 dark:border-gray-800/50',
|
||||||
|
title: 'font-heading text-xl font-bold'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Footer customizations
|
||||||
|
footer: {
|
||||||
|
slots: {
|
||||||
|
root: 'border-t border-gray-200 dark:border-gray-800'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Input customizations for newsletter form
|
||||||
|
input: {
|
||||||
|
defaultVariants: {
|
||||||
|
size: 'lg'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Accordion customizations
|
||||||
|
accordion: {
|
||||||
|
slots: {
|
||||||
|
trigger: 'text-base font-medium',
|
||||||
|
content: 'text-base text-muted'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
222
landing/app/app.vue
Normal file
222
landing/app/app.vue
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
<template>
|
||||||
|
<UApp>
|
||||||
|
<!-- Skip link for accessibility -->
|
||||||
|
<a href="#main-content" class="skip-link"> Zum Hauptinhalt springen </a>
|
||||||
|
|
||||||
|
<NuxtRouteAnnouncer />
|
||||||
|
|
||||||
|
<!-- Header with transparent background and blur on scroll -->
|
||||||
|
<UHeader
|
||||||
|
:title="'LegalConsentHub'"
|
||||||
|
:ui="{
|
||||||
|
root: [
|
||||||
|
'fixed top-0 left-0 right-0 z-50 transition-all duration-300',
|
||||||
|
isScrolled
|
||||||
|
? 'bg-white/90 dark:bg-gray-950/90 backdrop-blur-xl shadow-sm border-b border-gray-200/50 dark:border-gray-800/50'
|
||||||
|
: 'bg-transparent border-transparent'
|
||||||
|
].join(' ')
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<NuxtLink to="/" class="flex items-center gap-3 group">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center shadow-lg shadow-primary-500/25 group-hover:shadow-primary-500/40 transition-shadow"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-scale" class="w-5 h-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="font-heading text-xl font-bold bg-gradient-to-r from-primary-600 to-cyan-600 bg-clip-text text-transparent"
|
||||||
|
>
|
||||||
|
LegalConsentHub
|
||||||
|
</span>
|
||||||
|
</NuxtLink>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<UNavigationMenu
|
||||||
|
:items="navigationItems"
|
||||||
|
:ui="{
|
||||||
|
link: 'text-gray-700 dark:text-gray-200 hover:text-primary-600 dark:hover:text-primary-400 font-medium transition-colors'
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<template #right>
|
||||||
|
<UColorModeButton
|
||||||
|
:ui="{
|
||||||
|
base: 'text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400'
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<UButton
|
||||||
|
to="#newsletter"
|
||||||
|
class="btn-gradient px-5 py-2.5 rounded-xl font-semibold shadow-lg shadow-primary-500/25 hover:shadow-primary-500/40 transition-shadow"
|
||||||
|
>
|
||||||
|
<span>Informiert bleiben</span>
|
||||||
|
</UButton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #body>
|
||||||
|
<UNavigationMenu
|
||||||
|
:items="navigationItems"
|
||||||
|
orientation="vertical"
|
||||||
|
class="-mx-2.5"
|
||||||
|
:ui="{
|
||||||
|
link: 'text-gray-700 dark:text-gray-200 hover:text-primary-600 dark:hover:text-primary-400 font-medium'
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div class="mt-6 pt-6 border-t border-gray-200 dark:border-gray-800">
|
||||||
|
<UButton to="#newsletter" size="lg" block class="btn-gradient rounded-xl font-semibold">
|
||||||
|
Informiert bleiben
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UHeader>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<UMain id="main-content">
|
||||||
|
<NuxtPage />
|
||||||
|
</UMain>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-800">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 lg:py-16">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-8 lg:gap-12">
|
||||||
|
<!-- Brand column -->
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<NuxtLink to="/" class="flex items-center gap-3 mb-4">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-scale" class="w-5 h-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<span class="font-heading text-xl font-bold text-gray-900 dark:text-white"> LegalConsentHub </span>
|
||||||
|
</NuxtLink>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 max-w-sm mb-6">
|
||||||
|
Digitale Mitbestimmung für IT- und KI-Systeme. Strukturierte Prozesse, revisionssichere Dokumentation.
|
||||||
|
</p>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<UButton
|
||||||
|
icon="i-lucide-linkedin"
|
||||||
|
color="neutral"
|
||||||
|
variant="ghost"
|
||||||
|
to="https://linkedin.com"
|
||||||
|
target="_blank"
|
||||||
|
aria-label="LinkedIn"
|
||||||
|
class="hover:text-primary-600 dark:hover:text-primary-400"
|
||||||
|
/>
|
||||||
|
<UButton
|
||||||
|
icon="i-lucide-mail"
|
||||||
|
color="neutral"
|
||||||
|
variant="ghost"
|
||||||
|
to="mailto:info@legalconsenthub.de"
|
||||||
|
aria-label="E-Mail"
|
||||||
|
class="hover:text-primary-600 dark:hover:text-primary-400"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Links column -->
|
||||||
|
<div>
|
||||||
|
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">Navigation</h4>
|
||||||
|
<ul class="space-y-3">
|
||||||
|
<li v-for="item in navigationItems" :key="item.label">
|
||||||
|
<NuxtLink
|
||||||
|
:to="item.to"
|
||||||
|
class="text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</NuxtLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Legal column -->
|
||||||
|
<div>
|
||||||
|
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">Rechtliches</h4>
|
||||||
|
<ul class="space-y-3">
|
||||||
|
<li v-for="item in footerLinks" :key="item.label">
|
||||||
|
<NuxtLink
|
||||||
|
:to="item.to"
|
||||||
|
class="text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</NuxtLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bottom bar -->
|
||||||
|
<div class="mt-12 pt-8 border-t border-gray-200 dark:border-gray-800">
|
||||||
|
<div class="flex flex-col sm:flex-row justify-between items-center gap-4">
|
||||||
|
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
© {{ new Date().getFullYear() }} LegalConsentHub. Alle Rechte vorbehalten.
|
||||||
|
</p>
|
||||||
|
<div class="flex items-center gap-6 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<UIcon name="i-lucide-server" class="w-4 h-4" />
|
||||||
|
<span>Hosted in Germany</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<UIcon name="i-lucide-shield-check" class="w-4 h-4" />
|
||||||
|
<span>DSGVO-konform</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</UApp>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||||
|
|
||||||
|
// Track scroll position for header styling
|
||||||
|
const isScrolled = ref(false)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
isScrolled.value = window.scrollY > 50
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('scroll', handleScroll, { passive: true })
|
||||||
|
handleScroll() // Check initial position
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('scroll', handleScroll)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const navigationItems = computed<NavigationMenuItem[]>(() => [
|
||||||
|
{
|
||||||
|
label: 'Für Betriebsräte',
|
||||||
|
to: '#betriebsraete'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Für Unternehmen',
|
||||||
|
to: '#unternehmen'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Features',
|
||||||
|
to: '#features'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Kontakt',
|
||||||
|
to: '#kontakt'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const footerLinks = computed<NavigationMenuItem[]>(() => [
|
||||||
|
{
|
||||||
|
label: 'Impressum',
|
||||||
|
to: '/impressum'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Datenschutz',
|
||||||
|
to: '/datenschutz'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'AGB',
|
||||||
|
to: '/agb'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
</script>
|
||||||
820
landing/app/assets/css/main.css
Normal file
820
landing/app/assets/css/main.css
Normal file
@@ -0,0 +1,820 @@
|
|||||||
|
@import 'tailwindcss';
|
||||||
|
@import '@nuxt/ui';
|
||||||
|
|
||||||
|
/* Theme configuration with new teal/cyan/violet palette */
|
||||||
|
@theme {
|
||||||
|
/* Typography - Bricolage Grotesque for headings, DM Sans for body */
|
||||||
|
--font-sans: 'DM Sans', system-ui, sans-serif;
|
||||||
|
--font-heading: 'Bricolage Grotesque', system-ui, sans-serif;
|
||||||
|
|
||||||
|
/* Primary color - Teal/Cyan gradient base */
|
||||||
|
--color-primary-50: #f0fdfa;
|
||||||
|
--color-primary-100: #ccfbf1;
|
||||||
|
--color-primary-200: #99f6e4;
|
||||||
|
--color-primary-300: #5eead4;
|
||||||
|
--color-primary-400: #2dd4bf;
|
||||||
|
--color-primary-500: #14b8a6;
|
||||||
|
--color-primary-600: #0d9488;
|
||||||
|
--color-primary-700: #0f766e;
|
||||||
|
--color-primary-800: #115e59;
|
||||||
|
--color-primary-900: #134e4a;
|
||||||
|
--color-primary-950: #042f2e;
|
||||||
|
|
||||||
|
/* Accent color - Violet for highlights */
|
||||||
|
--color-accent-50: #f5f3ff;
|
||||||
|
--color-accent-100: #ede9fe;
|
||||||
|
--color-accent-200: #ddd6fe;
|
||||||
|
--color-accent-300: #c4b5fd;
|
||||||
|
--color-accent-400: #a78bfa;
|
||||||
|
--color-accent-500: #8b5cf6;
|
||||||
|
--color-accent-600: #7c3aed;
|
||||||
|
--color-accent-700: #6d28d9;
|
||||||
|
--color-accent-800: #5b21b6;
|
||||||
|
--color-accent-900: #4c1d95;
|
||||||
|
--color-accent-950: #2e1065;
|
||||||
|
|
||||||
|
/* Cyan for gradient effects */
|
||||||
|
--color-cyan-50: #ecfeff;
|
||||||
|
--color-cyan-100: #cffafe;
|
||||||
|
--color-cyan-200: #a5f3fc;
|
||||||
|
--color-cyan-300: #67e8f9;
|
||||||
|
--color-cyan-400: #22d3ee;
|
||||||
|
--color-cyan-500: #06b6d4;
|
||||||
|
--color-cyan-600: #0891b2;
|
||||||
|
--color-cyan-700: #0e7490;
|
||||||
|
--color-cyan-800: #155e75;
|
||||||
|
--color-cyan-900: #164e63;
|
||||||
|
--color-cyan-950: #083344;
|
||||||
|
|
||||||
|
/* Success color - Emerald */
|
||||||
|
--color-success-50: #ecfdf5;
|
||||||
|
--color-success-100: #d1fae5;
|
||||||
|
--color-success-200: #a7f3d0;
|
||||||
|
--color-success-300: #6ee7b7;
|
||||||
|
--color-success-400: #34d399;
|
||||||
|
--color-success-500: #10b981;
|
||||||
|
--color-success-600: #059669;
|
||||||
|
--color-success-700: #047857;
|
||||||
|
--color-success-800: #065f46;
|
||||||
|
--color-success-900: #064e3b;
|
||||||
|
--color-success-950: #022c22;
|
||||||
|
|
||||||
|
/* Warning color - Amber */
|
||||||
|
--color-warning-50: #fffbeb;
|
||||||
|
--color-warning-100: #fef3c7;
|
||||||
|
--color-warning-200: #fde68a;
|
||||||
|
--color-warning-300: #fcd34d;
|
||||||
|
--color-warning-400: #fbbf24;
|
||||||
|
--color-warning-500: #f59e0b;
|
||||||
|
--color-warning-600: #d97706;
|
||||||
|
--color-warning-700: #b45309;
|
||||||
|
--color-warning-800: #92400e;
|
||||||
|
--color-warning-900: #78350f;
|
||||||
|
--color-warning-950: #451a03;
|
||||||
|
|
||||||
|
/* Animation durations */
|
||||||
|
--animate-duration-slow: 1s;
|
||||||
|
--animate-duration-normal: 0.5s;
|
||||||
|
--animate-duration-fast: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Heading styles with Bricolage Grotesque */
|
||||||
|
.font-heading {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gradient text effect */
|
||||||
|
.gradient-text {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
var(--color-primary-500) 0%,
|
||||||
|
var(--color-cyan-500) 50%,
|
||||||
|
var(--color-accent-500) 100%
|
||||||
|
);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-text-teal {
|
||||||
|
background: linear-gradient(135deg, var(--color-primary-600) 0%, var(--color-cyan-500) 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
ANIMATIONS
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* Fade in up animation */
|
||||||
|
@keyframes fade-in-up {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(30px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fade in animation */
|
||||||
|
@keyframes fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Float animation for orbs */
|
||||||
|
@keyframes orb-float {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translate(0, 0) scale(1);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: translate(10px, -20px) scale(1.05);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translate(-5px, -10px) scale(0.95);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: translate(-15px, -25px) scale(1.02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Slower float for large elements - more noticeable movement */
|
||||||
|
@keyframes float-slow {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(-15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fast float for small elements */
|
||||||
|
@keyframes float-fast {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translateY(0) rotate(0deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(-10px) rotate(2deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gradient rotation for backgrounds */
|
||||||
|
@keyframes gradient-rotate {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shimmer effect */
|
||||||
|
@keyframes shimmer {
|
||||||
|
0% {
|
||||||
|
background-position: -200% 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 200% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pulse glow effect */
|
||||||
|
@keyframes pulse-glow {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 0.5;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.8;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Particle drift */
|
||||||
|
@keyframes particle-drift {
|
||||||
|
0% {
|
||||||
|
transform: translate(0, 0) rotate(0deg);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate(var(--drift-x, 100px), var(--drift-y, -100px)) rotate(360deg);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scale in animation */
|
||||||
|
@keyframes scale-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Border gradient animation */
|
||||||
|
@keyframes border-dance {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-position: 100% 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count up number animation */
|
||||||
|
@keyframes count-pulse {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tilt hover animation */
|
||||||
|
@keyframes tilt-hover {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: perspective(1000px) rotateX(0deg) rotateY(0deg);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: perspective(1000px) rotateX(2deg) rotateY(-2deg);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: perspective(1000px) rotateX(-2deg) rotateY(2deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
ANIMATION UTILITY CLASSES
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.animate-fade-in-up {
|
||||||
|
animation: fade-in-up 0.7s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in {
|
||||||
|
animation: fade-in 0.5s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-orb-float {
|
||||||
|
animation: orb-float 20s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-float-slow {
|
||||||
|
animation: float-slow 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-float-fast {
|
||||||
|
animation: float-fast 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-gradient-rotate {
|
||||||
|
animation: gradient-rotate 20s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-shimmer {
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: shimmer 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-pulse-glow {
|
||||||
|
animation: pulse-glow 3s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-scale-in {
|
||||||
|
animation: scale-in 0.6s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-border-dance {
|
||||||
|
background-size: 200% 200%;
|
||||||
|
animation: border-dance 4s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-tilt-hover {
|
||||||
|
animation: tilt-hover 6s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Staggered animation delays */
|
||||||
|
.delay-75 {
|
||||||
|
animation-delay: 75ms;
|
||||||
|
}
|
||||||
|
.delay-100 {
|
||||||
|
animation-delay: 100ms;
|
||||||
|
}
|
||||||
|
.delay-150 {
|
||||||
|
animation-delay: 150ms;
|
||||||
|
}
|
||||||
|
.delay-200 {
|
||||||
|
animation-delay: 200ms;
|
||||||
|
}
|
||||||
|
.delay-300 {
|
||||||
|
animation-delay: 300ms;
|
||||||
|
}
|
||||||
|
.delay-400 {
|
||||||
|
animation-delay: 400ms;
|
||||||
|
}
|
||||||
|
.delay-500 {
|
||||||
|
animation-delay: 500ms;
|
||||||
|
}
|
||||||
|
.delay-600 {
|
||||||
|
animation-delay: 600ms;
|
||||||
|
}
|
||||||
|
.delay-700 {
|
||||||
|
animation-delay: 700ms;
|
||||||
|
}
|
||||||
|
.delay-800 {
|
||||||
|
animation-delay: 800ms;
|
||||||
|
}
|
||||||
|
.delay-1000 {
|
||||||
|
animation-delay: 1000ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initial state for animated elements */
|
||||||
|
.animate-on-scroll {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-on-scroll.is-visible {
|
||||||
|
animation: fade-in-up 0.7s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
REDUCED MOTION SUPPORT
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
animation-duration: 0.01ms !important;
|
||||||
|
animation-iteration-count: 1 !important;
|
||||||
|
transition-duration: 0.01ms !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-orb-float,
|
||||||
|
.animate-float-slow,
|
||||||
|
.animate-float-fast,
|
||||||
|
.animate-gradient-rotate,
|
||||||
|
.animate-shimmer,
|
||||||
|
.animate-pulse-glow,
|
||||||
|
.animate-border-dance,
|
||||||
|
.animate-tilt-hover {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
GRADIENT BACKGROUNDS
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* Light hero gradient with orbs */
|
||||||
|
.hero-gradient-light {
|
||||||
|
background: linear-gradient(180deg, #ffffff 0%, #f0fdfa 50%, #ecfeff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark hero gradient */
|
||||||
|
.dark .hero-gradient-light {
|
||||||
|
background: linear-gradient(180deg, #0a0a0a 0%, #042f2e 50%, #083344 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gradient orb styles */
|
||||||
|
.gradient-orb {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
filter: blur(80px);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-orb-teal {
|
||||||
|
background: linear-gradient(135deg, var(--color-primary-400), var(--color-cyan-400));
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-orb-violet {
|
||||||
|
background: linear-gradient(135deg, var(--color-accent-400), var(--color-accent-600));
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-orb-cyan {
|
||||||
|
background: linear-gradient(135deg, var(--color-cyan-300), var(--color-primary-400));
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .gradient-orb {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mesh gradient for CTAs */
|
||||||
|
.mesh-gradient-cta {
|
||||||
|
background:
|
||||||
|
radial-gradient(at 40% 20%, var(--color-primary-500) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 80% 0%, var(--color-cyan-400) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 0% 50%, var(--color-accent-500) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 80% 50%, var(--color-primary-400) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 0% 100%, var(--color-cyan-500) 0px, transparent 50%),
|
||||||
|
linear-gradient(135deg, var(--color-primary-600) 0%, var(--color-accent-600) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
GLASS MORPHISM
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.glass {
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
-webkit-backdrop-filter: blur(20px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .glass {
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-subtle {
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .glass-subtle {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
CARD EFFECTS
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* Card with gradient border on hover */
|
||||||
|
.card-gradient-border {
|
||||||
|
position: relative;
|
||||||
|
background: white;
|
||||||
|
border-radius: 1rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-gradient-border::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: -2px;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: linear-gradient(135deg, var(--color-primary-400), var(--color-cyan-400), var(--color-accent-400));
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-gradient-border:hover::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .card-gradient-border {
|
||||||
|
background: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card hover lift effect - subtle version without clipping issues */
|
||||||
|
.card-hover-lift {
|
||||||
|
transition:
|
||||||
|
transform 0.3s ease,
|
||||||
|
box-shadow 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover-lift:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow:
|
||||||
|
0 10px 25px -5px rgba(0, 0, 0, 0.1),
|
||||||
|
0 8px 10px -6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spotlight effect for cards */
|
||||||
|
.card-spotlight {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-spotlight::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: radial-gradient(
|
||||||
|
600px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
|
||||||
|
rgba(20, 184, 166, 0.1),
|
||||||
|
transparent 40%
|
||||||
|
);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-spotlight:hover::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3D tilt effect */
|
||||||
|
.card-3d {
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
perspective: 1000px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-3d-inner {
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-3d:hover .card-3d-inner {
|
||||||
|
transform: rotateX(5deg) rotateY(-5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
BUTTON STYLES
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* Gradient button */
|
||||||
|
.btn-gradient {
|
||||||
|
background: linear-gradient(135deg, var(--color-primary-500) 0%, var(--color-cyan-500) 100%);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-gradient::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(135deg, var(--color-cyan-500) 0%, var(--color-accent-500) 100%);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-gradient:hover::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-gradient span {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Outline gradient button */
|
||||||
|
.btn-outline-gradient {
|
||||||
|
position: relative;
|
||||||
|
background: transparent;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(white, white), linear-gradient(135deg, var(--color-primary-500), var(--color-cyan-500));
|
||||||
|
background-origin: border-box;
|
||||||
|
background-clip: padding-box, border-box;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .btn-outline-gradient {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(#1a1a1a, #1a1a1a), linear-gradient(135deg, var(--color-primary-500), var(--color-cyan-500));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline-gradient:hover {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(var(--color-primary-50), var(--color-primary-50)),
|
||||||
|
linear-gradient(135deg, var(--color-primary-500), var(--color-cyan-500));
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .btn-outline-gradient:hover {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(var(--color-primary-950), var(--color-primary-950)),
|
||||||
|
linear-gradient(135deg, var(--color-primary-500), var(--color-cyan-500));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
DECORATIVE ELEMENTS
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* Dots pattern */
|
||||||
|
.dots-pattern {
|
||||||
|
background-image: radial-gradient(var(--color-primary-200) 1px, transparent 1px);
|
||||||
|
background-size: 24px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .dots-pattern {
|
||||||
|
background-image: radial-gradient(var(--color-primary-800) 1px, transparent 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grid pattern */
|
||||||
|
.grid-pattern {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(to right, var(--color-primary-100) 1px, transparent 1px),
|
||||||
|
linear-gradient(to bottom, var(--color-primary-100) 1px, transparent 1px);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .grid-pattern {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(to right, var(--color-primary-900) 1px, transparent 1px),
|
||||||
|
linear-gradient(to bottom, var(--color-primary-900) 1px, transparent 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section divider with gradient */
|
||||||
|
.section-divider {
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(90deg, transparent, var(--color-primary-300), var(--color-cyan-300), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .section-divider {
|
||||||
|
background: linear-gradient(90deg, transparent, var(--color-primary-700), var(--color-cyan-700), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gradient line accent */
|
||||||
|
.gradient-line {
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: linear-gradient(90deg, var(--color-primary-500), var(--color-cyan-500), var(--color-accent-500));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
ACCESSIBILITY
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* Focus styles */
|
||||||
|
:focus-visible {
|
||||||
|
outline: 2px solid var(--color-primary-500);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip link */
|
||||||
|
.skip-link {
|
||||||
|
position: absolute;
|
||||||
|
top: -40px;
|
||||||
|
left: 0;
|
||||||
|
background: var(--color-primary-600);
|
||||||
|
color: white;
|
||||||
|
padding: 8px 16px;
|
||||||
|
z-index: 100;
|
||||||
|
transition: top 0.3s;
|
||||||
|
border-radius: 0 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-link:focus {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
PARTICLES (for newsletter section)
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.particle {
|
||||||
|
position: absolute;
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--color-primary-400);
|
||||||
|
opacity: 0;
|
||||||
|
animation: particle-drift 8s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.particle:nth-child(1) {
|
||||||
|
--drift-x: 80px;
|
||||||
|
--drift-y: -120px;
|
||||||
|
animation-delay: 0s;
|
||||||
|
left: 10%;
|
||||||
|
top: 80%;
|
||||||
|
}
|
||||||
|
.particle:nth-child(2) {
|
||||||
|
--drift-x: -60px;
|
||||||
|
--drift-y: -100px;
|
||||||
|
animation-delay: 1s;
|
||||||
|
left: 20%;
|
||||||
|
top: 70%;
|
||||||
|
}
|
||||||
|
.particle:nth-child(3) {
|
||||||
|
--drift-x: 100px;
|
||||||
|
--drift-y: -80px;
|
||||||
|
animation-delay: 2s;
|
||||||
|
left: 80%;
|
||||||
|
top: 90%;
|
||||||
|
}
|
||||||
|
.particle:nth-child(4) {
|
||||||
|
--drift-x: -80px;
|
||||||
|
--drift-y: -140px;
|
||||||
|
animation-delay: 3s;
|
||||||
|
left: 70%;
|
||||||
|
top: 75%;
|
||||||
|
}
|
||||||
|
.particle:nth-child(5) {
|
||||||
|
--drift-x: 60px;
|
||||||
|
--drift-y: -90px;
|
||||||
|
animation-delay: 4s;
|
||||||
|
left: 30%;
|
||||||
|
top: 85%;
|
||||||
|
}
|
||||||
|
.particle:nth-child(6) {
|
||||||
|
--drift-x: -100px;
|
||||||
|
--drift-y: -110px;
|
||||||
|
animation-delay: 5s;
|
||||||
|
left: 90%;
|
||||||
|
top: 80%;
|
||||||
|
}
|
||||||
|
.particle:nth-child(7) {
|
||||||
|
--drift-x: 40px;
|
||||||
|
--drift-y: -130px;
|
||||||
|
animation-delay: 6s;
|
||||||
|
left: 50%;
|
||||||
|
top: 95%;
|
||||||
|
}
|
||||||
|
.particle:nth-child(8) {
|
||||||
|
--drift-x: -40px;
|
||||||
|
--drift-y: -70px;
|
||||||
|
animation-delay: 7s;
|
||||||
|
left: 40%;
|
||||||
|
top: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Particle color variations */
|
||||||
|
.particle:nth-child(odd) {
|
||||||
|
background: var(--color-cyan-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.particle:nth-child(3n) {
|
||||||
|
background: var(--color-accent-400);
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
BENTO GRID
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.bento-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
grid-auto-rows: minmax(200px, auto);
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-item-large {
|
||||||
|
grid-column: span 2;
|
||||||
|
grid-row: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-item-tall {
|
||||||
|
grid-row: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-item-wide {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.bento-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-item-large {
|
||||||
|
grid-column: span 2;
|
||||||
|
grid-row: span 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.bento-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-item-large,
|
||||||
|
.bento-item-wide {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-item-tall {
|
||||||
|
grid-row: span 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
123
landing/app/components/landing/AdditionalFeatures.vue
Normal file
123
landing/app/components/landing/AdditionalFeatures.vue
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<UPageSection
|
||||||
|
:ui="{
|
||||||
|
root: 'py-16 lg:py-20 bg-gray-50 dark:bg-gray-900/50'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<div class="flex flex-col items-center text-center mb-4">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-success-100 dark:bg-success-900/30 text-success-700 dark:text-success-300 text-sm font-medium mb-4"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-shield" class="w-4 h-4" />
|
||||||
|
Vertrauen & Sicherheit
|
||||||
|
</span>
|
||||||
|
<h2
|
||||||
|
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white"
|
||||||
|
>
|
||||||
|
Weitere <span class="gradient-text">Vorteile</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #description>
|
||||||
|
<p class="text-center text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
|
||||||
|
Alles aus einer Hand – ohne Drittanbieter, mit Serverstandort in Deutschland.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Icon grid with hover animations -->
|
||||||
|
<div class="mt-12 grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<div
|
||||||
|
v-for="(feature, index) in features"
|
||||||
|
:key="index"
|
||||||
|
class="group animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${index * 100}ms` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-transparent transition-all relative overflow-hidden"
|
||||||
|
>
|
||||||
|
<!-- Gradient border on hover -->
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 rounded-2xl bg-gradient-to-br from-primary-500 via-cyan-500 to-accent-500 opacity-0 group-hover:opacity-100 transition-opacity -z-10"
|
||||||
|
/>
|
||||||
|
<div class="absolute inset-[2px] rounded-[14px] bg-white dark:bg-gray-900 -z-10" />
|
||||||
|
|
||||||
|
<div class="flex items-start gap-4">
|
||||||
|
<!-- Icon with gradient background -->
|
||||||
|
<div class="relative shrink-0">
|
||||||
|
<div
|
||||||
|
class="w-14 h-14 rounded-2xl bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
<UIcon :name="feature.icon" class="w-7 h-7 text-primary-600 dark:text-primary-400" />
|
||||||
|
</div>
|
||||||
|
<!-- Animated ring on hover -->
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 rounded-2xl ring-2 ring-primary-500/0 group-hover:ring-primary-500/50 transition-all scale-100 group-hover:scale-125 opacity-0 group-hover:opacity-100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1">
|
||||||
|
<h3
|
||||||
|
class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2 group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors"
|
||||||
|
>
|
||||||
|
{{ feature.title }}
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">
|
||||||
|
{{ feature.description }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bottom CTA -->
|
||||||
|
<div class="mt-12 text-center">
|
||||||
|
<p class="text-gray-500 dark:text-gray-400 mb-4">Haben Sie Fragen zu unseren Sicherheitsstandards?</p>
|
||||||
|
<UButton to="#kontakt" variant="outline" class="btn-outline-gradient">
|
||||||
|
<UIcon name="i-lucide-message-circle" class="w-4 h-4 mr-2" />
|
||||||
|
Kontakt aufnehmen
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</UPageSection>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const features = [
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-puzzle',
|
||||||
|
title: 'Keine Zusatztools erforderlich',
|
||||||
|
description:
|
||||||
|
'Keine externen Zusatzlösungen für Prozess, Abstimmung und Dokumentenerstellung – alles läuft in einem System.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-server',
|
||||||
|
title: 'Hosting & Backups in Deutschland',
|
||||||
|
description:
|
||||||
|
'Betrieb und Datensicherung erfolgen in Deutschland – transparente Datenflüsse ohne unerwartete Auslandsverarbeitung.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-lock',
|
||||||
|
title: 'Verschlüsselte Übertragung',
|
||||||
|
description:
|
||||||
|
'Alle Verbindungen sind per TLS/HTTPS verschlüsselt, damit Inhalte und Zugangsdaten beim Transport geschützt sind.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-sparkles',
|
||||||
|
title: 'Einfach zu bedienen',
|
||||||
|
description: 'Nutzerfreundliche, selbsterklärende Oberfläche mit geführten Eingaben – reduziert Schulungsaufwand.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-settings',
|
||||||
|
title: 'Hohe Anpassbarkeit',
|
||||||
|
description:
|
||||||
|
'Templates, Felder und Prozessschritte lassen sich auf Organisation und Abläufe konkret anpassen (auf Anfrage).'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-headphones',
|
||||||
|
title: 'Persönlicher Support',
|
||||||
|
description: 'Bei Fragen steht Ihnen unser Support-Team zur Verfügung – schnell, kompetent und auf Deutsch.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
101
landing/app/components/landing/AnimatedBackground.vue
Normal file
101
landing/app/components/landing/AnimatedBackground.vue
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<div class="absolute inset-0 overflow-hidden pointer-events-none" :class="variant">
|
||||||
|
<!-- Animated gradient orbs -->
|
||||||
|
<div
|
||||||
|
v-for="(orb, index) in orbs"
|
||||||
|
:key="index"
|
||||||
|
class="absolute rounded-full blur-3xl animate-float"
|
||||||
|
:class="orb.color"
|
||||||
|
:style="{
|
||||||
|
width: orb.size,
|
||||||
|
height: orb.size,
|
||||||
|
top: orb.top,
|
||||||
|
left: orb.left,
|
||||||
|
right: orb.right,
|
||||||
|
bottom: orb.bottom,
|
||||||
|
animationDelay: `${index * 2}s`,
|
||||||
|
animationDuration: `${6 + index * 2}s`
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Grid pattern -->
|
||||||
|
<div v-if="showGrid" class="absolute inset-0 dots-pattern opacity-20" />
|
||||||
|
|
||||||
|
<!-- Animated lines (for tech feel) -->
|
||||||
|
<svg v-if="showLines" class="absolute inset-0 w-full h-full opacity-10" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" class="[stop-color:var(--color-primary-500)]" stop-opacity="0" />
|
||||||
|
<stop offset="50%" class="[stop-color:var(--color-primary-500)]" stop-opacity="1" />
|
||||||
|
<stop offset="100%" class="[stop-color:var(--color-primary-500)]" stop-opacity="0" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- Horizontal animated lines -->
|
||||||
|
<g v-for="i in 3" :key="`h-${i}`">
|
||||||
|
<line
|
||||||
|
x1="0"
|
||||||
|
:y1="`${20 + i * 25}%`"
|
||||||
|
x2="100%"
|
||||||
|
:y2="`${20 + i * 25}%`"
|
||||||
|
stroke="url(#lineGradient)"
|
||||||
|
stroke-width="1"
|
||||||
|
class="animate-pulse-soft"
|
||||||
|
:style="{ animationDelay: `${i * 0.5}s` }"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<!-- Floating particles -->
|
||||||
|
<div v-if="showParticles" class="absolute inset-0">
|
||||||
|
<div
|
||||||
|
v-for="i in 12"
|
||||||
|
:key="`particle-${i}`"
|
||||||
|
class="absolute w-1 h-1 rounded-full bg-primary-400/30 animate-float"
|
||||||
|
:style="{
|
||||||
|
top: `${Math.random() * 100}%`,
|
||||||
|
left: `${Math.random() * 100}%`,
|
||||||
|
animationDelay: `${Math.random() * 5}s`,
|
||||||
|
animationDuration: `${4 + Math.random() * 4}s`
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
variant?: 'hero' | 'section' | 'cta'
|
||||||
|
showGrid?: boolean
|
||||||
|
showLines?: boolean
|
||||||
|
showParticles?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
variant: 'section',
|
||||||
|
showGrid: true,
|
||||||
|
showLines: false,
|
||||||
|
showParticles: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const orbs = computed(() => {
|
||||||
|
switch (props.variant) {
|
||||||
|
case 'hero':
|
||||||
|
return [
|
||||||
|
{ size: '400px', top: '-100px', left: '-100px', color: 'bg-primary-500/20' },
|
||||||
|
{ size: '300px', top: '200px', right: '-50px', color: 'bg-success-500/15' },
|
||||||
|
{ size: '250px', bottom: '-50px', left: '30%', color: 'bg-primary-400/15' }
|
||||||
|
]
|
||||||
|
case 'cta':
|
||||||
|
return [
|
||||||
|
{ size: '300px', top: '-50px', right: '-100px', color: 'bg-white/10' },
|
||||||
|
{ size: '200px', bottom: '-50px', left: '-50px', color: 'bg-white/5' }
|
||||||
|
]
|
||||||
|
default:
|
||||||
|
return [
|
||||||
|
{ size: '200px', top: '10%', left: '-50px', color: 'bg-primary-500/10' },
|
||||||
|
{ size: '150px', bottom: '20%', right: '-30px', color: 'bg-success-500/10' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
185
landing/app/components/landing/BenefitsCompany.vue
Normal file
185
landing/app/components/landing/BenefitsCompany.vue
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
<template>
|
||||||
|
<UPageSection
|
||||||
|
id="unternehmen"
|
||||||
|
:ui="{
|
||||||
|
root: 'scroll-mt-20 py-16 lg:py-20 bg-gray-50 dark:bg-gray-900/50'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<div class="flex flex-col items-center text-center mb-4">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-accent-100 dark:bg-accent-900/30 text-accent-700 dark:text-accent-300 text-sm font-medium mb-4"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-building-2" class="w-4 h-4" />
|
||||||
|
Für Unternehmen
|
||||||
|
</span>
|
||||||
|
<h2
|
||||||
|
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white"
|
||||||
|
>
|
||||||
|
Vorteile für <span class="gradient-text">Unternehmen</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #description>
|
||||||
|
<p class="text-center text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
|
||||||
|
Schneller zur abgestimmten Einführung von IT- und KI-Systemen mit planbaren Timelines.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Comparison view -->
|
||||||
|
<div class="mt-12 grid lg:grid-cols-2 gap-8 lg:gap-12">
|
||||||
|
<!-- Pain points column -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div class="flex items-center gap-3 mb-6">
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-2xl bg-gradient-to-br from-warning-500 to-orange-500 flex items-center justify-center shadow-lg shadow-warning-500/25"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-x" class="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-heading text-xl font-bold text-gray-900 dark:text-white">Weg von</h3>
|
||||||
|
<p class="text-sm text-gray-500 dark:text-gray-400">Typische Herausforderungen</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div
|
||||||
|
v-for="(point, index) in painPoints"
|
||||||
|
:key="index"
|
||||||
|
class="group flex gap-4 p-4 rounded-xl bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 hover:border-warning-300 dark:hover:border-warning-600 transition-all animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${index * 75}ms` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mt-0.5 w-8 h-8 rounded-lg bg-warning-100 dark:bg-warning-900/30 flex items-center justify-center shrink-0 group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
<UIcon :name="point.icon" class="w-4 h-4 text-warning-600 dark:text-warning-400" />
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed">{{ point.text }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Benefits column -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div class="flex items-center gap-3 mb-6">
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-2xl bg-gradient-to-br from-success-500 to-emerald-500 flex items-center justify-center shadow-lg shadow-success-500/25"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-check" class="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-heading text-xl font-bold text-gray-900 dark:text-white">Hin zu</h3>
|
||||||
|
<p class="text-sm text-gray-500 dark:text-gray-400">Mit LegalConsentHub</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div
|
||||||
|
v-for="(benefit, index) in benefits"
|
||||||
|
:key="index"
|
||||||
|
class="group flex gap-4 p-4 rounded-xl bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 hover:border-success-300 dark:hover:border-success-600 transition-all animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${index * 75 + 100}ms` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mt-0.5 w-8 h-8 rounded-lg bg-success-100 dark:bg-success-900/30 flex items-center justify-center shrink-0 group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
<UIcon :name="benefit.icon" class="w-4 h-4 text-success-600 dark:text-success-400" />
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed">{{ benefit.text }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Highlights section -->
|
||||||
|
<div class="mt-12">
|
||||||
|
<div class="section-divider mb-8" />
|
||||||
|
<h3 class="font-heading text-2xl sm:text-3xl text-gray-900 dark:text-white text-center mb-10">
|
||||||
|
So wirkt es in der <span class="gradient-text">Praxis</span>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="grid sm:grid-cols-3 gap-6">
|
||||||
|
<div
|
||||||
|
v-for="(highlight, index) in highlights"
|
||||||
|
:key="index"
|
||||||
|
class="group animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${index * 150}ms` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 hover:shadow-xl hover:shadow-accent-500/10 hover:border-accent-200 dark:hover:border-accent-700 transition-all"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-2xl bg-gradient-to-br from-accent-500 to-violet-500 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform shadow-lg shadow-accent-500/25"
|
||||||
|
>
|
||||||
|
<UIcon :name="highlight.icon" class="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<h4 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">{{ highlight.title }}</h4>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-300">{{ highlight.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UPageSection>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const painPoints = [
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-refresh-cw',
|
||||||
|
text: 'Unkalkulierbare Schleifen im Mitbestimmungsverfahren (fehlende Infos, Nachforderungen)'
|
||||||
|
},
|
||||||
|
{ icon: 'i-lucide-ban', text: 'Verzögerungen, Projektstopps und Last-Minute-Änderungen kurz vor Go-live' },
|
||||||
|
{ icon: 'i-lucide-files', text: 'Hoher Koordinationsaufwand (E-Mail/Excel/Word) und Versionschaos' },
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-puzzle',
|
||||||
|
text: 'Komplexität und Reibung durch uneinheitliche Prozesse und unterschiedliche Erwartungshaltungen'
|
||||||
|
},
|
||||||
|
{ icon: 'i-lucide-help-circle', text: 'Unklarer Änderungsumfang bei Updates/Modulerweiterungen' },
|
||||||
|
{ icon: 'i-lucide-hourglass', text: 'Verlust wertvoller Zeit und begrenzter Ressourcen' },
|
||||||
|
{ icon: 'i-lucide-wallet', text: 'Vermeidbare Kosten (Einigungsstelle, externe Beratung, Eskalationen)' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const benefits = [
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-calendar-check',
|
||||||
|
text: 'Planbare, schnellere Verfahren durch Standardisierung & klare Prozessschritte'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-users',
|
||||||
|
text: 'Bessere Zusammenarbeit mit BR/PR durch Transparenz und nachvollziehbare Dokumentation'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-gauge',
|
||||||
|
text: 'Risikobasierter Ansatz: Schnellverfahren für Standard-/Low-Risk-Systeme, Fokus auf High-Risk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-thumbs-up',
|
||||||
|
text: 'Höhere Einigungswahrscheinlichkeit, weil die Verhandlungsgrundlage strukturiert ist'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-file-check-2',
|
||||||
|
text: 'Qualitativ konsistente, robuste Betriebs-/Dienstvereinbarungen (auch bei Änderungen updatefähig)'
|
||||||
|
},
|
||||||
|
{ icon: 'i-lucide-sparkles', text: 'Entlastung von Fachbereichen/IT/HR – mehr Zeit für Wertschöpfung' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const highlights = [
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-repeat',
|
||||||
|
title: 'Weniger Iterationen',
|
||||||
|
description: 'Unterlagen sind vollständig und vergleichbar – Nachforderungen sinken.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-rocket',
|
||||||
|
title: 'Schneller zur Freigabe',
|
||||||
|
description: 'Klare Schritte statt „Hauruck" und kurzfristiger Umplanungen.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-refresh-cw',
|
||||||
|
title: 'Change-ready',
|
||||||
|
description:
|
||||||
|
'Updates, neue Module oder neue Auswertungen werden strukturiert nachgezogen, ohne jedes Mal neu zu starten.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
209
landing/app/components/landing/BenefitsWorksCouncil.vue
Normal file
209
landing/app/components/landing/BenefitsWorksCouncil.vue
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
<template>
|
||||||
|
<UPageSection
|
||||||
|
id="betriebsraete"
|
||||||
|
:ui="{
|
||||||
|
root: 'scroll-mt-20 py-16 lg:py-20'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<div class="flex flex-col items-center text-center mb-4">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300 text-sm font-medium mb-4"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-users" class="w-4 h-4" />
|
||||||
|
Für Betriebsräte
|
||||||
|
</span>
|
||||||
|
<h2
|
||||||
|
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white"
|
||||||
|
>
|
||||||
|
Vorteile für <span class="gradient-text">Betriebsräte</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #description>
|
||||||
|
<p class="text-center text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
|
||||||
|
Weg von Informationsjagd und Blackbox-Systemen – hin zu Transparenz und belastbaren Vereinbarungen.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Toggle between pain points and benefits -->
|
||||||
|
<div class="mt-12">
|
||||||
|
<!-- Tab switcher -->
|
||||||
|
<div class="flex justify-center mb-10">
|
||||||
|
<div class="inline-flex p-1.5 rounded-2xl glass">
|
||||||
|
<button
|
||||||
|
:class="[
|
||||||
|
'px-6 py-3 rounded-xl text-sm font-semibold transition-all duration-300',
|
||||||
|
activeTab === 'pain'
|
||||||
|
? 'bg-gradient-to-r from-warning-500 to-warning-600 text-white shadow-lg'
|
||||||
|
: 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white'
|
||||||
|
]"
|
||||||
|
@click="activeTab = 'pain'"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-x-circle" class="w-4 h-4 inline mr-2" />
|
||||||
|
Weg von
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
:class="[
|
||||||
|
'px-6 py-3 rounded-xl text-sm font-semibold transition-all duration-300',
|
||||||
|
activeTab === 'benefit'
|
||||||
|
? 'bg-gradient-to-r from-success-500 to-success-600 text-white shadow-lg'
|
||||||
|
: 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white'
|
||||||
|
]"
|
||||||
|
@click="activeTab = 'benefit'"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-check-circle" class="w-4 h-4 inline mr-2" />
|
||||||
|
Hin zu
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Cards carousel -->
|
||||||
|
<div class="relative">
|
||||||
|
<!-- Pain points cards -->
|
||||||
|
<Transition
|
||||||
|
enter-active-class="transition-all duration-500 ease-out"
|
||||||
|
enter-from-class="opacity-0 translate-x-8"
|
||||||
|
enter-to-class="opacity-100 translate-x-0"
|
||||||
|
leave-active-class="transition-all duration-300 ease-in absolute inset-0"
|
||||||
|
leave-from-class="opacity-100 translate-x-0"
|
||||||
|
leave-to-class="opacity-0 -translate-x-8"
|
||||||
|
>
|
||||||
|
<div v-if="activeTab === 'pain'" class="grid sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
|
||||||
|
<div v-for="(point, index) in painPoints" :key="index" class="group">
|
||||||
|
<div
|
||||||
|
class="h-full p-5 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-warning-300 dark:hover:border-warning-700 shadow-sm hover:shadow-lg transition-all duration-300"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-warning-100 dark:bg-warning-900/30 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
<UIcon :name="point.icon" class="w-5 h-5 text-warning-600 dark:text-warning-400" />
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed">{{ point.text }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<!-- Benefits cards -->
|
||||||
|
<Transition
|
||||||
|
enter-active-class="transition-all duration-500 ease-out"
|
||||||
|
enter-from-class="opacity-0 translate-x-8"
|
||||||
|
enter-to-class="opacity-100 translate-x-0"
|
||||||
|
leave-active-class="transition-all duration-300 ease-in absolute inset-0"
|
||||||
|
leave-from-class="opacity-100 translate-x-0"
|
||||||
|
leave-to-class="opacity-0 -translate-x-8"
|
||||||
|
>
|
||||||
|
<div v-if="activeTab === 'benefit'" class="grid sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
|
||||||
|
<div v-for="(benefit, index) in benefits" :key="index" class="group">
|
||||||
|
<div
|
||||||
|
class="h-full p-5 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-success-300 dark:hover:border-success-700 shadow-sm hover:shadow-lg transition-all duration-300"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-success-100 dark:bg-success-900/30 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
<UIcon :name="benefit.icon" class="w-5 h-5 text-success-600 dark:text-success-400" />
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed">{{ benefit.text }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Highlights section -->
|
||||||
|
<div class="mt-12">
|
||||||
|
<div class="section-divider mb-8" />
|
||||||
|
<h3 class="font-heading text-2xl sm:text-3xl text-gray-900 dark:text-white text-center mb-10">
|
||||||
|
So hilft es im <span class="gradient-text">Alltag</span>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="grid sm:grid-cols-3 gap-6">
|
||||||
|
<div
|
||||||
|
v-for="(highlight, index) in highlights"
|
||||||
|
:key="index"
|
||||||
|
class="group animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${index * 150}ms` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-full p-6 rounded-2xl bg-gradient-to-br from-primary-50 to-cyan-50 dark:from-primary-950/50 dark:to-cyan-950/50 border border-primary-100 dark:border-primary-900 hover:shadow-xl hover:shadow-primary-500/10 transition-all"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-2xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform shadow-lg shadow-primary-500/25"
|
||||||
|
>
|
||||||
|
<UIcon :name="highlight.icon" class="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<h4 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">{{ highlight.title }}</h4>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-300">{{ highlight.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UPageSection>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const activeTab = ref<'pain' | 'benefit'>('benefit')
|
||||||
|
|
||||||
|
const painPoints = [
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-search',
|
||||||
|
text: 'Informationen zu IT-/KI-Systemen mühsam zusammensuchen (E-Mails, PDFs, PowerPoint, Excel-Chaos)'
|
||||||
|
},
|
||||||
|
{ icon: 'i-lucide-git-branch', text: 'Medienbrüche, Versionschaos und wiederkehrende Rückfragen' },
|
||||||
|
{ icon: 'i-lucide-timer', text: 'Ad-hoc-Systemeinführungen unter Zeitdruck („Hauruck" statt Prozess)' },
|
||||||
|
{ icon: 'i-lucide-brain', text: 'Überforderung durch Menge und Komplexität der Systeme' },
|
||||||
|
{ icon: 'i-lucide-eye-off', text: 'Blackbox bei Funktionen, Auswertungen, Schnittstellen und Änderungen' },
|
||||||
|
{ icon: 'i-lucide-file-question', text: 'Verhandlungen ohne belastbare Datenbasis' },
|
||||||
|
{ icon: 'i-lucide-calendar-x', text: 'Heute geregelt, morgen veraltet' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const benefits = [
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-layout-list',
|
||||||
|
text: 'Strukturierte, vollständige Informationsgrundlage (einheitlich je System/Verarbeitung)'
|
||||||
|
},
|
||||||
|
{ icon: 'i-lucide-route', text: 'Klarer Mitbestimmungsprozess mit bewährten Schritten und Zuständigkeiten' },
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-file-check',
|
||||||
|
text: 'Betriebs-/Dienstvereinbarungen auf belastbarer Grundlage – schneller, konsistenter, leicht aktualisierbar'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-scan-eye',
|
||||||
|
text: 'Transparenz über Systemfähigkeiten – inkl. möglicher Leistungs-/Verhaltenskontrolle'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-git-compare',
|
||||||
|
text: 'Vergleichbarkeit über viele Systeme hinweg durch Standardisierung und einheitliche Templates'
|
||||||
|
},
|
||||||
|
{ icon: 'i-lucide-clock', text: 'Große Zeitersparnis gegenüber konventionellem Verfahren' },
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-shield-check',
|
||||||
|
text: 'Schutzmaßnahmen konsequent dokumentiert und pro Auswertung/Verarbeitung nachvollziehbar'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-heart-handshake',
|
||||||
|
text: 'Spürbare Entlastung: mehr Zeit für andere Mitbestimmungsthemen und kontinuierlichen Arbeitnehmerschutz'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const highlights = [
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-zap',
|
||||||
|
title: 'Schneller prüfen',
|
||||||
|
description: 'Relevante Funktionen und Risiken sind auf einen Blick sichtbar.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-handshake',
|
||||||
|
title: 'Besser verhandeln',
|
||||||
|
description: 'Klare, konsistente Unterlagen statt Interpretationsspielräumen.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-shield',
|
||||||
|
title: 'Nachhaltig absichern',
|
||||||
|
description: 'Änderungen und neue Auswertungen lassen sich strukturiert nachziehen.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
175
landing/app/components/landing/ExpertAccess.vue
Normal file
175
landing/app/components/landing/ExpertAccess.vue
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
<template>
|
||||||
|
<section id="kontakt" class="relative py-16 lg:py-20 overflow-hidden scroll-mt-20">
|
||||||
|
<!-- Mesh gradient background -->
|
||||||
|
<div class="absolute inset-0 mesh-gradient-cta" />
|
||||||
|
|
||||||
|
<!-- Animated gradient overlay -->
|
||||||
|
<div class="absolute inset-0 bg-gradient-to-br from-primary-600/90 via-cyan-600/90 to-accent-600/90" />
|
||||||
|
|
||||||
|
<!-- Grid pattern -->
|
||||||
|
<div class="absolute inset-0 grid-pattern opacity-10" />
|
||||||
|
|
||||||
|
<!-- Floating elements -->
|
||||||
|
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
||||||
|
<div class="absolute top-10 left-10 w-20 h-20 rounded-full bg-white/10 animate-float-slow" />
|
||||||
|
<div
|
||||||
|
class="absolute bottom-20 right-20 w-32 h-32 rounded-full bg-white/5 animate-float-slow"
|
||||||
|
style="animation-delay: 2s"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="absolute top-1/2 left-1/4 w-16 h-16 rounded-full bg-white/10 animate-float-fast"
|
||||||
|
style="animation-delay: 1s"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
|
||||||
|
<!-- Left: Content -->
|
||||||
|
<div class="text-center lg:text-left">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/20 backdrop-blur-sm text-white text-sm font-medium mb-6"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-users" class="w-4 h-4" />
|
||||||
|
Expertennetzwerk
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<h2 class="font-heading text-3xl sm:text-4xl lg:text-5xl font-bold text-white mb-6 animate-fade-in-up">
|
||||||
|
Externer Sachverstand – direkt aus dem Verfahren
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p class="text-lg text-white/90 mb-8 animate-fade-in-up" style="animation-delay: 100ms">
|
||||||
|
Wenn Betriebsparteien bei einzelnen Fragen nicht weiterkommen, kann optional externer Sachverstand direkt im
|
||||||
|
System angefragt werden. Anfragen, Rückfragen und Ergebnisse bleiben nachvollziehbar dokumentiert.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- CTA buttons -->
|
||||||
|
<div
|
||||||
|
class="flex flex-wrap justify-center lg:justify-start gap-4 animate-fade-in-up"
|
||||||
|
style="animation-delay: 200ms"
|
||||||
|
>
|
||||||
|
<UButton
|
||||||
|
to="mailto:info@legalconsenthub.de"
|
||||||
|
size="xl"
|
||||||
|
class="bg-white text-primary-700 hover:bg-white/90 px-8 py-4 text-lg font-semibold rounded-xl shadow-lg"
|
||||||
|
>
|
||||||
|
Kontakt aufnehmen
|
||||||
|
<UIcon name="i-lucide-arrow-right" class="w-5 h-5 ml-2" />
|
||||||
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
to="#features"
|
||||||
|
size="xl"
|
||||||
|
class="bg-white/10 text-white border-2 border-white/30 hover:bg-white/20 px-8 py-4 text-lg font-semibold rounded-xl backdrop-blur-sm"
|
||||||
|
>
|
||||||
|
Mehr erfahren
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right: Expert cards with connection lines -->
|
||||||
|
<div class="flex justify-center animate-scale-in" style="animation-delay: 300ms">
|
||||||
|
<div class="relative">
|
||||||
|
<!-- Connection lines SVG -->
|
||||||
|
<svg class="absolute inset-0 w-full h-full pointer-events-none" viewBox="0 0 400 300">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color: rgba(255, 255, 255, 0.3)" />
|
||||||
|
<stop offset="50%" style="stop-color: rgba(255, 255, 255, 0.6)" />
|
||||||
|
<stop offset="100%" style="stop-color: rgba(255, 255, 255, 0.3)" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<!-- Animated connection lines -->
|
||||||
|
<path
|
||||||
|
d="M200,150 L100,80"
|
||||||
|
stroke="url(#lineGradient)"
|
||||||
|
stroke-width="2"
|
||||||
|
fill="none"
|
||||||
|
stroke-dasharray="5,5"
|
||||||
|
class="animate-pulse"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M200,150 L300,80"
|
||||||
|
stroke="url(#lineGradient)"
|
||||||
|
stroke-width="2"
|
||||||
|
fill="none"
|
||||||
|
stroke-dasharray="5,5"
|
||||||
|
class="animate-pulse"
|
||||||
|
style="animation-delay: 0.5s"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M200,150 L200,250"
|
||||||
|
stroke="url(#lineGradient)"
|
||||||
|
stroke-width="2"
|
||||||
|
fill="none"
|
||||||
|
stroke-dasharray="5,5"
|
||||||
|
class="animate-pulse"
|
||||||
|
style="animation-delay: 1s"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<!-- Center hub -->
|
||||||
|
<div class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-10">
|
||||||
|
<div
|
||||||
|
class="w-20 h-20 rounded-full bg-white/20 backdrop-blur-sm border-2 border-white/40 flex items-center justify-center animate-pulse-glow"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-link" class="w-8 h-8 text-white" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Expert cards -->
|
||||||
|
<div class="grid grid-cols-2 gap-6 w-80 sm:w-96">
|
||||||
|
<!-- Legal expert card -->
|
||||||
|
<div class="col-span-1 animate-float-slow">
|
||||||
|
<div
|
||||||
|
class="bg-white/15 backdrop-blur-md rounded-2xl p-5 border border-white/20 hover:bg-white/20 transition-all"
|
||||||
|
>
|
||||||
|
<div class="w-12 h-12 rounded-xl bg-white/20 flex items-center justify-center mb-4">
|
||||||
|
<UIcon name="i-lucide-scale" class="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<h4 class="font-heading font-bold text-white mb-1">Arbeitsrecht</h4>
|
||||||
|
<p class="text-sm text-white/70">Fachanwälte für Arbeitsrecht</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Technical expert card -->
|
||||||
|
<div class="col-span-1 animate-float-slow" style="animation-delay: 1s">
|
||||||
|
<div
|
||||||
|
class="bg-white/15 backdrop-blur-md rounded-2xl p-5 border border-white/20 hover:bg-white/20 transition-all"
|
||||||
|
>
|
||||||
|
<div class="w-12 h-12 rounded-xl bg-white/20 flex items-center justify-center mb-4">
|
||||||
|
<UIcon name="i-lucide-cpu" class="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<h4 class="font-heading font-bold text-white mb-1">Technik</h4>
|
||||||
|
<p class="text-sm text-white/70">IT-Sachverständige</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Spacer for center positioning -->
|
||||||
|
<div class="col-span-2 h-24" />
|
||||||
|
|
||||||
|
<!-- Process integration card -->
|
||||||
|
<div class="col-span-2 animate-float-slow" style="animation-delay: 2s">
|
||||||
|
<div
|
||||||
|
class="bg-white/15 backdrop-blur-md rounded-2xl p-5 border border-white/20 hover:bg-white/20 transition-all"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="w-12 h-12 rounded-xl bg-white/20 flex items-center justify-center shrink-0">
|
||||||
|
<UIcon name="i-lucide-file-check" class="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 class="font-heading font-bold text-white mb-1">Direkt im Verfahren</h4>
|
||||||
|
<p class="text-sm text-white/70">Dokumentiert & nachvollziehbar</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// No additional script needed
|
||||||
|
</script>
|
||||||
242
landing/app/components/landing/FeaturesGrid.vue
Normal file
242
landing/app/components/landing/FeaturesGrid.vue
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
<template>
|
||||||
|
<UPageSection
|
||||||
|
id="features"
|
||||||
|
:ui="{
|
||||||
|
root: 'scroll-mt-20 py-16 lg:py-20'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<div class="flex flex-col items-center text-center mb-4">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-cyan-100 dark:bg-cyan-900/30 text-cyan-700 dark:text-cyan-300 text-sm font-medium mb-4"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-sparkles" class="w-4 h-4" />
|
||||||
|
Features
|
||||||
|
</span>
|
||||||
|
<h2
|
||||||
|
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white"
|
||||||
|
>
|
||||||
|
Features, die Mitbestimmung <span class="gradient-text">effizient</span> machen
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #description>
|
||||||
|
<p class="text-center text-lg text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
|
||||||
|
Eine strukturierte Eingabelogik, klare Prozesse und revisionssichere Dokumentation – damit IT-/KI-Systeme
|
||||||
|
schneller bewertet, abgestimmt und sauber vereinbart werden können.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Bento Grid -->
|
||||||
|
<div ref="gridRef" class="mt-12 bento-grid">
|
||||||
|
<!-- Large featured card -->
|
||||||
|
<div class="bento-item-large group card-spotlight animate-fade-in-up" @mousemove="handleMouseMove">
|
||||||
|
<div
|
||||||
|
class="h-full p-8 rounded-3xl bg-gradient-to-br from-primary-500 to-cyan-500 text-white relative overflow-hidden"
|
||||||
|
>
|
||||||
|
<!-- Background pattern -->
|
||||||
|
<div class="absolute inset-0 opacity-10">
|
||||||
|
<div class="absolute inset-0 grid-pattern" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="relative z-10">
|
||||||
|
<div
|
||||||
|
class="w-14 h-14 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center mb-6 group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-route" class="w-7 h-7 text-white" />
|
||||||
|
</div>
|
||||||
|
<h3 class="font-heading text-2xl sm:text-3xl font-bold mb-4">Geführter Mitbestimmungsprozess</h3>
|
||||||
|
<p class="text-white/90 text-lg leading-relaxed mb-6">
|
||||||
|
Vorgegebene, erweiterbare Eingabeparameter strukturieren den gesamten Ablauf – von der Systembeschreibung
|
||||||
|
bis zur Vereinbarung.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Visual element -->
|
||||||
|
<div class="flex items-center gap-3 mt-8">
|
||||||
|
<div class="flex -space-x-2">
|
||||||
|
<div class="w-8 h-8 rounded-full bg-white/30 flex items-center justify-center text-xs font-bold">1</div>
|
||||||
|
<div class="w-8 h-8 rounded-full bg-white/30 flex items-center justify-center text-xs font-bold">2</div>
|
||||||
|
<div class="w-8 h-8 rounded-full bg-white/30 flex items-center justify-center text-xs font-bold">3</div>
|
||||||
|
<div class="w-8 h-8 rounded-full bg-white/30 flex items-center justify-center text-xs font-bold">4</div>
|
||||||
|
</div>
|
||||||
|
<span class="text-sm text-white/80">Strukturierte Prozessschritte</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Regular cards -->
|
||||||
|
<div
|
||||||
|
v-for="(feature, index) in features.slice(1, 5)"
|
||||||
|
:key="index"
|
||||||
|
class="group card-spotlight animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${(index + 1) * 100}ms` }"
|
||||||
|
@mousemove="handleMouseMove"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 transition-all hover:shadow-xl hover:shadow-primary-500/10"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-xl bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
<UIcon :name="feature.icon" class="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
||||||
|
</div>
|
||||||
|
<h3 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">{{ feature.title }}</h3>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">{{ feature.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tall card -->
|
||||||
|
<div
|
||||||
|
class="bento-item-tall group card-spotlight animate-fade-in-up"
|
||||||
|
style="animation-delay: 500ms"
|
||||||
|
@mousemove="handleMouseMove"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-full p-6 rounded-2xl bg-gradient-to-b from-accent-50 to-violet-50 dark:from-accent-950/50 dark:to-violet-950/50 border border-accent-200 dark:border-accent-800 hover:shadow-xl hover:shadow-accent-500/10 transition-all"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-xl bg-gradient-to-br from-accent-500 to-violet-500 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform shadow-lg shadow-accent-500/25"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-history" class="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<h3 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">Versionierung & Audit-Trail</h3>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed mb-6">
|
||||||
|
Änderungen werden versioniert und lückenlos nachvollziehbar dokumentiert – inklusive Historie und Vergleich.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Visual timeline -->
|
||||||
|
<div class="space-y-3 mt-auto">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-accent-500" />
|
||||||
|
<div class="flex-1 h-px bg-accent-200 dark:bg-accent-800" />
|
||||||
|
<span class="text-xs text-accent-600 dark:text-accent-400">v1.0</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-accent-500" />
|
||||||
|
<div class="flex-1 h-px bg-accent-200 dark:bg-accent-800" />
|
||||||
|
<span class="text-xs text-accent-600 dark:text-accent-400">v1.1</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-3 h-3 rounded-full bg-accent-500 ring-4 ring-accent-200 dark:ring-accent-800" />
|
||||||
|
<div class="flex-1 h-px bg-accent-300 dark:bg-accent-700" />
|
||||||
|
<span class="text-xs font-semibold text-accent-700 dark:text-accent-300">v2.0</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wide card -->
|
||||||
|
<div
|
||||||
|
class="bento-item-wide group card-spotlight animate-fade-in-up"
|
||||||
|
style="animation-delay: 600ms"
|
||||||
|
@mousemove="handleMouseMove"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 transition-all hover:shadow-xl hover:shadow-primary-500/10"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col sm:flex-row sm:items-start gap-6">
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-xl bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center shrink-0 group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-file-text" class="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">
|
||||||
|
Automatische BV-/DV-Generierung
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">
|
||||||
|
Nach Abschluss der Eingaben erzeugt das System strukturierte, übersichtliche und signaturbereite
|
||||||
|
Betriebs-/Dienstvereinbarungen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Remaining cards -->
|
||||||
|
<div
|
||||||
|
v-for="(feature, index) in features.slice(5)"
|
||||||
|
:key="index + 5"
|
||||||
|
class="group card-spotlight animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${(index + 7) * 100}ms` }"
|
||||||
|
@mousemove="handleMouseMove"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 transition-all hover:shadow-xl hover:shadow-primary-500/10"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-xl bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
<UIcon :name="feature.icon" class="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
||||||
|
</div>
|
||||||
|
<h3 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">{{ feature.title }}</h3>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">{{ feature.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UPageSection>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const gridRef = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
|
// Spotlight effect handler
|
||||||
|
function handleMouseMove(event: MouseEvent) {
|
||||||
|
const card = event.currentTarget as HTMLElement
|
||||||
|
const rect = card.getBoundingClientRect()
|
||||||
|
const x = ((event.clientX - rect.left) / rect.width) * 100
|
||||||
|
const y = ((event.clientY - rect.top) / rect.height) * 100
|
||||||
|
card.style.setProperty('--mouse-x', `${x}%`)
|
||||||
|
card.style.setProperty('--mouse-y', `${y}%`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const features = [
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-route',
|
||||||
|
title: 'Geführter Mitbestimmungsprozess',
|
||||||
|
description:
|
||||||
|
'Vorgegebene, erweiterbare Eingabeparameter strukturieren den gesamten Ablauf – von der Systembeschreibung bis zur Vereinbarung.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-shield-alert',
|
||||||
|
title: 'Risikobasierter Assistent',
|
||||||
|
description:
|
||||||
|
'Ein regelbasierter, risikoorientierter Assistent passt die Eingabemaske an Komplexität, Umfang und Potenziale zur Leistungs-/Verhaltensauswertung an.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-gauge',
|
||||||
|
title: 'Ampelsystem & Direktfeedback',
|
||||||
|
description:
|
||||||
|
'Kritikalität wird transparent bewertet und direkt beim Ausfüllen zurückgespielt – für schnelle Orientierung und weniger Schleifen.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-message-square',
|
||||||
|
title: 'Zusammenarbeit per Kommentaren',
|
||||||
|
description: 'Inline-Kommentare ermöglichen Abstimmung direkt an einzelnen Inhalten – ohne Medienbrüche.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-history',
|
||||||
|
title: 'Versionierung & Audit-Trail',
|
||||||
|
description:
|
||||||
|
'Änderungen werden versioniert und lückenlos nachvollziehbar dokumentiert – inklusive Historie und Vergleich.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-pen-tool',
|
||||||
|
title: 'Signaturfähig mit QES (eIDAS)',
|
||||||
|
description: 'Optional rechtsverbindliche Unterzeichnung per qualifizierter elektronischer Signatur nach eIDAS.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-bell',
|
||||||
|
title: 'Benachrichtigungen & News-Center',
|
||||||
|
description: 'Aktuell bleiben über Status-Updates, Änderungen und Aufgaben – per Nachrichten-Center und E-Mail.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-shield-check',
|
||||||
|
title: 'SSO & Governance',
|
||||||
|
description:
|
||||||
|
'SSO-Integration via SAML oder OIDC sowie ein umfangreich konfigurierbares Rollen- und Berechtigungskonzept.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
210
landing/app/components/landing/FrameworkAgreement.vue
Normal file
210
landing/app/components/landing/FrameworkAgreement.vue
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
<template>
|
||||||
|
<UPageSection
|
||||||
|
:ui="{
|
||||||
|
root: 'py-16 lg:py-20 scroll-mt-20'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
|
||||||
|
<!-- Left: Content -->
|
||||||
|
<div class="order-2 lg:order-1">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-accent-100 dark:bg-accent-900/30 text-accent-700 dark:text-accent-300 text-sm font-medium mb-6"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-file-text" class="w-4 h-4" />
|
||||||
|
Optional verfügbar
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<h2
|
||||||
|
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white mb-6"
|
||||||
|
>
|
||||||
|
Rahmenbetriebsvereinbarung <span class="gradient-text">IT/KI</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p class="text-lg text-gray-600 dark:text-gray-300 mb-8">
|
||||||
|
Für den Einstieg stellen wir auf Nachfrage eine optionale Rahmenbetriebs-/Rahmendienstvereinbarung für IT- und
|
||||||
|
KI-Systeme bereit. Sie ist auf die Struktur des Tools zugeschnitten und enthält praxiserprobte
|
||||||
|
Regelungsbausteine.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Animated checklist -->
|
||||||
|
<ul class="space-y-4 mb-8">
|
||||||
|
<li
|
||||||
|
v-for="(point, index) in bulletPoints"
|
||||||
|
:key="index"
|
||||||
|
class="flex gap-4 animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${index * 100}ms` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mt-1 w-6 h-6 rounded-full bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center shrink-0"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-check" class="w-3.5 h-3.5 text-white" />
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-700 dark:text-gray-300">{{ point }}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Price info -->
|
||||||
|
<div
|
||||||
|
class="p-4 rounded-xl bg-gradient-to-r from-primary-50 to-cyan-50 dark:from-primary-950/50 dark:to-cyan-950/50 border border-primary-200 dark:border-primary-800"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-tag" class="w-5 h-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-500 dark:text-gray-400">Preis</p>
|
||||||
|
<p class="font-heading text-lg font-bold text-gray-900 dark:text-white">Auf Anfrage</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CTA -->
|
||||||
|
<div class="mt-8">
|
||||||
|
<UButton
|
||||||
|
to="#kontakt"
|
||||||
|
size="xl"
|
||||||
|
class="btn-gradient px-8 py-4 text-lg font-semibold rounded-xl shadow-lg shadow-primary-500/25"
|
||||||
|
>
|
||||||
|
<span>Mehr erfahren</span>
|
||||||
|
<UIcon name="i-lucide-arrow-right" class="w-5 h-5 ml-2" />
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right: 3D Document Preview -->
|
||||||
|
<div class="order-1 lg:order-2 flex justify-center">
|
||||||
|
<div class="relative animate-scale-in">
|
||||||
|
<!-- 3D Document with tilt effect -->
|
||||||
|
<div
|
||||||
|
class="relative transform-gpu transition-transform duration-500 hover:rotate-0"
|
||||||
|
style="transform: perspective(1000px) rotateY(-8deg) rotateX(5deg)"
|
||||||
|
@mouseenter="isHovered = true"
|
||||||
|
@mouseleave="isHovered = false"
|
||||||
|
>
|
||||||
|
<!-- Shadow layer -->
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 bg-gray-900/20 dark:bg-black/40 blur-2xl rounded-3xl translate-x-4 translate-y-4"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Document card -->
|
||||||
|
<div
|
||||||
|
class="relative bg-white dark:bg-gray-900 rounded-2xl border border-gray-200 dark:border-gray-700 shadow-2xl overflow-hidden max-w-sm"
|
||||||
|
>
|
||||||
|
<!-- Document header -->
|
||||||
|
<div class="bg-gradient-to-r from-primary-600 to-cyan-600 px-6 py-5">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="w-12 h-12 rounded-xl bg-white/20 backdrop-blur-sm flex items-center justify-center">
|
||||||
|
<UIcon name="i-lucide-file-text" class="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 class="font-heading font-bold text-white text-lg">Rahmen-BV IT/KI</h4>
|
||||||
|
<p class="text-sm text-white/80">Betriebsvereinbarung Vorlage</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Document content preview -->
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Table of contents -->
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="text-xs uppercase tracking-wider text-gray-500 dark:text-gray-400 font-semibold">
|
||||||
|
Inhaltsverzeichnis
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Section items with staggered animation -->
|
||||||
|
<div
|
||||||
|
v-for="(section, index) in documentSections"
|
||||||
|
:key="index"
|
||||||
|
class="group flex items-center gap-3 p-3 rounded-xl bg-gray-50 dark:bg-gray-800 hover:bg-primary-50 dark:hover:bg-primary-900/20 transition-colors cursor-pointer"
|
||||||
|
:class="{ 'animate-fade-in-up': isHovered }"
|
||||||
|
:style="{ animationDelay: `${index * 100}ms` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-8 h-8 rounded-lg bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center text-sm font-bold text-primary-600 dark:text-primary-400 group-hover:scale-110 transition-transform"
|
||||||
|
>
|
||||||
|
{{ index + 1 }}
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<div class="text-sm font-medium text-gray-900 dark:text-white truncate">{{ section.title }}</div>
|
||||||
|
<div class="text-xs text-gray-500 dark:text-gray-400 truncate">{{ section.description }}</div>
|
||||||
|
</div>
|
||||||
|
<UIcon
|
||||||
|
:name="section.icon"
|
||||||
|
class="w-4 h-4 text-gray-400 group-hover:text-primary-500 transition-colors"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer info -->
|
||||||
|
<div class="mt-6 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<UIcon name="i-lucide-layers" class="w-4 h-4 text-gray-400" />
|
||||||
|
<span class="text-xs text-gray-500 dark:text-gray-400">12 Regelungsbausteine</span>
|
||||||
|
</div>
|
||||||
|
<UBadge color="success" variant="soft" size="sm">
|
||||||
|
<UIcon name="i-lucide-check-circle" class="w-3 h-3 mr-1" />
|
||||||
|
Praxiserprobt
|
||||||
|
</UBadge>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Floating badge -->
|
||||||
|
<div class="absolute -top-4 -right-4 z-10 animate-float-fast">
|
||||||
|
<div
|
||||||
|
class="bg-gradient-to-r from-accent-500 to-violet-500 text-white px-4 py-2 rounded-full shadow-lg text-sm font-semibold flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-download" class="w-4 h-4" />
|
||||||
|
Auf Anfrage
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Decorative elements -->
|
||||||
|
<div class="absolute -top-8 -left-8 w-32 h-32 bg-primary-400/20 rounded-full blur-3xl animate-pulse-glow" />
|
||||||
|
<div
|
||||||
|
class="absolute -bottom-8 -right-8 w-40 h-40 bg-accent-400/20 rounded-full blur-3xl animate-pulse-glow"
|
||||||
|
style="animation-delay: 1s"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UPageSection>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const isHovered = ref(false)
|
||||||
|
|
||||||
|
const bulletPoints = [
|
||||||
|
'Vorlage für eine Rahmen-BV/DV zu IT- und KI-Systemen',
|
||||||
|
'Auf die Tool-Logik und Dokumentationsstruktur zugeschnitten',
|
||||||
|
'Enthält praxiserprobte Regelungsbausteine als Startpunkt für systembezogene Vereinbarungen'
|
||||||
|
]
|
||||||
|
|
||||||
|
const documentSections = [
|
||||||
|
{
|
||||||
|
title: 'Geltungsbereich',
|
||||||
|
description: 'Definition der betroffenen Systeme',
|
||||||
|
icon: 'i-lucide-target'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Mitbestimmungsverfahren',
|
||||||
|
description: 'Prozessschritte und Zuständigkeiten',
|
||||||
|
icon: 'i-lucide-git-branch'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Datenschutz & Kontrolle',
|
||||||
|
description: 'Schutzmaßnahmen und Auswertungen',
|
||||||
|
icon: 'i-lucide-shield'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Änderungsmanagement',
|
||||||
|
description: 'Updates und Erweiterungen',
|
||||||
|
icon: 'i-lucide-refresh-cw'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
263
landing/app/components/landing/HeroSection.vue
Normal file
263
landing/app/components/landing/HeroSection.vue
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
<template>
|
||||||
|
<section class="relative min-h-screen flex items-center justify-center overflow-hidden hero-gradient-light">
|
||||||
|
<!-- Animated gradient orbs -->
|
||||||
|
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
||||||
|
<!-- Large teal orb -->
|
||||||
|
<div
|
||||||
|
class="gradient-orb gradient-orb-teal w-[600px] h-[600px] -top-40 -left-40 animate-orb-float"
|
||||||
|
style="animation-delay: 0s"
|
||||||
|
/>
|
||||||
|
<!-- Violet orb -->
|
||||||
|
<div
|
||||||
|
class="gradient-orb gradient-orb-violet w-[500px] h-[500px] top-1/4 -right-32 animate-orb-float"
|
||||||
|
style="animation-delay: 3s"
|
||||||
|
/>
|
||||||
|
<!-- Cyan orb -->
|
||||||
|
<div
|
||||||
|
class="gradient-orb gradient-orb-cyan w-[400px] h-[400px] bottom-0 left-1/4 animate-orb-float"
|
||||||
|
style="animation-delay: 6s"
|
||||||
|
/>
|
||||||
|
<!-- Small accent orb -->
|
||||||
|
<div
|
||||||
|
class="gradient-orb gradient-orb-violet w-[200px] h-[200px] top-1/2 left-10 animate-orb-float opacity-40"
|
||||||
|
style="animation-delay: 9s"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Grid pattern overlay -->
|
||||||
|
<div class="absolute inset-0 grid-pattern opacity-30" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="relative z-10 w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 lg:py-32">
|
||||||
|
<div class="text-center max-w-4xl mx-auto">
|
||||||
|
<!-- Badge -->
|
||||||
|
<div class="animate-fade-in-up mb-8">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-2 px-4 py-2 rounded-full glass text-sm font-medium text-gray-700 dark:text-gray-200"
|
||||||
|
>
|
||||||
|
<span class="relative flex h-2 w-2">
|
||||||
|
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary-400 opacity-75" />
|
||||||
|
<span class="relative inline-flex rounded-full h-2 w-2 bg-primary-500" />
|
||||||
|
</span>
|
||||||
|
Jetzt verfügbar
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Title with gradient text -->
|
||||||
|
<h1 class="font-heading text-4xl sm:text-5xl md:text-6xl lg:text-7xl tracking-tight mb-6">
|
||||||
|
<span class="animate-fade-in-up block text-gray-900 dark:text-white" style="animation-delay: 100ms">
|
||||||
|
Digitale Mitbestimmung
|
||||||
|
</span>
|
||||||
|
<span class="animate-fade-in-up block gradient-text" style="animation-delay: 200ms">
|
||||||
|
für IT- und KI-Systeme
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
<p
|
||||||
|
class="animate-fade-in-up text-lg sm:text-xl text-gray-600 dark:text-gray-300 max-w-2xl mx-auto mb-10"
|
||||||
|
style="animation-delay: 300ms"
|
||||||
|
>
|
||||||
|
{{ description }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- CTA Buttons -->
|
||||||
|
<div class="flex flex-wrap justify-center gap-4 animate-fade-in-up" style="animation-delay: 400ms">
|
||||||
|
<UButton
|
||||||
|
size="xl"
|
||||||
|
to="#kontakt"
|
||||||
|
trailing-icon="i-lucide-arrow-right"
|
||||||
|
class="btn-gradient px-8 py-4 text-lg font-semibold rounded-xl shadow-lg shadow-primary-500/25 hover:shadow-xl hover:shadow-primary-500/30 transition-all"
|
||||||
|
>
|
||||||
|
<span>Demo anfragen</span>
|
||||||
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
size="xl"
|
||||||
|
to="#features"
|
||||||
|
variant="outline"
|
||||||
|
class="btn-outline-gradient px-8 py-4 text-lg font-semibold rounded-xl"
|
||||||
|
>
|
||||||
|
Features entdecken
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Floating product preview cards -->
|
||||||
|
<div class="mt-16 lg:mt-24 relative animate-scale-in" style="animation-delay: 600ms">
|
||||||
|
<div class="flex flex-col lg:flex-row items-center justify-center gap-6 lg:gap-8">
|
||||||
|
<!-- Left card - tilted -->
|
||||||
|
<div class="card-3d w-full max-w-xs lg:-mr-8 lg:mt-12 order-2 lg:order-1">
|
||||||
|
<div
|
||||||
|
class="card-3d-inner glass rounded-2xl p-5 shadow-xl transform lg:-rotate-6 hover:rotate-0 transition-transform duration-500"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3 mb-4">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-gradient-to-br from-warning-400 to-warning-500 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-alert-triangle" class="w-5 h-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold text-gray-900 dark:text-white text-sm">Risikoprüfung</p>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400">3 Punkte offen</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-4 h-4 rounded bg-warning-100 dark:bg-warning-900/50 flex items-center justify-center">
|
||||||
|
<UIcon name="i-lucide-clock" class="w-2.5 h-2.5 text-warning-600" />
|
||||||
|
</div>
|
||||||
|
<span class="text-xs text-gray-600 dark:text-gray-300">Datenschutz-Folgenabschätzung</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-4 h-4 rounded bg-warning-100 dark:bg-warning-900/50 flex items-center justify-center">
|
||||||
|
<UIcon name="i-lucide-clock" class="w-2.5 h-2.5 text-warning-600" />
|
||||||
|
</div>
|
||||||
|
<span class="text-xs text-gray-600 dark:text-gray-300">Leistungskontrolle prüfen</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-4 h-4 rounded bg-success-100 dark:bg-success-900/50 flex items-center justify-center">
|
||||||
|
<UIcon name="i-lucide-check" class="w-2.5 h-2.5 text-success-600" />
|
||||||
|
</div>
|
||||||
|
<span class="text-xs text-gray-600 dark:text-gray-300">Zugriffsrechte definiert</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Center card - main -->
|
||||||
|
<div class="w-full max-w-md z-10 order-1 lg:order-2">
|
||||||
|
<div class="glass rounded-2xl overflow-hidden shadow-2xl border border-white/50 dark:border-white/10">
|
||||||
|
<!-- Mock header -->
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between px-5 py-4 bg-white/50 dark:bg-gray-900/50 border-b border-gray-200/50 dark:border-gray-700/50"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div
|
||||||
|
class="w-8 h-8 rounded-lg bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-file-text" class="w-4 h-4 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold text-gray-900 dark:text-white text-sm">Microsoft 365</p>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400">Betriebsvereinbarung</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<UBadge color="primary" variant="soft" size="sm">In Bearbeitung</UBadge>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mock content -->
|
||||||
|
<div class="p-5 space-y-4">
|
||||||
|
<!-- Progress section -->
|
||||||
|
<div>
|
||||||
|
<div class="flex justify-between text-sm mb-2">
|
||||||
|
<span class="text-gray-600 dark:text-gray-300 font-medium">Fortschritt</span>
|
||||||
|
<span class="text-primary-600 dark:text-primary-400 font-semibold">67%</span>
|
||||||
|
</div>
|
||||||
|
<div class="h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
|
||||||
|
<div class="h-full w-[67%] bg-gradient-to-r from-primary-500 to-cyan-500 rounded-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status items -->
|
||||||
|
<div class="grid grid-cols-2 gap-3">
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 p-3 rounded-xl bg-success-50 dark:bg-success-900/20 border border-success-200 dark:border-success-800"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-check-circle" class="w-5 h-5 text-success-500" />
|
||||||
|
<div>
|
||||||
|
<p class="text-xs font-medium text-success-700 dark:text-success-300">8 Abschnitte</p>
|
||||||
|
<p class="text-xs text-success-600 dark:text-success-400">abgeschlossen</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 p-3 rounded-xl bg-primary-50 dark:bg-primary-900/20 border border-primary-200 dark:border-primary-800"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-message-square" class="w-5 h-5 text-primary-500" />
|
||||||
|
<div>
|
||||||
|
<p class="text-xs font-medium text-primary-700 dark:text-primary-300">4 Kommentare</p>
|
||||||
|
<p class="text-xs text-primary-600 dark:text-primary-400">neu</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action button -->
|
||||||
|
<button
|
||||||
|
class="w-full py-3 px-4 rounded-xl bg-gradient-to-r from-primary-500 to-cyan-500 text-white font-semibold text-sm hover:from-primary-600 hover:to-cyan-600 transition-all shadow-lg shadow-primary-500/25"
|
||||||
|
>
|
||||||
|
Weiter bearbeiten
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right card - tilted -->
|
||||||
|
<div class="card-3d w-full max-w-xs lg:-ml-8 lg:mt-12 order-3">
|
||||||
|
<div
|
||||||
|
class="card-3d-inner glass rounded-2xl p-5 shadow-xl transform lg:rotate-6 hover:rotate-0 transition-transform duration-500"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3 mb-4">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-gradient-to-br from-success-400 to-success-500 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-check-circle" class="w-5 h-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold text-gray-900 dark:text-white text-sm">Abgeschlossen</p>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400">Letzte Woche</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div class="flex items-center justify-between p-2 rounded-lg bg-success-50 dark:bg-success-900/30">
|
||||||
|
<span class="text-xs text-gray-700 dark:text-gray-200">SAP S/4HANA</span>
|
||||||
|
<UIcon name="i-lucide-check" class="w-4 h-4 text-success-500" />
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between p-2 rounded-lg bg-success-50 dark:bg-success-900/30">
|
||||||
|
<span class="text-xs text-gray-700 dark:text-gray-200">Workday HCM</span>
|
||||||
|
<UIcon name="i-lucide-check" class="w-4 h-4 text-success-500" />
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between p-2 rounded-lg bg-success-50 dark:bg-success-900/30">
|
||||||
|
<span class="text-xs text-gray-700 dark:text-gray-200">Salesforce CRM</span>
|
||||||
|
<UIcon name="i-lucide-check" class="w-4 h-4 text-success-500" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Floating notification - positioned above all cards with higher z-index -->
|
||||||
|
<div
|
||||||
|
class="absolute top-0 right-8 lg:right-16 xl:right-24 z-20 animate-float-slow hidden lg:block"
|
||||||
|
style="animation-delay: 1s"
|
||||||
|
>
|
||||||
|
<div class="glass rounded-xl px-4 py-3 shadow-lg flex items-center gap-3">
|
||||||
|
<div
|
||||||
|
class="w-8 h-8 rounded-full bg-gradient-to-br from-success-400 to-success-500 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-sparkles" class="w-4 h-4 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-semibold text-gray-900 dark:text-white">BV erstellt!</p>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400">Bereit zur Unterschrift</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scroll indicator -->
|
||||||
|
<div class="absolute bottom-8 left-1/2 -translate-x-1/2 animate-bounce">
|
||||||
|
<a
|
||||||
|
href="#betriebsraete"
|
||||||
|
class="flex items-center justify-center w-12 h-12 rounded-full glass text-gray-600 dark:text-gray-300 hover:bg-white/80 dark:hover:bg-gray-800/80 transition-colors"
|
||||||
|
aria-label="Nach unten scrollen"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-chevron-down" class="w-6 h-6" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const description =
|
||||||
|
'Struktur statt Hauruck: Alle relevanten Informationen an einem Ort, klare Prozessschritte und nachvollziehbare Dokumentation – damit Mitbestimmung schneller, belastbarer und dauerhaft updatefähig wird.'
|
||||||
|
</script>
|
||||||
187
landing/app/components/landing/NewsletterSignup.vue
Normal file
187
landing/app/components/landing/NewsletterSignup.vue
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<template>
|
||||||
|
<section id="newsletter" class="relative py-16 lg:py-20 overflow-hidden scroll-mt-20">
|
||||||
|
<!-- Background with gradient and particles -->
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 bg-gradient-to-br from-primary-50 via-cyan-50 to-accent-50 dark:from-gray-950 dark:via-primary-950/30 dark:to-accent-950/30"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Animated particles -->
|
||||||
|
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
||||||
|
<div class="particle" />
|
||||||
|
<div class="particle" />
|
||||||
|
<div class="particle" />
|
||||||
|
<div class="particle" />
|
||||||
|
<div class="particle" />
|
||||||
|
<div class="particle" />
|
||||||
|
<div class="particle" />
|
||||||
|
<div class="particle" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Gradient orbs -->
|
||||||
|
<div class="absolute top-0 left-1/4 w-96 h-96 bg-primary-400/20 rounded-full blur-3xl animate-orb-float" />
|
||||||
|
<div
|
||||||
|
class="absolute bottom-0 right-1/4 w-80 h-80 bg-accent-400/20 rounded-full blur-3xl animate-orb-float"
|
||||||
|
style="animation-delay: 3s"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<!-- Glass card -->
|
||||||
|
<div class="max-w-2xl mx-auto">
|
||||||
|
<div class="glass rounded-3xl p-8 sm:p-12 shadow-2xl">
|
||||||
|
<!-- Icon -->
|
||||||
|
<div class="flex justify-center mb-6">
|
||||||
|
<div
|
||||||
|
class="w-16 h-16 rounded-2xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center animate-float-slow shadow-lg shadow-primary-500/25"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-mail" class="w-8 h-8 text-white" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<h2
|
||||||
|
class="font-heading text-3xl sm:text-4xl font-bold text-center text-gray-900 dark:text-white mb-4 animate-fade-in-up"
|
||||||
|
>
|
||||||
|
Bleiben Sie <span class="gradient-text">informiert</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
<p
|
||||||
|
class="text-center text-lg text-gray-600 dark:text-gray-300 mb-8 animate-fade-in-up"
|
||||||
|
style="animation-delay: 100ms"
|
||||||
|
>
|
||||||
|
Erhalten Sie Updates zur Entwicklung von LegalConsentHub und seien Sie unter den Ersten, die von neuen
|
||||||
|
Funktionen erfahren.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Form -->
|
||||||
|
<UForm
|
||||||
|
:state="formState"
|
||||||
|
:schema="schema"
|
||||||
|
class="animate-fade-in-up"
|
||||||
|
style="animation-delay: 200ms"
|
||||||
|
@submit="onSubmit"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col sm:flex-row gap-3">
|
||||||
|
<UFormField name="email" class="flex-1">
|
||||||
|
<UInput
|
||||||
|
v-model="formState.email"
|
||||||
|
type="email"
|
||||||
|
placeholder="Ihre E-Mail-Adresse"
|
||||||
|
size="xl"
|
||||||
|
:disabled="isLoading || isSuccess"
|
||||||
|
:ui="{
|
||||||
|
root: 'w-full',
|
||||||
|
base: 'rounded-xl bg-white dark:bg-gray-900 border-gray-200 dark:border-gray-700 focus:ring-2 focus:ring-primary-500 focus:border-transparent'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #leading>
|
||||||
|
<UIcon name="i-lucide-mail" class="w-5 h-5 text-gray-400" />
|
||||||
|
</template>
|
||||||
|
</UInput>
|
||||||
|
</UFormField>
|
||||||
|
|
||||||
|
<UButton
|
||||||
|
type="submit"
|
||||||
|
size="xl"
|
||||||
|
:loading="isLoading"
|
||||||
|
:disabled="isSuccess"
|
||||||
|
class="btn-gradient px-8 rounded-xl font-semibold shadow-lg shadow-primary-500/25 whitespace-nowrap"
|
||||||
|
>
|
||||||
|
<template v-if="isSuccess">
|
||||||
|
<UIcon name="i-lucide-check" class="w-5 h-5 mr-2" />
|
||||||
|
<span>Angemeldet!</span>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<span>Anmelden</span>
|
||||||
|
</template>
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</UForm>
|
||||||
|
|
||||||
|
<!-- Success message with animation -->
|
||||||
|
<Transition
|
||||||
|
enter-active-class="transition-all duration-500 ease-out"
|
||||||
|
enter-from-class="opacity-0 scale-95 translate-y-4"
|
||||||
|
enter-to-class="opacity-100 scale-100 translate-y-0"
|
||||||
|
leave-active-class="transition-all duration-300 ease-in"
|
||||||
|
leave-from-class="opacity-100 scale-100 translate-y-0"
|
||||||
|
leave-to-class="opacity-0 scale-95 translate-y-4"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="isSuccess"
|
||||||
|
class="mt-6 p-4 rounded-xl bg-success-100 dark:bg-success-900/30 border border-success-200 dark:border-success-800"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-center gap-3 text-success-700 dark:text-success-300">
|
||||||
|
<div class="w-8 h-8 rounded-full bg-success-500 flex items-center justify-center">
|
||||||
|
<UIcon name="i-lucide-check" class="w-5 h-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<span class="font-medium">Vielen Dank! Wir halten Sie auf dem Laufenden.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<!-- Privacy note -->
|
||||||
|
<p
|
||||||
|
class="mt-6 text-sm text-center text-gray-500 dark:text-gray-400 animate-fade-in-up"
|
||||||
|
style="animation-delay: 300ms"
|
||||||
|
>
|
||||||
|
Mit der Anmeldung stimmen Sie unserer
|
||||||
|
<NuxtLink to="/datenschutz" class="text-primary-600 dark:text-primary-400 hover:underline font-medium">
|
||||||
|
Datenschutzerklärung
|
||||||
|
</NuxtLink>
|
||||||
|
zu. Wir versenden keinen Spam.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Trust indicators -->
|
||||||
|
<div
|
||||||
|
class="mt-8 flex flex-wrap justify-center gap-6 text-sm animate-fade-in-up"
|
||||||
|
style="animation-delay: 400ms"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-2 text-gray-600 dark:text-gray-300">
|
||||||
|
<div class="w-6 h-6 rounded-full bg-success-100 dark:bg-success-900/30 flex items-center justify-center">
|
||||||
|
<UIcon name="i-lucide-shield-check" class="w-3.5 h-3.5 text-success-600 dark:text-success-400" />
|
||||||
|
</div>
|
||||||
|
<span>DSGVO-konform</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-gray-600 dark:text-gray-300">
|
||||||
|
<div class="w-6 h-6 rounded-full bg-success-100 dark:bg-success-900/30 flex items-center justify-center">
|
||||||
|
<UIcon name="i-lucide-lock" class="w-3.5 h-3.5 text-success-600 dark:text-success-400" />
|
||||||
|
</div>
|
||||||
|
<span>Verschlüsselt</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-gray-600 dark:text-gray-300">
|
||||||
|
<div class="w-6 h-6 rounded-full bg-success-100 dark:bg-success-900/30 flex items-center justify-center">
|
||||||
|
<UIcon name="i-lucide-x-circle" class="w-3.5 h-3.5 text-success-600 dark:text-success-400" />
|
||||||
|
</div>
|
||||||
|
<span>Kein Spam</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { z } from 'zod'
|
||||||
|
import type { FormSubmitEvent } from '@nuxt/ui'
|
||||||
|
|
||||||
|
const { isLoading, isSuccess, submitEmail } = useNewsletterSignup()
|
||||||
|
|
||||||
|
const schema = z.object({
|
||||||
|
email: z
|
||||||
|
.string()
|
||||||
|
.min(1, 'Bitte geben Sie eine E-Mail-Adresse ein')
|
||||||
|
.email('Bitte geben Sie eine gültige E-Mail-Adresse ein')
|
||||||
|
})
|
||||||
|
|
||||||
|
type Schema = z.output<typeof schema>
|
||||||
|
|
||||||
|
const formState = reactive<Partial<Schema>>({
|
||||||
|
email: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||||
|
await submitEmail(event.data.email)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
122
landing/app/components/landing/StatsSection.vue
Normal file
122
landing/app/components/landing/StatsSection.vue
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<section
|
||||||
|
class="py-10 lg:py-12 bg-gradient-to-r from-primary-50 via-cyan-50 to-accent-50 dark:from-primary-950/30 dark:via-cyan-950/30 dark:to-accent-950/30"
|
||||||
|
>
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<!-- Stats grid -->
|
||||||
|
<div class="grid grid-cols-2 lg:grid-cols-4 gap-8 lg:gap-12">
|
||||||
|
<div
|
||||||
|
v-for="(stat, index) in stats"
|
||||||
|
:key="index"
|
||||||
|
class="text-center animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${index * 100}ms` }"
|
||||||
|
>
|
||||||
|
<div class="relative inline-block mb-3">
|
||||||
|
<!-- Animated number -->
|
||||||
|
<span ref="counterRefs" class="font-heading text-4xl sm:text-5xl lg:text-6xl font-bold gradient-text">
|
||||||
|
{{ animatedValues[index] }}{{ stat.suffix }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- Decorative glow -->
|
||||||
|
<div class="absolute -inset-4 bg-primary-400/20 blur-2xl rounded-full -z-10 animate-pulse-glow" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-sm sm:text-base text-gray-600 dark:text-gray-300 font-medium">
|
||||||
|
{{ stat.label }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Trust badges -->
|
||||||
|
<div class="mt-10 pt-8 border-t border-gray-200 dark:border-gray-800">
|
||||||
|
<p class="text-center text-sm text-gray-500 dark:text-gray-400 mb-8">Vertrauen & Sicherheit</p>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap justify-center items-center gap-8 lg:gap-12">
|
||||||
|
<div
|
||||||
|
v-for="(badge, index) in trustBadges"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-center gap-3 px-4 py-2 rounded-full bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 shadow-sm hover:shadow-md transition-shadow animate-fade-in-up"
|
||||||
|
:style="{ animationDelay: `${(index + 4) * 100}ms` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-8 h-8 rounded-full bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<UIcon :name="badge.icon" class="w-4 h-4 text-primary-600 dark:text-primary-400" />
|
||||||
|
</div>
|
||||||
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-200">{{ badge.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const stats = [
|
||||||
|
{ value: 70, suffix: '%', label: 'Zeitersparnis im Verfahren' },
|
||||||
|
{ value: 100, suffix: '%', label: 'Revisionssicher dokumentiert' },
|
||||||
|
{ value: 24, suffix: '/7', label: 'Verfügbarkeit' },
|
||||||
|
{ value: 0, suffix: '', label: 'Medienbrüche' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const trustBadges = [
|
||||||
|
{ icon: 'i-lucide-shield-check', label: 'DSGVO-konform' },
|
||||||
|
{ icon: 'i-lucide-server', label: 'Hosting in Deutschland' },
|
||||||
|
{ icon: 'i-lucide-lock', label: 'Ende-zu-Ende verschlüsselt' },
|
||||||
|
{ icon: 'i-lucide-key', label: 'SSO-fähig' }
|
||||||
|
]
|
||||||
|
|
||||||
|
// Animated counter values
|
||||||
|
const animatedValues = ref(stats.map(() => 0))
|
||||||
|
const hasAnimated = ref(false)
|
||||||
|
|
||||||
|
// Counter animation function
|
||||||
|
function animateCounter(index: number, target: number, duration: number = 2000) {
|
||||||
|
const start = 0
|
||||||
|
const startTime = performance.now()
|
||||||
|
|
||||||
|
function update(currentTime: number) {
|
||||||
|
const elapsed = currentTime - startTime
|
||||||
|
const progress = Math.min(elapsed / duration, 1)
|
||||||
|
|
||||||
|
// Easing function (ease-out cubic)
|
||||||
|
const easeOut = 1 - Math.pow(1 - progress, 3)
|
||||||
|
|
||||||
|
animatedValues.value[index] = Math.round(start + (target - start) * easeOut)
|
||||||
|
|
||||||
|
if (progress < 1) {
|
||||||
|
requestAnimationFrame(update)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(update)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start animation when section is visible
|
||||||
|
onMounted(() => {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.isIntersecting && !hasAnimated.value) {
|
||||||
|
hasAnimated.value = true
|
||||||
|
stats.forEach((stat, index) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
animateCounter(index, stat.value)
|
||||||
|
}, index * 200)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ threshold: 0.3 }
|
||||||
|
)
|
||||||
|
|
||||||
|
const section = document.querySelector('section')
|
||||||
|
if (section) {
|
||||||
|
observer.observe(section)
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
observer.disconnect()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
43
landing/app/composables/useNewsletterSignup.ts
Normal file
43
landing/app/composables/useNewsletterSignup.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
export function useNewsletterSignup() {
|
||||||
|
const isLoading = ref(false)
|
||||||
|
const isSuccess = ref(false)
|
||||||
|
const error = ref<string | null>(null)
|
||||||
|
|
||||||
|
const submitEmail = async (_email: string) => {
|
||||||
|
isLoading.value = true
|
||||||
|
error.value = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Simulate API call - replace with actual newsletter service integration
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1500))
|
||||||
|
|
||||||
|
// TODO: Integrate with external newsletter service (e.g., Mailchimp, ConvertKit, etc.)
|
||||||
|
// Example:
|
||||||
|
// await $fetch('/api/newsletter/subscribe', {
|
||||||
|
// method: 'POST',
|
||||||
|
// body: { email }
|
||||||
|
// })
|
||||||
|
|
||||||
|
isSuccess.value = true
|
||||||
|
} catch (e: unknown) {
|
||||||
|
error.value = e instanceof Error ? e.message : 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.'
|
||||||
|
throw e
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
isLoading.value = false
|
||||||
|
isSuccess.value = false
|
||||||
|
error.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLoading,
|
||||||
|
isSuccess,
|
||||||
|
error,
|
||||||
|
submitEmail,
|
||||||
|
reset
|
||||||
|
}
|
||||||
|
}
|
||||||
87
landing/app/pages/index.vue
Normal file
87
landing/app/pages/index.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<div class="landing-page">
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<LandingHeroSection />
|
||||||
|
|
||||||
|
<!-- Stats Section (Social Proof) -->
|
||||||
|
<LandingStatsSection />
|
||||||
|
|
||||||
|
<!-- Benefits for Works Councils -->
|
||||||
|
<LandingBenefitsWorksCouncil />
|
||||||
|
|
||||||
|
<!-- Benefits for Companies -->
|
||||||
|
<LandingBenefitsCompany />
|
||||||
|
|
||||||
|
<!-- Features Grid (Bento Layout) -->
|
||||||
|
<LandingFeaturesGrid />
|
||||||
|
|
||||||
|
<!-- Additional Features / Trust Signals -->
|
||||||
|
<LandingAdditionalFeatures />
|
||||||
|
|
||||||
|
<!-- Framework Agreement Section -->
|
||||||
|
<LandingFrameworkAgreement />
|
||||||
|
|
||||||
|
<!-- Newsletter Signup (Glass-morphism) -->
|
||||||
|
<LandingNewsletterSignup />
|
||||||
|
|
||||||
|
<!-- Expert Access CTA (Gradient Mesh) -->
|
||||||
|
<LandingExpertAccess />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// SEO Meta
|
||||||
|
useSeoMeta({
|
||||||
|
title: 'LegalConsentHub - Digitale Mitbestimmung für IT- und KI-Systeme',
|
||||||
|
description:
|
||||||
|
'Struktur statt Hauruck: Alle relevanten Informationen an einem Ort, klare Prozessschritte und nachvollziehbare Dokumentation – damit Mitbestimmung schneller, belastbarer und dauerhaft updatefähig wird.',
|
||||||
|
ogTitle: 'LegalConsentHub - Digitale Mitbestimmung für IT- und KI-Systeme',
|
||||||
|
ogDescription: 'Strukturierte IT-Mitbestimmung mit klaren Prozessen und revisionssicherer Dokumentation.',
|
||||||
|
ogImage: '/og-image.png',
|
||||||
|
ogType: 'website',
|
||||||
|
twitterCard: 'summary_large_image'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Structured data for SEO
|
||||||
|
useHead({
|
||||||
|
script: [
|
||||||
|
{
|
||||||
|
type: 'application/ld+json',
|
||||||
|
innerHTML: JSON.stringify({
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'SoftwareApplication',
|
||||||
|
name: 'LegalConsentHub',
|
||||||
|
applicationCategory: 'BusinessApplication',
|
||||||
|
operatingSystem: 'Web',
|
||||||
|
description:
|
||||||
|
'Digitale Mitbestimmung für IT- und KI-Systeme. Strukturierte Eingabelogik, klare Prozesse und revisionssichere Dokumentation.',
|
||||||
|
offers: {
|
||||||
|
'@type': 'Offer',
|
||||||
|
price: '0',
|
||||||
|
priceCurrency: 'EUR',
|
||||||
|
description: 'Kontaktieren Sie uns für Preisdetails'
|
||||||
|
},
|
||||||
|
featureList: [
|
||||||
|
'Geführter Mitbestimmungsprozess',
|
||||||
|
'Risikobasierter Assistent',
|
||||||
|
'Versionierung & Audit-Trail',
|
||||||
|
'Automatische BV-/DV-Generierung',
|
||||||
|
'SSO & Governance'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Smooth scrolling for anchor links */
|
||||||
|
.landing-page {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add padding to account for fixed header */
|
||||||
|
.landing-page > :deep(section:first-child) {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
15
landing/eslint.config.mjs
Normal file
15
landing/eslint.config.mjs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// @ts-check
|
||||||
|
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||||
|
|
||||||
|
export default withNuxt({
|
||||||
|
rules: {
|
||||||
|
'vue/html-self-closing': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
html: {
|
||||||
|
void: 'any'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
42
landing/nuxt.config.ts
Normal file
42
landing/nuxt.config.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
export default defineNuxtConfig({
|
||||||
|
compatibilityDate: '2025-07-15',
|
||||||
|
modules: ['@nuxt/ui', '@nuxt/eslint', '@nuxt/fonts'],
|
||||||
|
css: ['~/assets/css/main.css'],
|
||||||
|
devtools: { enabled: true },
|
||||||
|
|
||||||
|
// SSR enabled by default for performance
|
||||||
|
ssr: true,
|
||||||
|
|
||||||
|
// Font configuration - Bricolage Grotesque for headings, DM Sans for body
|
||||||
|
fonts: {
|
||||||
|
families: [
|
||||||
|
{
|
||||||
|
name: 'Bricolage Grotesque',
|
||||||
|
provider: 'google',
|
||||||
|
weights: [400, 500, 600, 700, 800]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'DM Sans',
|
||||||
|
provider: 'google',
|
||||||
|
weights: [400, 500, 600, 700]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// App configuration
|
||||||
|
app: {
|
||||||
|
head: {
|
||||||
|
htmlAttrs: {
|
||||||
|
lang: 'de'
|
||||||
|
},
|
||||||
|
title: 'LegalConsentHub - Digitale Mitbestimmung für IT- und KI-Systeme',
|
||||||
|
meta: [
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
content:
|
||||||
|
'Struktur statt Hauruck: Alle relevanten Informationen an einem Ort, klare Prozessschritte und nachvollziehbare Dokumentation für IT-Mitbestimmung.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
36
landing/package.json
Normal file
36
landing/package.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "nuxt-app",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "nuxt build",
|
||||||
|
"dev": "nuxt dev",
|
||||||
|
"generate": "nuxt generate",
|
||||||
|
"preview": "nuxt preview",
|
||||||
|
"postinstall": "nuxt prepare",
|
||||||
|
"format": "prettier . --write",
|
||||||
|
"type-check": "nuxi typecheck",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"lint:fix": "eslint . --fix",
|
||||||
|
"check": "pnpm run lint && pnpm run type-check && pnpm run format && pnpm run test"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nuxt/eslint": "1.12.1",
|
||||||
|
"@nuxt/fonts": "^0.12.1",
|
||||||
|
"@nuxt/ui": "4.3.0",
|
||||||
|
"eslint": "9.39.2",
|
||||||
|
"nuxt": "4.2.2",
|
||||||
|
"vue": "3.5.26",
|
||||||
|
"vue-router": "4.6.4",
|
||||||
|
"zod": "^4.3.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "^3.7.4",
|
||||||
|
"typescript": "5.9.3"
|
||||||
|
},
|
||||||
|
"volta": {
|
||||||
|
"node": "22.16.0",
|
||||||
|
"pnpm": "10.11.0"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.13.1+sha512.37ebf1a5c7a30d5fabe0c5df44ee8da4c965ca0c5af3dbab28c3a1681b70a256218d05c81c9c0dcf767ef6b8551eb5b960042b9ed4300c59242336377e01cfad"
|
||||||
|
}
|
||||||
10306
landing/pnpm-lock.yaml
generated
Normal file
10306
landing/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
landing/public/favicon.ico
Normal file
BIN
landing/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
2
landing/public/robots.txt
Normal file
2
landing/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
User-Agent: *
|
||||||
|
Disallow:
|
||||||
18
landing/tsconfig.json
Normal file
18
landing/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
// https://nuxt.com/docs/guide/concepts/typescript
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./.nuxt/tsconfig.app.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./.nuxt/tsconfig.server.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./.nuxt/tsconfig.shared.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./.nuxt/tsconfig.node.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user