169 lines
9.3 KiB
PHP
169 lines
9.3 KiB
PHP
@props([
|
|
'title' => null,
|
|
'description' => null,
|
|
'robots' => null,
|
|
])
|
|
<!DOCTYPE html>
|
|
<html lang="de" class="scroll-smooth">
|
|
<head>
|
|
@if ($description)<meta name="description" content="{{ $description }}">@endif
|
|
@if ($robots)<meta name="robots" content="{{ $robots }}">@endif
|
|
<x-shell.head :title="$title" />
|
|
{{-- Parts of the page arrive on scroll, which an observer decides. Without
|
|
JavaScript nothing is ever observed. --}}
|
|
<noscript><style>.rv,.logline{opacity:1!important;transform:none!important}</style></noscript>
|
|
</head>
|
|
{{--
|
|
The public website.
|
|
|
|
Two rewrites. The first only recoloured the old page — same eight numbered
|
|
sections, same split hero, same comparison matrix — and was correctly called
|
|
out as the old thing in new paint. A palette is not a design.
|
|
|
|
What actually changed on the second pass: the § numbering is gone (a
|
|
document convention, and the document voice was exactly what the redesign
|
|
dropped), the hero shows the product instead of describing it, the uniform
|
|
card rows became one asymmetric grid, the price matrix became price cards
|
|
with the full table folded away underneath, and the page now has one dark
|
|
hinge in the middle instead of a dark section among seven light ones.
|
|
--}}
|
|
<body class="flex min-h-screen flex-col bg-bg text-body antialiased">
|
|
<div id="site-progress" class="fixed inset-x-0 top-0 z-[120] h-0.5 w-0 bg-accent" aria-hidden="true"></div>
|
|
|
|
{{-- A floating bar rather than a full-width band: it reads as an object on
|
|
the page instead of a browser chrome bolted to the top, and it lets the
|
|
hero start at the very top of the viewport. --}}
|
|
<header x-data="{ open: false }" class="fixed inset-x-0 top-0 z-[110] px-4 pt-4 sm:px-6">
|
|
{{-- Opaque. Translucency plus backdrop-blur looks like glass over a
|
|
photograph and like a rendering fault over a dark panel, which is
|
|
exactly what scrolls under this bar. --}}
|
|
<div class="mx-auto max-w-[1120px] rounded-xl border border-line bg-surface shadow-sm">
|
|
<div class="flex h-14 items-center gap-8 pl-4 pr-3">
|
|
<a href="{{ route('home') }}"><x-ui.brand size="md" /></a>
|
|
|
|
<nav class="hidden items-center gap-1 text-sm text-muted lg:flex">
|
|
@foreach (['#product' => 'Produkt', '#process' => 'Ablauf', '#security' => 'Sicherheit', '#pricing' => 'Preise', '#faq' => 'Fragen'] as $href => $label)
|
|
<a href="{{ route('home') }}{{ $href }}" class="rounded px-3 py-1.5 transition-colors hover:bg-surface-hover hover:text-ink">{{ $label }}</a>
|
|
@endforeach
|
|
</nav>
|
|
|
|
<div class="ml-auto flex items-center gap-2">
|
|
<a href="{{ route('login') }}" class="hidden rounded px-3 py-1.5 text-sm text-muted transition-colors hover:bg-surface-hover hover:text-ink sm:block">Anmelden</a>
|
|
<x-ui.button href="{{ route('home') }}#pricing" variant="ink" size="sm">Preise</x-ui.button>
|
|
<button type="button" class="grid size-9 place-items-center rounded text-muted transition-colors hover:bg-surface-hover hover:text-ink lg:hidden" @click="open = !open" :aria-expanded="open" aria-label="Menü">
|
|
<x-ui.icon name="menu" class="size-5" x-show="!open" />
|
|
<x-ui.icon name="x" class="size-5" x-show="open" x-cloak />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<nav x-show="open" x-cloak @click="open = false" class="border-t border-line px-4 pb-2 lg:hidden">
|
|
@foreach (['#product' => 'Produkt', '#process' => 'Ablauf', '#security' => 'Sicherheit', '#pricing' => 'Preise', '#faq' => 'Fragen', route('login') => 'Anmelden'] as $href => $label)
|
|
<a href="{{ Str::startsWith($href, '#') ? route('home').$href : $href }}" class="flex min-h-11 items-center border-b border-line text-sm text-body last:border-0">{{ $label }}</a>
|
|
@endforeach
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="flex-1">
|
|
{{ $slot }}
|
|
</main>
|
|
|
|
<footer class="border-t border-line bg-surface">
|
|
<div class="mx-auto max-w-[1120px] px-5 py-14 sm:px-6">
|
|
<div class="grid gap-10 sm:grid-cols-2 lg:grid-cols-4">
|
|
<div class="lg:col-span-2">
|
|
<x-ui.brand size="md" />
|
|
<p class="mt-4 max-w-[38ch] text-sm leading-relaxed text-muted">
|
|
Eine eigene, isolierte Cloud für Ihr Unternehmen — eingerichtet, gesichert und
|
|
überwacht von uns, mit Serverstandort in der EU.
|
|
</p>
|
|
<a href="mailto:office@clupilot.com" class="mt-5 inline-flex items-center gap-2 text-sm font-medium text-accent-text underline-offset-4 hover:underline">
|
|
<x-ui.icon name="mail" class="size-4" />office@clupilot.com
|
|
</a>
|
|
</div>
|
|
|
|
<div>
|
|
<p class="lbl">Produkt</p>
|
|
<div class="mt-4 flex flex-col gap-2.5 text-sm text-muted">
|
|
<a href="{{ route('home') }}#product" class="transition-colors hover:text-ink">Was enthalten ist</a>
|
|
<a href="{{ route('home') }}#process" class="transition-colors hover:text-ink">Ablauf</a>
|
|
<a href="{{ route('home') }}#security" class="transition-colors hover:text-ink">Sicherheit</a>
|
|
<a href="{{ route('home') }}#pricing" class="transition-colors hover:text-ink">Preise</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<p class="lbl">Rechtliches & Betrieb</p>
|
|
<div class="mt-4 flex flex-col gap-2.5 text-sm text-muted">
|
|
<a href="{{ route('legal.impressum') }}" class="transition-colors hover:text-ink">Impressum</a>
|
|
<a href="{{ route('legal.datenschutz') }}" class="transition-colors hover:text-ink">Datenschutz</a>
|
|
<a href="{{ route('legal.agb') }}" class="transition-colors hover:text-ink">AGB</a>
|
|
<a href="{{ route('status') }}" class="transition-colors hover:text-ink">Betriebsstatus</a>
|
|
<a href="{{ route('security') }}" class="transition-colors hover:text-ink">Echte Adressen erkennen</a>
|
|
<a href="{{ route('login') }}" class="transition-colors hover:text-ink">Anmelden</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-12 flex flex-col gap-2 border-t border-line pt-6 sm:flex-row sm:items-center">
|
|
<span class="lbl">© {{ date('Y') }} CluPilot Cloud · Österreich</span>
|
|
<span class="lbl sm:ml-auto">Serverstandort EU · Support auf Deutsch</span>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
@verbatim
|
|
<script>
|
|
(function () {
|
|
const reduce = matchMedia('(prefers-reduced-motion:reduce)').matches;
|
|
const progress = document.getElementById('site-progress');
|
|
|
|
addEventListener('scroll', () => {
|
|
const el = document.documentElement;
|
|
const max = el.scrollHeight - el.clientHeight;
|
|
progress.style.width = (max > 0 ? (scrollY / max) * 100 : 0) + '%';
|
|
}, { passive: true });
|
|
|
|
const reveal = new IntersectionObserver(entries => entries.forEach(entry => {
|
|
if (!entry.isIntersecting) return;
|
|
entry.target.classList.add('in');
|
|
reveal.unobserve(entry.target);
|
|
}), { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
|
|
document.querySelectorAll('.rv').forEach(el => reveal.observe(el));
|
|
|
|
// Tabular figures are set on the element, so counting never shifts
|
|
// the layout around it.
|
|
const count = new IntersectionObserver(entries => entries.forEach(entry => {
|
|
if (!entry.isIntersecting) return;
|
|
count.unobserve(entry.target);
|
|
const el = entry.target;
|
|
const target = parseFloat(el.dataset.count);
|
|
const decimals = parseInt(el.dataset.decimals || 0, 10);
|
|
const format = v => v.toFixed(decimals).replace('.', ',');
|
|
if (reduce) { el.textContent = format(target); return; }
|
|
const start = performance.now();
|
|
(function tick(now) {
|
|
const p = Math.min((now - start) / 1100, 1);
|
|
el.textContent = format(target * (1 - Math.pow(1 - p, 3)));
|
|
if (p < 1) requestAnimationFrame(tick);
|
|
})(start);
|
|
}), { threshold: 0.6 });
|
|
document.querySelectorAll('[data-count]').forEach(el => count.observe(el));
|
|
|
|
const log = document.getElementById('deploy-log');
|
|
if (log) {
|
|
const lines = new IntersectionObserver(entries => entries.forEach(entry => {
|
|
if (!entry.isIntersecting) return;
|
|
lines.unobserve(log);
|
|
log.querySelectorAll('.logline').forEach((row, i) =>
|
|
setTimeout(() => row.classList.add('in'), reduce ? 0 : 200 + i * 340));
|
|
}), { threshold: 0.3 });
|
|
lines.observe(log);
|
|
}
|
|
})();
|
|
</script>
|
|
@endverbatim
|
|
</body>
|
|
</html>
|