chahinebrini c1edef8abd feat(magic): RebreakMagic device-binding + DNS profile
- backend: /api/magic/{register,devices,profile,release} + AdGuard provisioning + 24h cooldown
- prisma: magic_binding_fields migration (additive on UserDevice)
- mac-app: Phase 2 - Login + MacRegistration + Profile install
- marketing: landing section + /download/rebreakmagic + DMG
- lyra: forbidden phrases + RebreakMagic coach guidance
2026-06-02 09:15:19 +02:00

507 lines
25 KiB
Vue

<template>
<div class="bg-default overflow-x-hidden">
<!-- HERO -->
<section class="relative min-h-[80dvh] flex flex-col items-center justify-center px-4 text-center">
<div class="absolute inset-0 bg-linear-to-b from-gray-950 via-primary-950/20 to-gray-950 pointer-events-none" />
<div
class="absolute top-1/3 left-1/2 -translate-x-1/2 -translate-y-1/2 w-175 h-175 bg-primary-900/15 rounded-full blur-3xl pointer-events-none" />
<div class="relative max-w-3xl mx-auto">
<div
class="inline-flex items-center gap-2 bg-primary-950/60 border border-primary-800/40 rounded-full px-4 py-1.5 text-sm text-primary-300 mb-8">
<UIcon name="i-heroicons-user-group" class="text-primary-400" />
{{ $t('landing.hero_badge') }}
</div>
<h1 class="text-3xl md:text-7xl font-black text-highlighted leading-[1.05] tracking-tight mb-6">
{{ $t('landing.hero_title') }}
<span class="block text-2xl text-transparent bg-clip-text bg-linear-to-r from-primary-300 to-primary-500">
{{ $t('landing.hero_subtitle') }}
</span>
</h1>
<p class="text-sm text-muted max-w-lg mx-auto mb-10 leading-relaxed">
{{ $t('landing.hero_text') }}
</p>
<img src="/encrypted.svg" alt="Community Illustration" class="w-15 max-w-md mx-auto mb-10" />
<div class="flex flex-col sm:flex-row items-center justify-center gap-4">
<a href="https://apps.apple.com/app/rebreak" target="_blank" rel="noopener">
<UButton size="xl" class="px-8">
<UIcon name="i-heroicons-bolt" />
{{ $t('landing.cta_start') }}
</UButton>
</a>
</div>
<div class="flex justify-center gap-x-10 mt-16 text-center">
<div>
<div class="text-3xl font-extrabold text-highlighted">
<AnimatedCounter :target="300" :duration="2000" />k+
</div>
<div class="text-xs text-muted mt-1">{{ $t('landing.stat_affected') }}</div>
</div>
<div>
<div class="text-3xl font-extrabold text-primary-400">
<AnimatedCounter :target="208" :duration="1600" :delay="200" />k+
</div>
<div class="text-xs text-muted mt-1">{{ $t('landing.stat_blocked') }}</div>
</div>
<div>
<div class="text-3xl font-extrabold text-primary-400">3,99</div>
<div class="text-xs text-muted mt-1">{{ $t('landing.stat_from') }}</div>
</div>
</div>
<div class="mt-8">
<UButton size="lg" variant="ghost" color="neutral" @click="scrollToInfo">
{{ $t('landing.more_info') }}
<UIcon name="i-heroicons-chevron-down" />
</UButton>
</div>
</div>
</section>
<!-- INFO SECTIONS -->
<div v-if="showInfoSections" ref="infoSections">
<!-- Blocker -->
<section class="py-8 px-4">
<div v-motion :initial="{ opacity: 0, y: 50 }" :visible="{ opacity: 1, y: 0, transition: { duration: 700 } }"
class="max-w-6xl mx-auto grid lg:grid-cols-2 gap-16 items-center">
<div class="order-2 lg:order-1">
<div
class="inline-flex items-center gap-2 bg-primary-950/60 border border-primary-800/40 rounded-full px-3 py-1 text-xs text-primary-300 mb-6">
<UIcon name="i-heroicons-shield-exclamation" />
{{ $t('landing.blocker_badge') }}
</div>
<h2 class="text-4xl md:text-5xl font-black text-highlighted leading-tight mb-6">
<AnimatedCounter :target="100" :duration="2500" />k+ {{ $t('landing.blocker_title_domains') }}<br />
<span class="text-primary-400">{{ $t('landing.blocker_title_activated') }}</span>
</h2>
<p class="text-lg text-muted leading-relaxed mb-8">
{{ $t('landing.blocker_desc') }}
</p>
<ul class="space-y-3 text-sm text-default">
<li v-for="f in blockerFeatures" :key="f" class="flex items-center gap-3">
<UIcon name="i-heroicons-check-circle" class="text-primary-400 shrink-0" />{{ f }}
</li>
</ul>
</div>
<div class="order-1 lg:order-2 flex items-center justify-center">
<div
class="w-72 h-72 rounded-3xl bg-linear-to-br from-primary-950/60 to-primary-900/20 border border-primary-800/20 flex items-center justify-center shadow-2xl shadow-primary-950/50">
<UIcon name="i-heroicons-shield-check" class="text-primary-400 w-32 h-32" />
</div>
</div>
</div>
</section>
<!-- OASIS Warning -->
<section class="py-8 px-4">
<div v-motion :initial="{ opacity: 0, y: 40 }" :visible="{ opacity: 1, y: 0, transition: { duration: 700 } }"
class="max-w-4xl mx-auto">
<div class="bg-orange-950/20 border border-orange-800/20 rounded-3xl p-6 md:p-8">
<div
class="inline-flex items-center gap-2 bg-orange-950/60 border border-orange-800/40 rounded-full px-3 py-1 text-xs text-orange-300 mb-5">
<UIcon name="i-heroicons-exclamation-triangle" />
{{ $t('landing.oasis_badge') }}
</div>
<h2 class="text-2xl md:text-3xl font-black text-highlighted leading-tight mb-4">
{{ $t('landing.oasis_title') }}<br class="hidden sm:block" />
<span class="text-orange-400">{{ $t('landing.oasis_subtitle') }}</span>
</h2>
<p class="text-muted leading-relaxed mb-6 max-w-2xl">
{{ $t('landing.oasis_desc') }}
</p>
<div class="grid sm:grid-cols-3 gap-3">
<div class="bg-elevated rounded-2xl p-4">
<div class="text-orange-400 font-black text-2xl mb-1">50+</div>
<div class="text-xs text-muted leading-relaxed">{{ $t('landing.oasis_new_domains') }}</div>
</div>
<div class="bg-elevated rounded-2xl p-4">
<div class="text-orange-400 font-black text-2xl mb-1">Offshore</div>
<div class="text-xs text-muted leading-relaxed">{{ $t('landing.oasis_offshore') }}</div>
</div>
<div class="bg-elevated rounded-2xl p-4">
<div class="text-primary-400 font-black text-2xl mb-1">208.000+</div>
<div class="text-xs text-muted leading-relaxed">{{ $t('landing.oasis_updated') }}</div>
</div>
</div>
</div>
</div>
</section>
<!-- Streak -->
<section class="py-8 px-4 bg-linear-to-b from-transparent via-orange-950/10 to-transparent">
<div v-motion :initial="{ opacity: 0, y: 50 }" :visible="{ opacity: 1, y: 0, transition: { duration: 700 } }"
class="max-w-6xl mx-auto grid lg:grid-cols-2 gap-16 items-center">
<div class="flex items-center justify-center">
<div class="relative">
<div
class="w-72 h-72 rounded-3xl bg-linear-to-br from-orange-950/60 to-yellow-900/20 border border-orange-800/20 flex flex-col items-center justify-center shadow-2xl shadow-orange-950/50 gap-2">
<UIcon name="i-heroicons-fire" class="text-orange-400 w-20 h-20" />
<div class="text-5xl font-black text-highlighted">
<AnimatedCounter :target="47" :duration="2800" />
</div>
<div class="text-orange-300 text-sm font-medium">{{ $t('landing.streak_days_free') }}</div>
</div>
<div
class="absolute -bottom-4 -right-4 bg-green-950 border border-green-700/40 rounded-2xl px-4 py-2 text-sm">
<span class="text-green-400 font-bold">+
<AnimatedCounter :target="423" :duration="3000" />
</span>
<span class="text-muted ml-1">{{ $t('landing.streak_saved') }}</span>
</div>
</div>
</div>
<div>
<div
class="inline-flex items-center gap-2 bg-orange-950/60 border border-orange-800/40 rounded-full px-3 py-1 text-xs text-orange-300 mb-6">
<UIcon name="i-heroicons-fire" />
{{ $t('landing.streak_badge') }}
</div>
<h2 class="text-4xl md:text-5xl font-black text-highlighted leading-tight mb-6">
{{ $t('landing.streak_title') }}<br />
<span class="text-orange-400">{{ $t('landing.streak_subtitle') }}</span>
</h2>
<p class="text-lg text-muted leading-relaxed">
{{ $t('landing.streak_desc') }}
</p>
</div>
</div>
</section>
<!-- SOS + Atemübungen -->
<section class="py-8 px-4">
<div v-motion :initial="{ opacity: 0, y: 50 }" :visible="{ opacity: 1, y: 0, transition: { duration: 700 } }"
class="max-w-6xl mx-auto">
<div class="text-center mb-10">
<div
class="inline-flex items-center gap-2 bg-orange-950/60 border border-orange-800/40 rounded-full px-3 py-1 text-xs text-orange-300 mb-5">
<UIcon name="i-heroicons-bolt" />
{{ $t('landing.crisis_badge') }}
</div>
<h2 class="text-4xl md:text-5xl font-black text-highlighted leading-tight">
{{ $t('landing.crisis_title') }}<br />
<span class="text-orange-400">{{ $t('landing.crisis_subtitle') }}</span>
</h2>
</div>
<div class="grid md:grid-cols-2 gap-6">
<!-- SOS -->
<div class="bg-orange-950/20 border border-orange-800/20 rounded-3xl p-6 flex flex-col gap-4">
<div class="flex items-center gap-3">
<div
class="w-10 h-10 rounded-xl bg-orange-900/60 border border-orange-700/30 flex items-center justify-center shrink-0">
<UIcon name="i-heroicons-bolt" class="text-orange-400 text-xl" />
</div>
<div>
<div class="font-bold text-highlighted">{{ $t('landing.sos_title') }}</div>
<div class="text-xs text-orange-400">{{ $t('landing.sos_subtitle') }}</div>
</div>
</div>
<p class="text-sm text-muted leading-relaxed">
{{ $t('landing.sos_desc') }}
</p>
<div class="grid grid-cols-2 gap-2">
<div class="bg-elevated rounded-xl px-3 py-2.5 flex items-center gap-2">
<span class="text-xl">😤</span>
<span class="text-sm text-default">{{ $t('landing.sos_angry') }}</span>
</div>
<div class="bg-elevated rounded-xl px-3 py-2.5 flex items-center gap-2">
<span class="text-xl">😔</span>
<span class="text-sm text-default">{{ $t('landing.sos_sad') }}</span>
</div>
<div class="bg-elevated rounded-xl px-3 py-2.5 flex items-center gap-2">
<span class="text-xl">😰</span>
<span class="text-sm text-default">{{ $t('landing.sos_stressed') }}</span>
</div>
<div class="bg-elevated rounded-xl px-3 py-2.5 flex items-center gap-2">
<span class="text-xl">😶</span>
<span class="text-sm text-default">{{ $t('landing.sos_empty') }}</span>
</div>
</div>
</div>
<!-- Atemübungen -->
<div class="bg-primary-950/20 border border-primary-800/20 rounded-3xl p-6 flex flex-col gap-4">
<div class="flex items-center gap-3">
<div
class="w-10 h-10 rounded-xl bg-primary-900/60 border border-primary-700/30 flex items-center justify-center shrink-0">
<UIcon name="i-heroicons-heart" class="text-primary-400 text-xl" />
</div>
<div>
<div class="font-bold text-highlighted">{{ $t('landing.breathing_title') }}</div>
<div class="text-xs text-primary-400">{{ $t('landing.breathing_subtitle') }}</div>
</div>
</div>
<p class="text-sm text-muted leading-relaxed">
{{ $t('landing.breathing_desc') }}
</p>
<div class="flex items-center justify-center py-6">
<div class="relative flex items-center justify-center">
<div
class="w-24 h-24 rounded-full bg-primary-900/20 border border-primary-700/20 absolute animate-ping opacity-20">
</div>
<div
class="w-20 h-20 rounded-full bg-primary-900/30 border border-primary-700/30 absolute opacity-40 scale-110">
</div>
<div
class="w-16 h-16 rounded-full bg-primary-900/50 border border-primary-600/40 flex items-center justify-center">
<span class="text-primary-200 text-xs font-bold">{{ $t('landing.breathing_breathe') }}</span>
</div>
</div>
</div>
<div class="flex justify-between text-[11px] px-2">
<span class="text-primary-400 font-medium">{{ $t('landing.breathing_inhale') }}</span>
<span class="text-dimmed"></span>
<span class="text-muted">{{ $t('landing.breathing_hold') }}</span>
<span class="text-dimmed"></span>
<span class="text-muted">{{ $t('landing.breathing_exhale') }}</span>
</div>
</div>
</div>
</div>
</section>
<!-- Coach + Community -->
<section class="py-8 px-4 bg-linear-to-b from-transparent via-primary-950/10 to-transparent">
<div v-motion :initial="{ opacity: 0, y: 50 }" :visible="{ opacity: 1, y: 0, transition: { duration: 700 } }"
class="max-w-6xl mx-auto grid lg:grid-cols-2 gap-16 items-center">
<div class="flex items-center justify-center">
<div class="w-72 bg-elevated border border-default rounded-3xl p-6 space-y-3 shadow-2xl">
<div class="flex items-center gap-2 mb-2">
<div class="w-8 h-8 rounded-full bg-primary-900 flex items-center justify-center">
<UIcon name="i-heroicons-cpu-chip" class="text-primary-400 text-sm" />
</div>
<span class="text-sm font-medium text-highlighted">{{ $t('landing.coach_label') }}</span>
</div>
<div v-for="msg in chatMessages" :key="msg.text" :class="msg.isBot ? 'mr-8' : 'ml-8 text-right'">
<div :class="msg.isBot
? 'bg-muted text-default rounded-2xl rounded-tl-sm'
: 'bg-primary-600 text-white rounded-2xl rounded-tr-sm'
" class="inline-block px-3 py-2 text-xs leading-relaxed max-w-[90%]">
{{ msg.text }}
</div>
</div>
</div>
</div>
<div>
<div
class="inline-flex items-center gap-2 bg-primary-950/60 border border-primary-800/40 rounded-full px-3 py-1 text-xs text-primary-300 mb-6">
<UIcon name="i-heroicons-user-group" />
{{ $t('landing.coach_badge') }}
</div>
<h2 class="text-4xl md:text-5xl font-black text-highlighted leading-tight mb-6">
{{ $t('landing.coach_title') }}<br />
<span class="text-primary-400">{{ $t('landing.coach_subtitle') }}</span>
</h2>
<p class="text-lg text-muted leading-relaxed mb-6">
{{ $t('landing.coach_desc') }}
</p>
<div class="bg-primary-950/30 border border-primary-800/20 rounded-2xl p-4 space-y-3">
<div class="flex items-center gap-2">
<UIcon name="i-heroicons-rocket-launch" class="text-primary-400" />
<span class="text-xs font-bold text-primary-300 uppercase tracking-wider">{{
$t('landing.founding_badge') }}</span>
</div>
<p class="text-sm text-muted">{{ $t('landing.founding_desc', { count: 50 }) }}</p>
<div class="flex items-center gap-3">
<div class="flex-1 bg-muted rounded-full h-1.5 overflow-hidden">
<div class="bg-linear-to-r from-primary-500 to-orange-500 h-full rounded-full" style="width: 34%">
</div>
</div>
<span class="text-xs text-muted shrink-0">{{ $t('landing.founding_slots', { current: 17, total: 50 })
}}</span>
</div>
<a href="https://apps.apple.com/app/rebreak" target="_blank" rel="noopener">
<UButton size="sm" class="w-full">
<UIcon name="i-heroicons-bolt" />
{{ $t('landing.founding_cta') }}
</UButton>
</a>
</div>
</div>
</div>
</section>
<!-- Mail Agent -->
<section class="py-8 px-4 bg-linear-to-b from-transparent via-primary-950/10 to-transparent">
<div v-motion :initial="{ opacity: 0, y: 50 }" :visible="{ opacity: 1, y: 0, transition: { duration: 700 } }"
class="max-w-6xl mx-auto grid lg:grid-cols-2 gap-16 items-center">
<div>
<div
class="inline-flex items-center gap-2 bg-primary-950/60 border border-primary-800/40 rounded-full px-3 py-1 text-xs text-primary-300 mb-6">
<UIcon name="i-heroicons-envelope" />
{{ $t('landing.mail_badge') }}
</div>
<h2 class="text-4xl md:text-5xl font-black text-highlighted leading-tight mb-6">
{{ $t('landing.mail_title') }}<br />
<span class="text-primary-400">{{ $t('landing.mail_subtitle') }}</span>
</h2>
<p class="text-lg text-muted leading-relaxed mb-6">
{{ $t('landing.mail_desc') }}
</p>
<ul class="space-y-3 text-sm text-default">
<li class="flex items-center gap-3">
<UIcon name="i-heroicons-check-circle" class="text-primary-400 shrink-0" />
{{ $t('landing.mail_feat_providers') }}
</li>
<li class="flex items-center gap-3">
<UIcon name="i-heroicons-check-circle" class="text-primary-400 shrink-0" />
{{ $t('landing.mail_feat_intervals') }}
</li>
<li class="flex items-center gap-3">
<UIcon name="i-heroicons-check-circle" class="text-primary-400 shrink-0" />
{{ $t('landing.mail_feat_privacy') }}
</li>
</ul>
</div>
<!-- Mock Mail-App UI -->
<div class="flex items-center justify-center">
<div class="w-72 bg-elevated border border-default rounded-3xl p-5 shadow-2xl space-y-4">
<div class="grid grid-cols-3 gap-2 text-center">
<div class="bg-muted rounded-xl p-2.5">
<div class="text-xl font-black text-primary-400">276</div>
<div class="text-[10px] text-muted mt-0.5">{{ $t('landing.mail_mock_blocked') }}</div>
</div>
<div class="bg-muted rounded-xl p-2.5">
<div class="text-xl font-black text-highlighted">1450</div>
<div class="text-[10px] text-muted mt-0.5">{{ $t('landing.mail_mock_scanned') }}</div>
</div>
<div class="bg-muted rounded-xl p-2.5">
<div class="text-xl font-black text-orange-400">19%</div>
<div class="text-[10px] text-muted mt-0.5">{{ $t('landing.mail_mock_rate') }}</div>
</div>
</div>
<div>
<div class="flex items-center justify-between mb-2">
<div class="text-xs text-muted font-medium">{{ $t('landing.mail_mock_accounts') }}</div>
<span class="text-xs text-primary-400 font-medium">2/5</span>
</div>
<div class="bg-muted rounded-xl p-3">
<div class="flex items-center gap-2">
<div
class="w-6 h-6 rounded-full bg-primary-900/60 border border-primary-800/30 flex items-center justify-center shrink-0">
<UIcon name="i-heroicons-envelope" class="text-primary-400 text-xs" />
</div>
<div class="flex-1 min-w-0">
<div class="text-xs text-highlighted font-medium truncate">user@example.com</div>
<div class="text-[10px] text-primary-400">4 blockiert · 06.04.</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- RebreakMagic (Lock-Modus, optional) -->
<section class="py-8 px-4">
<div v-motion :initial="{ opacity: 0, y: 50 }" :visible="{ opacity: 1, y: 0, transition: { duration: 700 } }"
class="max-w-6xl mx-auto grid lg:grid-cols-2 gap-16 items-center">
<div>
<div
class="inline-flex items-center gap-2 bg-primary-950/60 border border-primary-800/40 rounded-full px-3 py-1 text-xs text-primary-300 mb-6">
<UIcon name="i-heroicons-lock-closed" />
{{ $t('landing.magic_badge') }}
</div>
<h2 class="text-4xl md:text-5xl font-black text-highlighted leading-tight mb-6">
{{ $t('landing.magic_title') }}<br />
<span class="text-primary-400">{{ $t('landing.magic_subtitle') }}</span>
</h2>
<p class="text-lg text-muted leading-relaxed mb-8">
{{ $t('landing.magic_desc') }}
</p>
<ul class="space-y-3 text-sm text-default mb-8">
<li class="flex items-center gap-3">
<UIcon name="i-heroicons-check-circle" class="text-primary-400 shrink-0" />
{{ $t('landing.magic_feat_noreset') }}
</li>
<li class="flex items-center gap-3">
<UIcon name="i-heroicons-check-circle" class="text-primary-400 shrink-0" />
{{ $t('landing.magic_feat_speed') }}
</li>
<li class="flex items-center gap-3">
<UIcon name="i-heroicons-check-circle" class="text-primary-400 shrink-0" />
{{ $t('landing.magic_feat_lock') }}
</li>
<li class="flex items-center gap-3">
<UIcon name="i-heroicons-check-circle" class="text-primary-400 shrink-0" />
{{ $t('landing.magic_feat_trustee') }}
</li>
</ul>
<NuxtLink to="/download/rebreakmagic">
<UButton size="lg" class="px-6">
<UIcon name="i-heroicons-arrow-down-tray" />
{{ $t('landing.magic_cta') }}
</UButton>
</NuxtLink>
<p class="text-xs text-muted mt-3">{{ $t('landing.magic_note') }}</p>
</div>
<div class="flex items-center justify-center">
<div
class="w-72 h-72 rounded-3xl bg-linear-to-br from-primary-950/60 to-primary-900/20 border border-primary-800/20 flex items-center justify-center shadow-2xl shadow-primary-950/50 relative">
<UIcon name="i-heroicons-sparkles" class="text-primary-400 w-32 h-32" />
<div class="absolute bottom-4 left-4 right-4 bg-gray-950/80 backdrop-blur rounded-xl px-3 py-2 flex items-center gap-2">
<UIcon name="i-heroicons-computer-desktop" class="text-primary-400 text-sm" />
<span class="text-xs text-highlighted font-medium">RebreakMagic.app</span>
<span class="text-[10px] text-muted ml-auto">~2 min</span>
</div>
</div>
</div>
</div>
</section>
<!-- FINAL CTA -->
<section class="py-16 px-4 pb-24 text-center relative">
<div class="absolute inset-0 bg-linear-to-t from-primary-950/20 to-transparent pointer-events-none" />
<div class="relative max-w-2xl mx-auto">
<h2 class="text-5xl font-black text-highlighted mb-4">{{ $t('landing.final_title') }}</h2>
<p class="text-muted mb-10 text-lg">
{{ $t('landing.final_desc') }}
</p>
<a href="https://apps.apple.com/app/rebreak" target="_blank" rel="noopener">
<UButton size="xl" class="px-12">
<UIcon name="i-heroicons-bolt" />
{{ $t('landing.final_cta') }}
</UButton>
</a>
</div>
</section>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({ layout: "default" });
const { t } = useI18n();
const infoSections = ref<HTMLElement | null>(null);
const showInfoSections = ref(true);
onMounted(() => {
if (window.innerWidth < 768) showInfoSections.value = false;
});
function scrollToInfo() {
showInfoSections.value = true;
nextTick(() => infoSections.value?.scrollIntoView({ behavior: "smooth" }));
}
const blockerFeatures = computed(() => [
t('landing.blocker_feat_platforms'),
t('landing.blocker_feat_updated'),
t('landing.blocker_feat_custom'),
t('landing.blocker_feat_cooldown'),
]);
const chatMessages = computed(() => [
{ text: t('landing.chat_msg_1'), isBot: false },
{ text: t('landing.chat_msg_2'), isBot: true },
{ text: t('landing.chat_msg_3'), isBot: false },
{ text: t('landing.chat_msg_4'), isBot: true },
]);
</script>