mid light/dark coloured gradient/shadows that thus contrast on light and dark mode
This commit is contained in:
@@ -86,10 +86,16 @@ export function CampaignHeroBackground({ imageUrl, className }: CampaignHeroBack
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Warm tint + dark gradient — keeps foreground text legible without
|
||||
completely washing the photo out. */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-background/85 via-background/55 to-background/40" />
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/25 via-transparent to-secondary/30" />
|
||||
{/* Dark vertical scrim — strong at the bottom (spotlight card) and
|
||||
lighter at the top so the photo still reads. Uses black instead of
|
||||
background so the overlay is consistent across light/dark themes. */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/45 to-black/15" />
|
||||
{/* Warm primary tint — gives the hero its brand feel. */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/20 via-transparent to-primary/10" />
|
||||
|
||||
{/* Left wash — mobile only, where the globe arc crosses the headline.
|
||||
Dark so white headline text has a reliable backdrop. */}
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-black/75 via-black/35 to-transparent sm:hidden" />
|
||||
|
||||
{/* Film grain — same trick as Treasures' HeroGallery. Helps the
|
||||
composited globe + photo feel like one image. */}
|
||||
|
||||
@@ -63,10 +63,9 @@ export function HeroCampaignSpotlight({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
// Compact text block over the photo. Light text + subtle drop
|
||||
// shadow for legibility, no card chrome — modeled after the
|
||||
// Treasures hero overlay: tight, dense, low-key.
|
||||
'space-y-1.5 text-foreground [text-shadow:0_1px_2px_rgb(0_0_0/0.4)]',
|
||||
// Compact text block over the photo — always white regardless of
|
||||
// theme since the hero is always a dark-scrimed photo.
|
||||
'space-y-1.5 text-white hero-text-shadow-soft',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
@@ -75,7 +74,7 @@ export function HeroCampaignSpotlight({
|
||||
</p>
|
||||
|
||||
{campaign.summary && (
|
||||
<p className="text-xs text-foreground/80 line-clamp-2 max-w-xs">
|
||||
<p className="text-xs text-white/80 line-clamp-2 max-w-xs">
|
||||
{campaign.summary}
|
||||
</p>
|
||||
)}
|
||||
@@ -101,12 +100,12 @@ export function HeroCampaignSpotlight({
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-baseline justify-between gap-2 text-[11px] [text-shadow:none]">
|
||||
<span className="font-semibold text-foreground">
|
||||
<span className="font-semibold text-white">
|
||||
{formatCampaignAmount(raised, btcPrice)}
|
||||
{!hasGoal && <span className="ml-1 font-normal text-foreground/70">raised</span>}
|
||||
{!hasGoal && <span className="ml-1 font-normal text-white/70">raised</span>}
|
||||
</span>
|
||||
{hasGoal && (
|
||||
<span className="text-foreground/70">
|
||||
<span className="text-white/70">
|
||||
of {formatCampaignAmount(goal!, btcPrice)} goal
|
||||
</span>
|
||||
)}
|
||||
@@ -115,7 +114,7 @@ export function HeroCampaignSpotlight({
|
||||
);
|
||||
})()}
|
||||
|
||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-foreground/75 pt-0.5">
|
||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-white/75 pt-0.5">
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<Avatar className="size-4 ring-1 ring-white/40">
|
||||
{authorPicture && <AvatarImage src={authorPicture} alt="" />}
|
||||
|
||||
@@ -313,8 +313,8 @@ export function HeroGlobe({
|
||||
<stop offset="100%" stopColor={hue.glow} stopOpacity="0" />
|
||||
</radialGradient>
|
||||
{/* Soft highlight in the upper-left to sell the sphere shape. */}
|
||||
<radialGradient id="hero-globe-highlight" cx="28%" cy="22%" r="38%">
|
||||
<stop offset="0%" stopColor="hsl(50 100% 98% / 0.85)" />
|
||||
<radialGradient id="hero-globe-highlight" cx="30%" cy="25%" r="35%">
|
||||
<stop offset="0%" stopColor="hsl(50 100% 98% / 0.58)" />
|
||||
<stop offset="100%" stopColor="hsl(50 100% 98% / 0)" />
|
||||
</radialGradient>
|
||||
{/* Marker glow halo. Soft, warm, no pulsing. */}
|
||||
|
||||
@@ -753,3 +753,28 @@
|
||||
.hero-pan-right, .hero-pan-left { animation: none; }
|
||||
.hero-globe-halo-breath { animation: none; opacity: 0.42; }
|
||||
}
|
||||
|
||||
/* Dark drop-shadow for hero copy — photo backgrounds are always colorful,
|
||||
so we want a dark shadow regardless of light/dark theme. */
|
||||
.hero-text-shadow {
|
||||
text-shadow:
|
||||
0 2px 8px rgba(0, 0, 0, 0.8),
|
||||
0 0 20px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.hero-text-shadow-soft {
|
||||
text-shadow: 0 1px 6px rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
/* On mobile the globe sits under the headline — soften its left edge. */
|
||||
.hero-globe-mask {
|
||||
-webkit-mask-image: linear-gradient(to right, transparent 0%, black 48%, black 100%);
|
||||
mask-image: linear-gradient(to right, transparent 0%, black 48%, black 100%);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.hero-globe-mask {
|
||||
-webkit-mask-image: none;
|
||||
mask-image: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ export function CampaignsPage() {
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
<div className="relative max-w-7xl mx-auto h-full px-4 sm:px-6">
|
||||
<div className="absolute inset-y-0 right-4 sm:right-6 flex items-center">
|
||||
<div className="pointer-events-auto translate-x-[40%] sm:translate-x-[38%] lg:translate-x-[38%] opacity-90">
|
||||
<div className="pointer-events-auto hero-globe-mask translate-x-[40%] sm:translate-x-[38%] lg:translate-x-[38%] opacity-90">
|
||||
<HeroGlobe
|
||||
markers={globeMarkers}
|
||||
selectedKey={highlightedMarkerKey}
|
||||
@@ -305,12 +305,12 @@ export function CampaignsPage() {
|
||||
{/* Foreground content — headline + CTAs at the top, spotlight info
|
||||
at the bottom. Shares the `max-w-7xl mx-auto` container with the
|
||||
globe so everything aligns to the same left/right axis. */}
|
||||
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 py-14 lg:py-20 min-h-[560px] sm:min-h-[600px] lg:min-h-[640px] flex flex-col">
|
||||
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 py-14 lg:py-20 min-h-[560px] sm:min-h-[600px] lg:min-h-[640px] flex flex-col text-white">
|
||||
<div className="relative space-y-5 max-w-2xl">
|
||||
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight leading-[1.1] drop-shadow-sm">
|
||||
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight leading-[1.1] hero-text-shadow">
|
||||
Connecting activists to unstoppable funding.
|
||||
</h1>
|
||||
<p className="text-base sm:text-lg text-foreground/80 max-w-2xl">
|
||||
<p className="text-base sm:text-lg text-white/85 max-w-2xl hero-text-shadow-soft">
|
||||
Raise Bitcoin directly from supporters around the world. Every donation settles
|
||||
straight to your campaign's beneficiaries, with no middlemen, no chargebacks, and no
|
||||
platform holding your funds.
|
||||
|
||||
Reference in New Issue
Block a user