Files
OpenSquawk/app/pages/index.vue
itsrubberduck e91c3c6aa9 init
2025-09-14 21:09:47 +02:00

414 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="bg-[#0b1020] text-white antialiased selection:bg-cyan-400/30">
<!-- NAV -->
<header class="sticky top-0 z-50 bg-[#0b1020]/70 backdrop-blur border-b border-white/10">
<nav class="mx-auto max-w-[1200px] px-4 py-3 flex items-center justify-between">
<a href="#" class="flex items-center gap-2 font-semibold tracking-tight">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" class="text-cyan-400"><path d="M12 3l8 4v10l-8 4-8-4V7l8-4z" stroke="currentColor" stroke-width="1.5"/><path d="M12 7l4 2v6l-4 2-4-2V9l4-2z" fill="currentColor" class="opacity-60"/></svg>
<span class="text-white">OpenSquawk</span>
</a>
<div class="hidden md:flex gap-6 text-sm">
<a href="#features" class="hover:text-cyan-300">Features</a>
<a href="#learn" class="hover:text-cyan-300">Lernpfad</a>
<a href="#pricing" class="hover:text-cyan-300">Preise</a>
<a href="#opensource" class="hover:text-cyan-300">OpenSource</a>
<a href="#faq" class="hover:text-cyan-300">FAQ</a>
</div>
<div class="flex items-center gap-2">
<a href="#demo" class="btn btn-ghost text-sm">LiveDemo</a>
<a href="#cta" class="btn btn-primary text-sm">Frühzugang</a>
</div>
</nav>
</header>
<!-- HERO -->
<section class="gradient-hero relative overflow-hidden">
<div class="absolute inset-0 pointer-events-none">
<div class="absolute -top-24 right-0 w-[600px] h-[600px] bg-cyan-500/10 rounded-full blur-3xl" />
</div>
<div class="mx-auto max-w-[1200px] px-4 pt-16 pb-12 md:pt-24 md:pb-20">
<div class="max-w-2xl">
<span class="chip mb-4">OpenSource · AIATC · Simulator</span>
<h1 class="text-4xl md:text-6xl font-semibold leading-tight">OpenSquawk<br><span class="text-cyan-400">AIATC, offen & bezahlbar</span></h1>
<p class="mt-4 md:mt-6 text-white/80 text-base md:text-lg">Offene Alternative für AIATC im Flugsimulator. Lerne echte Phraseologie, übe sichere Abläufe und steige Schritt für Schritt Richtung VATSIM ein. Optional als gehosteter Plan so günstig wie möglich.</p>
<div class="flex flex-col sm:flex-row gap-3 mt-6">
<a href="#cta" class="btn btn-primary text-base">Frühzugang sichern</a>
<a href="#video" class="btn btn-ghost text-base">1MinÜberblick ansehen</a>
</div>
<div class="mt-6 flex items-center gap-4 text-white/70 text-sm">
<div class="flex -space-x-3">
<img alt="avatar" src="https://i.pravatar.cc/40?img=1" class="w-8 h-8 rounded-full border border-white/10" />
<img alt="avatar" src="https://i.pravatar.cc/40?img=2" class="w-8 h-8 rounded-full border border-white/10" />
<img alt="avatar" src="https://i.pravatar.cc/40?img=3" class="w-8 h-8 rounded-full border border-white/10" />
</div>
<p><b>1500+</b> Pilot:innen im EarlyAccess</p>
</div>
</div>
<div class="mt-10 md:mt-16">
<div class="card relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-r from-cyan-500/10 via-blue-500/5 to-transparent" />
<img src="https://images.unsplash.com/photo-1509749837427-392dfae2dbd1?q=80&w=1600&auto=format&fit=crop" alt="Cockpit" class="rounded-xl w-full object-cover" />
<div class="absolute bottom-3 right-3 text-xs text-white/70 bg-black/40 px-2 py-1 rounded">Symbolbild</div>
</div>
</div>
</div>
</section>
<!-- SOCIAL PROOF / LOGOS -->
<section class="py-10 border-t border-white/10 bg-[#0a0f1c]">
<div class="mx-auto max-w-[1200px] px-4">
<div class="grid grid-cols-2 md:grid-cols-4 gap-6 items-center opacity-80">
<div class="text-center text-white/60">MSFS</div>
<div class="text-center text-white/60">XPlane</div>
<div class="text-center text-white/60">VATSIM* (Lernpfad)</div>
<div class="text-center text-white/60">IVAO* (Lernpfad)</div>
</div>
</div>
</section>
<!-- FEATURES -->
<section id="features" class="py-16 md:py-24 bg-gradient-to-b from-[#0a0f1c] to-[#0b1020]">
<div class="mx-auto max-w-[1200px] px-4">
<div class="max-w-2xl mb-10">
<h2 class="text-3xl md:text-4xl font-semibold">Warum OpenSquawk?</h2>
<p class="mt-3 text-white/80">EchtzeitFunk mit KI, lernfreundliche Erklärungen und offene Architektur damit du souverän taxi, departure, approach & landing beherrschst.</p>
</div>
<div class="grid md:grid-cols-3 gap-6">
<div class="card">
<div class="flex items-center gap-3">
<div class="p-2 rounded-lg bg-cyan-500/20 border border-cyan-400/20"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><path d="M12 3l8 4v10l-8 4-8-4V7l8-4z" stroke="#22d3ee"/></svg></div>
<h3 class="font-semibold text-lg">AIATC in Echtzeit</h3>
</div>
<p class="mt-3 text-white/80">StreamingASR, LLMVerständnis & TTS Stimmen. Klar, schnell, latenzarm optimiert für Phraseologie.</p>
</div>
<div class="card">
<div class="flex items-center gap-3">
<div class="p-2 rounded-lg bg-cyan-500/20 border border-cyan-400/20"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="#22d3ee"/></svg></div>
<h3 class="font-semibold text-lg">Lernpfad VATSIM</h3>
</div>
<p class="mt-3 text-white/80">Geführte Übungen, Checks & Erklärungen vom Readback bis zu komplexen Clearances. Schrittweise Richtung OnlineNetzwerke.</p>
</div>
<div class="card">
<div class="flex items-center gap-3">
<div class="p-2 rounded-lg bg-cyan-500/20 border border-cyan-400/20"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><path d="M5 12h14M12 5v14" stroke="#22d3ee"/></svg></div>
<h3 class="font-semibold text-lg">OpenSource + Hosted</h3>
</div>
<p class="mt-3 text-white/80">Selbst hosten oder unseren günstigen Plan nutzen. Transparente Architektur, CommunityPlugins & APIs.</p>
</div>
</div>
<div class="grid md:grid-cols-2 gap-6 mt-6">
<div class="card">
<h3 class="font-semibold text-lg">TaxiRouten & Ground Awareness</h3>
<p class="mt-3 text-white/80">OSM/apt.datbasierte TaxiwayGraphen, A*Routing zu Holding Points, progressive Anweisungen mit VisualOverlay.</p>
<ul class="mt-3 space-y-2 text-white/70 text-sm list-disc list-inside">
<li>Taxi to RWY 25C via A, A5, B2</li>
<li>HotspotVermeidung & progressive Readbacks</li>
<li>Optional: NOTAM/ATIS Einbindung</li>
</ul>
</div>
<div class="card">
<h3 class="font-semibold text-lg">TechStack</h3>
<p class="mt-3 text-white/80">StreamingASR, LLMDialog, TTS orchestriert mit WebRTC/WS. OfflineFallbacks möglich.</p>
<div class="mt-4 grid grid-cols-2 gap-3 text-sm">
<div class="glass rounded-xl p-3">ASR: Whisper/Alternativen (API)</div>
<div class="glass rounded-xl p-3">LLM: GPT5Nano/4oMini etc.</div>
<div class="glass rounded-xl p-3">TTS: neural voices</div>
<div class="glass rounded-xl p-3">Routing: A* / Dijkstra</div>
</div>
</div>
</div>
</div>
</section>
<!-- LEARN PATH -->
<section id="learn" class="py-16 md:py-24 bg-[#0b1020]">
<div class="mx-auto max-w-[1200px] px-4">
<div class="grid md:grid-cols-2 gap-8 items-center">
<div>
<h2 class="text-3xl md:text-4xl font-semibold">ATC verstehen Schritt für Schritt</h2>
<p class="mt-3 text-white/80">Geführter Lernmodus: Hören, Nachsprechen, Feedback. Vom ersten Ready to taxi bis zur komplexen STAR/ApproachFreigabe.</p>
<ol class="mt-5 space-y-3 text-white/80">
<li class="flex gap-3"><span class="chip">1</span><span><b>Basics</b>: Alphabet, Zahlen, StandardPhrasen, Readback.</span></li>
<li class="flex gap-3"><span class="chip">2</span><span><b>Ground</b>: TaxiFlows, Hotspots, Holdingshort.</span></li>
<li class="flex gap-3"><span class="chip">3</span><span><b>Departure</b>: SID, Altitudes, Heading/Speed.</span></li>
<li class="flex gap-3"><span class="chip">4</span><span><b>Arrival</b>: STAR, Vectors, Approach Briefing.</span></li>
<li class="flex gap-3"><span class="chip">5</span><span><b>VATSIM</b>: Checklisten, Etiquette, LiveÜbungen.</span></li>
</ol>
<div class="mt-6 flex gap-3">
<a href="#cta" class="btn btn-primary">Jetzt loslegen</a>
<a href="#faq" class="btn btn-ghost">FAQ</a>
</div>
</div>
<div class="card">
<ClientOnly>
<video id="video" class="w-full rounded-xl" autoplay muted loop playsinline poster="https://images.unsplash.com/photo-1518306724291-1f5c9b4d2452?q=80&w=1600&auto=format&fit=crop">
<source src="https://cdn.coverr.co/videos/coverr-airplane-taking-off-8255/1080p.mp4" type="video/mp4" />
</video>
</ClientOnly>
<p class="mt-3 text-xs text-white/60">Kurzclip: Symbolisch für den Lernpfad</p>
</div>
</div>
</div>
</section>
<!-- PRICING -->
<section id="pricing" class="py-16 md:py-24 bg-gradient-to-b from-[#0b1020] to-[#0a0f1c]">
<div class="mx-auto max-w-[1200px] px-4">
<div class="flex flex-col md:flex-row md:items-end md:justify-between gap-4">
<div class="max-w-2xl">
<h2 class="text-3xl md:text-4xl font-semibold">Preise</h2>
<p class="mt-3 text-white/80">OpenSource bleibt frei. Der gehostete Plan ist so günstig wie möglich kalkuliert. Umschalten:
<button @click="yearly=!yearly" class="chip ml-2"><span>{{ yearly ? 'jährlich' : 'monatlich' }}</span></button>
</p>
</div>
</div>
<div class="mt-8 grid md:grid-cols-3 gap-6">
<!-- OSS -->
<div class="card relative">
<div class="absolute -top-3 right-4 chip">Community</div>
<h3 class="text-xl font-semibold">OpenSource (Selfhost)</h3>
<p class="mt-2 text-white/80">Volle Kontrolle. Eigene Infrastruktur. APIKeys selbst verwalten.</p>
<div class="mt-5 text-3xl font-semibold">0<span class="text-white/60 text-sm font-normal"> / immer</span></div>
<ul class="mt-5 space-y-2 text-white/80 text-sm">
<li> Voller Funktionsumfang</li>
<li> Plugins & SDK</li>
<li> CommunitySupport</li>
</ul>
<a href="#opensource" class="btn btn-ghost w-full mt-6">Repository ansehen</a>
</div>
<!-- Hosted Basic -->
<div class="card border-2 border-cyan-400/40 relative shadow-glow">
<div class="absolute -top-3 right-4 chip bg-cyan-500/30 border-cyan-400/50">Empfohlen</div>
<h3 class="text-xl font-semibold">Hosted Basic</h3>
<p class="mt-2 text-white/80">Alles fertig eingerichtet. Ideal zum Lernen & Üben.</p>
<div class="mt-5 text-3xl font-semibold"><span>{{ yearly ? '4,00€' : '4,50€' }}</span><span class="text-white/60 text-sm font-normal"> / Monat</span></div>
<ul class="mt-5 space-y-2 text-white/80 text-sm">
<li> FairUse AudioMinuten</li>
<li> Lernpfad & Fortschritt</li>
<li> Updates & CloudScaling</li>
</ul>
<a href="#cta" class="btn btn-primary w-full mt-6">Kostenlos testen</a>
<p class="mt-3 text-xs text-white/60">Preisziel: minimal + Betriebskosten. Änderungen möglich.</p>
</div>
<!-- Hosted Pro -->
<div class="card relative">
<div class="absolute -top-3 right-4 chip">PowerUser</div>
<h3 class="text-xl font-semibold">Hosted Pro</h3>
<p class="mt-2 text-white/80">Mehr Kontingente, eigene Stimmen, APIZugriff.</p>
<div class="mt-5 text-3xl font-semibold"><span>{{ yearly ? '12€' : '14€' }}</span><span class="text-white/60 text-sm font-normal"> / Monat</span></div>
<ul class="mt-5 space-y-2 text-white/80 text-sm">
<li> Höhere Limits</li>
<li> TeamSeats</li>
<li> Priorisierter Support</li>
</ul>
<a href="#cta" class="btn btn-ghost w-full mt-6">Kontakt aufnehmen</a>
</div>
</div>
</div>
</section>
<!-- OPEN SOURCE -->
<section id="opensource" class="py-16 md:py-24 bg-[#0a0f1c]">
<div class="mx-auto max-w-[1200px] px-4">
<div class="grid md:grid-cols-2 gap-8 items-center">
<div>
<h2 class="text-3xl md:text-4xl font-semibold">OpenSource, Communitygetrieben</h2>
<p class="mt-3 text-white/80">Transparente Architektur, klare Roadmap, offene Issues. Baue eigene Voices, Integrationen und Workflows.</p>
<ul class="mt-4 grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm">
<li class="glass rounded-xl p-3">MIT/ApacheLizenz (tbd)</li>
<li class="glass rounded-xl p-3">DockerCompose / Helm</li>
<li class="glass rounded-xl p-3">PluginSDK (TS/JS)</li>
<li class="glass rounded-xl p-3">CLI & REST API</li>
</ul>
<div class="mt-6 flex gap-3">
<a href="#cta" class="btn btn-primary">Mitmachen</a>
<a href="#demo" class="btn btn-ghost">Demo</a>
</div>
</div>
<div class="card">
<pre class="text-xs md:text-sm overflow-x-auto"><code>// Beispiel: RESTRoute für TaxiRouten
POST /api/route/taxi
{
"icao": "EDDF",
"from": { "type": "gate", "ref": "A20" },
"to": { "type": "runway", "ref": "25C" }
}
// → Antwort: Liste der Segmente, Geometrie, ReadbackVorschlag</code></pre>
</div>
</div>
</div>
</section>
<!-- HOW IT WORKS -->
<section class="py-16 md:py-24 bg-[#0b1020]">
<div class="mx-auto max-w-[1200px] px-4">
<div class="max-w-2xl mb-10">
<h2 class="text-3xl md:text-4xl font-semibold">So funktionierts</h2>
<p class="mt-3 text-white/80">Audio rein Verständnis Antwort raus. Designed für niedrige Latenz & klare FunkDisziplin.</p>
</div>
<div class="grid md:grid-cols-4 gap-4 md:gap-6">
<div class="card"><h3 class="font-semibold">1 · ASR</h3><p class="mt-2 text-white/80">StreamingSpeechtoText mit FunkTuning.</p></div>
<div class="card"><h3 class="font-semibold">2 · NLU</h3><p class="mt-2 text-white/80">LLM versteht Intention, Kontext, State.</p></div>
<div class="card"><h3 class="font-semibold">3 · Logic</h3><p class="mt-2 text-white/80">Regeln, Flugdaten, TaxiRouting, Validierung.</p></div>
<div class="card"><h3 class="font-semibold">4 · TTS</h3><p class="mt-2 text-white/80">Natürliches VoiceOut mit korrekten Zahlen.</p></div>
</div>
</div>
</section>
<!-- CTA -->
<section id="cta" class="py-16 md:py-24 bg-gradient-to-tr from-cyan-500/20 via-blue-500/10 to-transparent border-y border-white/10">
<div class="mx-auto max-w-[1200px] px-4">
<div class="card md:flex md:items-center md:justify-between">
<div>
<h3 class="text-2xl md:text-3xl font-semibold">Jetzt OpenSquawk ausprobieren</h3>
<p class="mt-2 text-white/80">Starte kostenlos. Upgrade jederzeit. Keine Bindung.</p>
</div>
<form class="mt-4 md:mt-0 flex w-full md:w-auto gap-2" @submit.prevent="submitEmail">
<input v-model="email" aria-label="EMail" type="email" required placeholder="dein@email" class="w-full md:w-72 px-4 py-3 rounded-xl bg-white/5 border border-white/10 placeholder-white/40 outline-none focus:border-cyan-400" />
<button class="btn btn-primary">Einladung anfordern</button>
</form>
</div>
<p v-if="thanks" class="mt-3 text-sm text-green-300">Danke! Wir melden uns in Kürze mit deinem Zugang.</p>
</div>
</section>
<!-- FAQ -->
<section id="faq" class="py-16 md:py-24 bg-[#0a0f1c]">
<div class="mx-auto max-w-[1200px] px-4">
<div class="max-w-2xl mb-10">
<h2 class="text-3xl md:text-4xl font-semibold">FAQ</h2>
<p class="mt-3 text-white/80">Kurz beantwortet.</p>
</div>
<div class="grid md:grid-cols-2 gap-6">
<div class="card">
<h3 class="font-semibold">Ist das für reale Luftfahrt?</h3>
<p class="mt-2 text-white/80">Nein, OpenSquawk ist für Flugsimulatoren und Training. Nicht für den realen Flugfunk.</p>
</div>
<div class="card">
<h3 class="font-semibold">Welche Simulatoren werden unterstützt?</h3>
<p class="mt-2 text-white/80">MSFS, XPlane (weitere geplant). Integrationen per PluginSDK.</p>
</div>
<div class="card">
<h3 class="font-semibold">Kann ich selbst hosten?</h3>
<p class="mt-2 text-white/80">Ja. DockerCompose/Helm bereitgestellt. HostedPlan als bequeme Alternative.</p>
</div>
<div class="card">
<h3 class="font-semibold">Wie günstig ist Hosted Basic?</h3>
<p class="mt-2 text-white/80">Ziel: knapp über Betriebskosten. Pilotphase mit 45 mtl. (vorläufig).</p>
</div>
</div>
</div>
</section>
<!-- FOOTER -->
<footer class="py-12 bg-[#0b1020] border-t border-white/10">
<div class="mx-auto max-w-[1200px] px-4">
<div class="grid md:grid-cols-4 gap-6">
<div>
<div class="flex items-center gap-2 font-semibold"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" class="text-cyan-400"><path d="M12 3l8 4v10l-8 4-8-4V7l8-4z" stroke="currentColor"/></svg>OpenSquawk</div>
<p class="mt-3 text-white/70 text-sm">OpenSource AIATC für Simulatorpiloten. Lernpfad & günstiger HostedPlan.</p>
</div>
<div>
<h4 class="font-semibold mb-3">Produkt</h4>
<ul class="space-y-2 text-white/70 text-sm">
<li><a href="#features" class="hover:text-cyan-300">Features</a></li>
<li><a href="#learn" class="hover:text-cyan-300">Lernpfad</a></li>
<li><a href="#pricing" class="hover:text-cyan-300">Preise</a></li>
</ul>
</div>
<div>
<h4 class="font-semibold mb-3">Ressourcen</h4>
<ul class="space-y-2 text-white/70 text-sm">
<li><a href="#opensource" class="hover:text-cyan-300">OpenSource</a></li>
<li><a href="#demo" class="hover:text-cyan-300">Demo</a></li>
<li><a href="#faq" class="hover:text-cyan-300">FAQ</a></li>
</ul>
</div>
<div>
<h4 class="font-semibold mb-3">Rechtliches</h4>
<ul class="space-y-2 text-white/70 text-sm">
<li><a href="#" class="hover:text-cyan-300">Impressum</a></li>
<li><a href="#" class="hover:text-cyan-300">Datenschutz</a></li>
<li><a href="#" class="hover:text-cyan-300">Nutzungshinweise</a></li>
</ul>
</div>
</div>
<div class="mt-8 pt-6 border-t border-white/10 text-xs text-white/60">© {{ year }} OpenSquawk. Nicht für reale Luftfahrt. *VATSIM/IVAO: Marken der jeweiligen Eigentümer.</div>
</div>
</footer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useHead } from '#imports'
const yearly = ref(true)
const email = ref('')
const thanks = ref(false)
const year = new Date().getFullYear()
function submitEmail(){
// TODO: replace with real endpoint
console.log('request access:', email.value)
thanks.value = true
}
useHead({
title: 'OpenSquawk OpenSource AIATC für Simulatorpiloten',
meta: [
{ name: 'description', content: 'OpenSquawk ist die offene, günstige Alternative für AIATC im Flugsimulator mit Lernpfad zu echter Funkphraseologie und sanftem Einstieg Richtung VATSIM.' },
{ name: 'theme-color', content: '#0ea5e9' },
{ property: 'og:title', content: 'OpenSquawk OpenSource AIATC' },
{ property: 'og:description', content: 'Open, günstig, lernfreundlich. AIATC mit Lernpfad & gehostetem Plan.' },
{ property: 'og:type', content: 'website' },
{ property: 'og:image', content: 'https://opensquawk.example.com/cover.png' },
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'twitter:title', content: 'OpenSquawk OpenSource AIATC' },
{ name: 'twitter:description', content: 'Open, günstig, lernfreundlich. AIATC mit Lernpfad & gehostetem Plan.' },
{ name: 'twitter:image', content: 'https://opensquawk.example.com/cover.png' }
],
script: [
{ src: 'https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js', defer: true },
{ src: 'https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js', defer: true },
{ type: 'application/ld+json', children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'OpenSquawk',
applicationCategory: 'Simulation',
offers: { '@type': 'AggregateOffer', lowPrice: '0', priceCurrency: 'EUR' },
description: 'OpenSource AIATC für Flugsimulatoren mit Lernpfad & HostedPlan.',
operatingSystem: 'Windows, macOS'
}) }
]
})
onMounted(() => {
const w: any = window as any
const gsap = w.gsap
const ScrollTrigger = w.ScrollTrigger
if (!gsap || !ScrollTrigger) return
gsap.registerPlugin(ScrollTrigger)
gsap.from('header nav', { y: -30, opacity: 0, duration: .6, ease: 'power2'})
gsap.from('.card', { opacity: 0, y: 20, duration: .6, stagger: .08, ease: 'power2', scrollTrigger: { trigger: '#features', start: 'top 80%' }})
gsap.from('#pricing .card', { opacity: 0, y: 24, duration: .6, stagger: .08, ease: 'power2', scrollTrigger: { trigger: '#pricing', start: 'top 80%' }})
gsap.from('#learn .card, #learn h2, #learn ol li', { opacity: 0, y: 18, duration: .6, stagger: .06, ease: 'power2', scrollTrigger: { trigger: '#learn', start: 'top 80%' }})
gsap.from('#opensource .card', { opacity: 0, y: 18, duration: .6, stagger: .06, ease: 'power2', scrollTrigger: { trigger: '#opensource', start: 'top 80%' }})
gsap.from('#cta .card', { opacity: 0, scale: .98, duration: .6, ease: 'power2', scrollTrigger: { trigger: '#cta', start: 'top 90%' }})
})
</script>
<style scoped>
.glass { background: rgba(255,255,255,.06); backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,.08); }
.card { @apply glass rounded-2xl p-5 md:p-6; }
.btn { @apply inline-flex items-center justify-center gap-2 rounded-xl px-5 py-3 font-medium transition; }
.btn-primary { @apply bg-cyan-500 text-white hover:bg-cyan-400 shadow-[0_0_40px_rgba(34,211,238,.25)]; }
.btn-ghost { @apply bg-white/5 text-white hover:bg-white/10; }
.chip { @apply inline-flex items-center gap-2 rounded-full bg-white/10 border border-white/15 text-white px-3 py-1 text-xs; }
.gradient-hero { background: radial-gradient(1200px 600px at 10% -10%, rgba(6,182,212,.35), transparent), radial-gradient(900px 480px at 100% 10%, rgba(59,130,246,.25), transparent), linear-gradient(180deg, #0b1020 0%, #0b1020 60%, #0a0f1c 100%); }
</style>