feat(design): Hero asymmetric layout with real product UI + bug fixes

- Hero restructured from stacked to 2-col grid on lg+ (copy left, product
  screenshot right). Replaces the abstract RouteDiagram with the actual
  exchange-detail view — the product doing the thing the copy promises.
- Kicker broken out of the shared uppercase-mono pattern: italic pill with
  a soft amber fill/border, scaled up to 14px. The humor now wears a
  different costume from the other section kickers.
- Hero brand mark scaled to 64px and given a slow 7s sway (reduced-motion
  guarded) — living atmosphere, not ambient animation.
- H1 min-height raised to 2.5em to absorb the 2-line wrap of line 1 at
  mobile sizes without layout shift on rotation.
- Amber radial glow behind the product shot + subtle bevel + frame ring.
- Footer placeholder 3-wavy-lines SVG replaced with real camel logo
  (spec gap from earlier refresh — header got swapped, footer didn't).
- Screenshot assets imported under public/product/.
This commit is contained in:
hsiegeln
2026-04-25 00:20:39 +02:00
parent af7c61c203
commit 8c77db02ac
5 changed files with 87 additions and 40 deletions

View File

@@ -0,0 +1 @@
{"sessionId":"5f077efe-7838-4a44-8b13-5439c0e554a1","pid":30820,"acquiredAt":1777049469642}

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 KiB

View File

@@ -4,14 +4,14 @@ const year = new Date().getFullYear();
<footer class="border-t border-border mt-24"> <footer class="border-t border-border mt-24">
<div class="max-w-content mx-auto px-6 py-12 flex flex-col md:flex-row md:items-center md:justify-between gap-8"> <div class="max-w-content mx-auto px-6 py-12 flex flex-col md:flex-row md:items-center md:justify-between gap-8">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<svg width="24" height="24" viewBox="0 0 32 32" aria-hidden="true"> <img
<rect width="32" height="32" rx="6" fill="#0c111a"/> src="/cameleer-logo.svg"
<g fill="none" stroke="#f0b429" stroke-width="1.6" stroke-linecap="round"> width="24"
<path d="M4 10 Q10 6 16 12 T28 10"/> height="24"
<path d="M4 16 Q10 12 16 18 T28 16"/> alt=""
<path d="M4 22 Q10 18 16 24 T28 22"/> decoding="async"
</g> class="shrink-0 opacity-80"
</svg> />
<span class="text-text-muted text-sm">© {year} Cameleer</span> <span class="text-text-muted text-sm">© {year} Cameleer</span>
</div> </div>
<nav class="flex items-center gap-8 text-sm text-text-muted" aria-label="Footer"> <nav class="flex items-center gap-8 text-sm text-text-muted" aria-label="Footer">

View File

@@ -1,27 +1,28 @@
--- ---
import CTAButtons from '../CTAButtons.astro'; import CTAButtons from '../CTAButtons.astro';
import RouteDiagram from '../RouteDiagram.astro';
import TopographicBg from '../TopographicBg.astro'; import TopographicBg from '../TopographicBg.astro';
--- ---
<section class="relative overflow-hidden border-b border-border"> <section class="relative overflow-hidden border-b border-border">
<TopographicBg opacity={0.14} lines={10} /> <TopographicBg opacity={0.22} lines={11} />
<div class="relative max-w-content mx-auto px-6 pt-20 pb-24 md:pt-28 md:pb-32"> <div class="relative max-w-content mx-auto px-6 pt-16 pb-20 md:pt-24 md:pb-24 lg:pt-28">
<div class="max-w-3xl"> <div class="grid lg:grid-cols-12 gap-10 lg:gap-14 items-center">
<div class="flex items-center gap-3 mb-6"> <div class="lg:col-span-5">
<img <img
src="/cameleer-logo.svg" src="/cameleer-logo.svg"
width="48" width="64"
height="48" height="64"
alt="" alt=""
decoding="async" decoding="async"
class="shrink-0" class="shrink-0 mb-5 hero-mark"
/> />
<p class="text-accent font-mono text-xs tracking-[0.25em] uppercase"> <p
class="inline-flex items-center gap-2 mb-7 rounded-full border border-accent/30 bg-accent/[0.08] text-accent px-3.5 py-1 text-sm italic font-medium"
>
<span aria-hidden="true" class="text-base">✦</span>
Your camels called. They want a GPS. Your camels called. They want a GPS.
</p> </p>
</div>
<h1 <h1
class="text-display font-bold text-text mb-6 hero-rotator" class="font-bold text-text mb-6 hero-rotator"
aria-live="off" aria-live="off"
data-hero-rotator data-hero-rotator
> >
@@ -34,25 +35,41 @@ import TopographicBg from '../TopographicBg.astro';
</p> </p>
<CTAButtons size="lg" /> <CTAButtons size="lg" />
</div> </div>
<div class="mt-16 md:mt-20"> <div class="lg:col-span-7 relative">
<RouteDiagram /> <div class="hero-shot relative rounded-lg border border-border-strong bg-bg-elevated overflow-hidden">
<img
src="/product/exchange-detail.png"
alt="Cameleer Mission Control — route execution detail with processor-level trace"
width="1920"
height="945"
loading="eager"
decoding="async"
class="block w-full h-auto"
/>
<div class="absolute inset-0 ring-1 ring-inset ring-accent/10 pointer-events-none rounded-lg"></div>
</div>
<div aria-hidden="true" class="hero-shot-glow"></div>
</div>
</div> </div>
</div> </div>
</section> </section>
<style> <style>
/* Rotating H1 — fluid size + fade transition */
.hero-rotator { .hero-rotator {
font-size: clamp(2.25rem, 4.5vw, 4rem);
line-height: 1.05;
letter-spacing: -0.02em;
position: relative; position: relative;
display: block; display: block;
/* Reserve height for the tallest line so no layout shift on swap. /* Reserve enough vertical space that a 2-line wrap of the longest line
Two lines at current H1 size handles all three on most viewports. */ does not push the page on swap (mobile wraps line 1 to 2 lines). */
min-height: 2.2em; min-height: 2.5em;
} }
.hero-line { .hero-line {
display: block; display: block;
opacity: 0; opacity: 0;
transition: opacity 700ms ease-in-out; transition: opacity 700ms ease-in-out;
/* Stack all lines on top of each other — only [data-active] is visible. */
position: absolute; position: absolute;
inset: 0; inset: 0;
} }
@@ -60,10 +77,39 @@ import TopographicBg from '../TopographicBg.astro';
opacity: 1; opacity: 1;
position: relative; position: relative;
} }
@media (prefers-reduced-motion: reduce) {
.hero-line { /* Product screenshot frame — subtle dropshadow + amber glow behind */
transition: none; .hero-shot {
box-shadow:
0 1px 0 rgba(240, 180, 41, 0.08) inset,
0 30px 60px -20px rgba(0, 0, 0, 0.6),
0 10px 25px -10px rgba(0, 0, 0, 0.5);
} }
.hero-shot-glow {
position: absolute;
inset: 10% -5% 10% -5%;
background: radial-gradient(
60% 60% at 50% 50%,
rgba(240, 180, 41, 0.18),
transparent 70%
);
filter: blur(40px);
z-index: -1;
}
/* Slow sway on the mark — tasteful, not distracting */
@keyframes hero-mark-sway {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-2px) rotate(-1.5deg); }
}
.hero-mark {
animation: hero-mark-sway 7s ease-in-out infinite;
transform-origin: 50% 90%;
}
@media (prefers-reduced-motion: reduce) {
.hero-line { transition: none; }
.hero-mark { animation: none; }
} }
</style> </style>