polish: deep visual pass across all homepage sections
All checks were successful
Build & Push / build-and-push (push) Successful in 1m26s
All checks were successful
Build & Push / build-and-push (push) Successful in 1m26s
Hero: - Removed fake trust proof avatars - Added decorative gradient separator line - Pushed content down for better vertical rhythm - More visible secondary CTA button TrustBar: - Icon circles with primary tint backdrops - Gradient top accent bar on hover - Gradient fade transition from hero section - Increased card padding Services: - Subtle grid texture background - Larger primary-colored feature dots - Enhanced AI narrative with horizontal decorative rules - Hover shadow elevation on pillars Configurator: - Step numbers in tinted circles with vertical rail - ShieldCheck trust icon - Radial gradient glow on wizard panel - Sparkles icon on AI toggle - Empty-state hint message - Service card icons in circular primary backdrops Process: - Gradient top accent strips on cards - Icon containers with primary tint - Vertical accent bar on section heading - Dashed SVG connector lines between cards SelectedWorks: - Distinct geometric compositions per card (Monaco, Nimara, Amador) - Bottom gradient fade on placeholder images - Dot separators between tags - Animated background pulse on coming-soon cards - Enhanced CTA hover animations Philosophy: - Enriched decorative panel (circle rings, diagonal lines, navy gradient) - Primary-colored pillar numbers - Left border accent on pull-quote card CTABanner: - Grid pattern + circle ring overlays - Email link underline-on-hover animation Footer: - Full logo image replacing text wordmark - Larger social icons - Gradient divider line - Larger nav logo (h-14 desktop, h-11 mobile) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -92,97 +92,278 @@ const comingSoonVariants = {
|
||||
|
||||
function GeometricPlaceholder({
|
||||
variant = 'featured',
|
||||
cardVariant = 'default',
|
||||
className,
|
||||
}: {
|
||||
variant?: 'featured' | 'small';
|
||||
cardVariant?: 'default' | 'nimara' | 'amador';
|
||||
className?: string;
|
||||
}) {
|
||||
const isFeatured = variant === 'featured';
|
||||
|
||||
// Different gradient bases per card so secondary cards look distinct
|
||||
const gradientMap = {
|
||||
default: 'from-primary-dark/90 to-primary/70',
|
||||
nimara: 'from-navy/95 to-primary-dark/75',
|
||||
amador: 'from-[#1a3a4a]/95 to-primary/60',
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'relative overflow-hidden bg-gradient-to-br from-primary-dark/90 to-primary/70',
|
||||
'relative overflow-hidden bg-gradient-to-br',
|
||||
gradientMap[cardVariant],
|
||||
className,
|
||||
)}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{/* Abstract geometric shapes */}
|
||||
<div className="absolute inset-0">
|
||||
{/* Large circle top-right */}
|
||||
<div
|
||||
className="absolute rounded-full bg-white/[0.06]"
|
||||
style={{
|
||||
width: isFeatured ? '55%' : '70%',
|
||||
height: isFeatured ? '55%' : '70%',
|
||||
top: '-15%',
|
||||
right: '-10%',
|
||||
}}
|
||||
/>
|
||||
{/* Medium circle bottom-left */}
|
||||
<div
|
||||
className="absolute rounded-full bg-white/[0.08]"
|
||||
style={{
|
||||
width: isFeatured ? '40%' : '50%',
|
||||
height: isFeatured ? '40%' : '50%',
|
||||
bottom: '-20%',
|
||||
left: '-5%',
|
||||
}}
|
||||
/>
|
||||
{/* Diagonal stripes overlay */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.04]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'repeating-linear-gradient(-45deg, #fff 0, #fff 1px, transparent 0, transparent 50%)',
|
||||
backgroundSize: isFeatured ? '28px 28px' : '20px 20px',
|
||||
}}
|
||||
/>
|
||||
{/* Small accent rectangle */}
|
||||
<div
|
||||
className="absolute bg-white/[0.12] rounded-sm"
|
||||
style={{
|
||||
width: isFeatured ? '18%' : '24%',
|
||||
height: isFeatured ? '28%' : '36%',
|
||||
bottom: '18%',
|
||||
right: '15%',
|
||||
transform: 'rotate(-6deg)',
|
||||
}}
|
||||
/>
|
||||
{/* Thin horizontal line accent */}
|
||||
<div
|
||||
className="absolute bg-white/20 rounded-full"
|
||||
style={{
|
||||
width: isFeatured ? '30%' : '40%',
|
||||
height: '1px',
|
||||
top: '38%',
|
||||
left: '10%',
|
||||
}}
|
||||
/>
|
||||
{/* Grid-dot accent */}
|
||||
<div
|
||||
className="absolute opacity-[0.07]"
|
||||
style={{
|
||||
width: isFeatured ? '25%' : '30%',
|
||||
height: isFeatured ? '25%' : '30%',
|
||||
top: '50%',
|
||||
right: '22%',
|
||||
backgroundImage: 'radial-gradient(circle, #fff 1px, transparent 1px)',
|
||||
backgroundSize: '8px 8px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{isFeatured ? (
|
||||
/* ── Featured (Monaco): blueprint feel ── */
|
||||
<>
|
||||
{/* Large filled circle top-right */}
|
||||
<div
|
||||
className="absolute rounded-full bg-white/[0.06]"
|
||||
style={{ width: '55%', height: '55%', top: '-15%', right: '-10%' }}
|
||||
/>
|
||||
{/* Large circle ring — blueprint layer */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '45%',
|
||||
height: '45%',
|
||||
top: '10%',
|
||||
left: '5%',
|
||||
border: '1px solid rgba(255,255,255,0.12)',
|
||||
opacity: 0.4,
|
||||
}}
|
||||
/>
|
||||
{/* Medium circle bottom-left */}
|
||||
<div
|
||||
className="absolute rounded-full bg-white/[0.08]"
|
||||
style={{ width: '40%', height: '40%', bottom: '-20%', left: '-5%' }}
|
||||
/>
|
||||
{/* Subtle grid overlay (blueprint feel) */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.035]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'linear-gradient(rgba(255,255,255,1) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,1) 1px, transparent 1px)',
|
||||
backgroundSize: '32px 32px',
|
||||
}}
|
||||
/>
|
||||
{/* Diagonal stripes very subtle */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.025]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'repeating-linear-gradient(-45deg, #fff 0, #fff 1px, transparent 0, transparent 50%)',
|
||||
backgroundSize: '28px 28px',
|
||||
}}
|
||||
/>
|
||||
{/* Small dot cluster */}
|
||||
<div
|
||||
className="absolute opacity-[0.12]"
|
||||
style={{
|
||||
width: '20%',
|
||||
height: '20%',
|
||||
top: '55%',
|
||||
right: '18%',
|
||||
backgroundImage: 'radial-gradient(circle, #fff 1.5px, transparent 1.5px)',
|
||||
backgroundSize: '8px 8px',
|
||||
}}
|
||||
/>
|
||||
{/* Blueprint horizontal line — wide, white/20 */}
|
||||
<div
|
||||
className="absolute bg-white/[0.22] rounded-full"
|
||||
style={{ width: '60%', height: '1px', top: '50%', left: '5%' }}
|
||||
/>
|
||||
{/* Second thinner line below */}
|
||||
<div
|
||||
className="absolute bg-white/[0.10] rounded-full"
|
||||
style={{ width: '40%', height: '1px', top: 'calc(50% + 10px)', left: '5%' }}
|
||||
/>
|
||||
{/* Accent rotated rectangle */}
|
||||
<div
|
||||
className="absolute bg-white/[0.10] rounded-sm"
|
||||
style={{
|
||||
width: '18%',
|
||||
height: '28%',
|
||||
bottom: '18%',
|
||||
right: '15%',
|
||||
transform: 'rotate(-6deg)',
|
||||
}}
|
||||
/>
|
||||
{/* Small diagonal accent line */}
|
||||
<div
|
||||
className="absolute bg-white/[0.15]"
|
||||
style={{
|
||||
width: '25%',
|
||||
height: '1px',
|
||||
top: '28%',
|
||||
right: '8%',
|
||||
transform: 'rotate(-30deg)',
|
||||
transformOrigin: 'left center',
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
) : cardVariant === 'nimara' ? (
|
||||
/* ── Port Nimara: horizontal bands + arc ── */
|
||||
<>
|
||||
{/* Large arc ring top-left */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '80%',
|
||||
height: '80%',
|
||||
top: '-30%',
|
||||
left: '-20%',
|
||||
border: '1px solid rgba(255,255,255,0.10)',
|
||||
opacity: 0.5,
|
||||
}}
|
||||
/>
|
||||
{/* Smaller ring center */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '45%',
|
||||
height: '70%',
|
||||
bottom: '-15%',
|
||||
right: '-10%',
|
||||
border: '1px solid rgba(91,164,217,0.25)',
|
||||
}}
|
||||
/>
|
||||
{/* Horizontal rule band */}
|
||||
<div
|
||||
className="absolute bg-white/[0.06]"
|
||||
style={{ height: '28%', bottom: 0, left: 0, right: 0 }}
|
||||
/>
|
||||
{/* Fine horizontal lines */}
|
||||
<div
|
||||
className="absolute bg-white/20 rounded-full"
|
||||
style={{ width: '50%', height: '1px', top: '35%', right: '8%' }}
|
||||
/>
|
||||
<div
|
||||
className="absolute bg-white/10 rounded-full"
|
||||
style={{ width: '30%', height: '1px', top: '45%', right: '8%' }}
|
||||
/>
|
||||
{/* Dot cluster top-right */}
|
||||
<div
|
||||
className="absolute opacity-[0.14]"
|
||||
style={{
|
||||
width: '25%',
|
||||
height: '30%',
|
||||
top: '5%',
|
||||
right: '5%',
|
||||
backgroundImage: 'radial-gradient(circle, #fff 1.5px, transparent 1.5px)',
|
||||
backgroundSize: '8px 8px',
|
||||
}}
|
||||
/>
|
||||
{/* Diagonal line */}
|
||||
<div
|
||||
className="absolute bg-white/[0.12]"
|
||||
style={{
|
||||
width: '40%',
|
||||
height: '1px',
|
||||
top: '60%',
|
||||
left: '5%',
|
||||
transform: 'rotate(-20deg)',
|
||||
transformOrigin: 'left center',
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
/* ── Port Amador: triangular/radial composition ── */
|
||||
<>
|
||||
{/* Central radial glow */}
|
||||
<div
|
||||
className="absolute"
|
||||
style={{
|
||||
width: '70%',
|
||||
height: '70%',
|
||||
top: '-10%',
|
||||
right: '-15%',
|
||||
background:
|
||||
'radial-gradient(circle, rgba(91,164,217,0.18) 0%, transparent 70%)',
|
||||
}}
|
||||
/>
|
||||
{/* Diamond/rotated square accent */}
|
||||
<div
|
||||
className="absolute"
|
||||
style={{
|
||||
width: '30%',
|
||||
height: '50%',
|
||||
bottom: '-10%',
|
||||
left: '10%',
|
||||
border: '1px solid rgba(255,255,255,0.12)',
|
||||
transform: 'rotate(45deg)',
|
||||
}}
|
||||
/>
|
||||
{/* Diagonal stripes (different angle) */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.03]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'repeating-linear-gradient(30deg, #fff 0, #fff 1px, transparent 0, transparent 50%)',
|
||||
backgroundSize: '20px 20px',
|
||||
}}
|
||||
/>
|
||||
{/* Top horizontal line */}
|
||||
<div
|
||||
className="absolute bg-white/20 rounded-full"
|
||||
style={{ width: '40%', height: '1px', top: '22%', left: '8%' }}
|
||||
/>
|
||||
{/* Small filled rectangle */}
|
||||
<div
|
||||
className="absolute bg-white/[0.12] rounded-sm"
|
||||
style={{
|
||||
width: '20%',
|
||||
height: '32%',
|
||||
top: '15%',
|
||||
right: '12%',
|
||||
transform: 'rotate(8deg)',
|
||||
}}
|
||||
/>
|
||||
{/* Dot accent bottom-right */}
|
||||
<div
|
||||
className="absolute opacity-[0.16]"
|
||||
style={{
|
||||
width: '22%',
|
||||
height: '22%',
|
||||
bottom: '8%',
|
||||
right: '8%',
|
||||
backgroundImage: 'radial-gradient(circle, #fff 1.5px, transparent 1.5px)',
|
||||
backgroundSize: '7px 7px',
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{/* Bottom gradient fade */}
|
||||
<div className="absolute inset-x-0 bottom-0 h-1/3 bg-gradient-to-t from-primary-dark/50 to-transparent" />
|
||||
|
||||
{/* Bottom gradient fade — card bg color bleed for text readability */}
|
||||
<div
|
||||
className="absolute inset-x-0 bottom-0 h-2/5"
|
||||
style={{
|
||||
background: isFeatured
|
||||
? 'linear-gradient(to top, rgba(0,100,148,0.55) 0%, transparent 100%)'
|
||||
: cardVariant === 'nimara'
|
||||
? 'linear-gradient(to top, rgba(28,43,58,0.60) 0%, transparent 100%)'
|
||||
: 'linear-gradient(to top, rgba(26,58,74,0.55) 0%, transparent 100%)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Tag Chip ─────────────────────────────────────────────────────────────────
|
||||
|
||||
function TagChip({ label }: { label: string }) {
|
||||
function TagChip({ label, showDot = false }: { label: string; showDot?: boolean }) {
|
||||
return (
|
||||
<span className="inline-flex items-center bg-primary/10 text-primary-dark text-xs font-medium px-2.5 py-1 rounded-full leading-none">
|
||||
<span className="inline-flex items-center gap-1.5 bg-primary/10 text-primary-dark text-[0.75rem] font-semibold px-3 py-1 rounded-full leading-none tracking-wide">
|
||||
{showDot && (
|
||||
<span className="w-1 h-1 rounded-full bg-primary/50 shrink-0" aria-hidden="true" />
|
||||
)}
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
@@ -203,6 +384,7 @@ function FeaturedCard({ project, readLabel }: { project: Project; readLabel: str
|
||||
{/* Geometric image placeholder */}
|
||||
<GeometricPlaceholder
|
||||
variant="featured"
|
||||
cardVariant="default"
|
||||
className="w-full aspect-[16/9] md:aspect-[2/1]"
|
||||
/>
|
||||
|
||||
@@ -210,8 +392,8 @@ function FeaturedCard({ project, readLabel }: { project: Project; readLabel: str
|
||||
<div className="flex flex-col flex-1 p-7 gap-4">
|
||||
{/* Tags */}
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{project.tags.map((tag) => (
|
||||
<TagChip key={tag} label={tag} />
|
||||
{project.tags.map((tag, i) => (
|
||||
<TagChip key={tag} label={tag} showDot={i > 0} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -230,16 +412,15 @@ function FeaturedCard({ project, readLabel }: { project: Project; readLabel: str
|
||||
href={`/work/${project.slug}`}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-2 text-sm font-medium text-primary-dark',
|
||||
'transition-gap duration-200 group/link',
|
||||
'mt-1',
|
||||
'mt-1 group/link',
|
||||
)}
|
||||
>
|
||||
<span className="underline underline-offset-4 decoration-primary/40 group-hover/link:decoration-primary-dark transition-colors duration-200">
|
||||
<span className="relative after:absolute after:bottom-0 after:left-0 after:h-px after:w-full after:bg-primary-dark after:origin-left after:scale-x-100 after:transition-transform after:duration-200">
|
||||
{readLabel}
|
||||
</span>
|
||||
<ArrowRight
|
||||
size={14}
|
||||
className="transition-transform duration-200 group-hover/link:translate-x-1"
|
||||
size={15}
|
||||
className="transition-transform duration-200 group-hover/link:translate-x-1.5"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -249,7 +430,14 @@ function FeaturedCard({ project, readLabel }: { project: Project; readLabel: str
|
||||
|
||||
// ─── Small Card ───────────────────────────────────────────────────────────────
|
||||
|
||||
const SLUG_TO_VARIANT: Record<string, 'nimara' | 'amador'> = {
|
||||
'port-nimara': 'nimara',
|
||||
'port-amador': 'amador',
|
||||
};
|
||||
|
||||
function SmallCard({ project, readLabel }: { project: Project; readLabel: string }) {
|
||||
const cardVariant = SLUG_TO_VARIANT[project.slug] ?? 'nimara';
|
||||
|
||||
return (
|
||||
<motion.article
|
||||
variants={smallCardVariants}
|
||||
@@ -271,6 +459,7 @@ function SmallCard({ project, readLabel }: { project: Project; readLabel: string
|
||||
>
|
||||
<GeometricPlaceholder
|
||||
variant="small"
|
||||
cardVariant={cardVariant}
|
||||
className="w-full aspect-[16/7]"
|
||||
/>
|
||||
</div>
|
||||
@@ -280,8 +469,8 @@ function SmallCard({ project, readLabel }: { project: Project; readLabel: string
|
||||
<div className="flex flex-col flex-1 p-5 gap-3">
|
||||
{/* Tags */}
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{project.tags.map((tag) => (
|
||||
<TagChip key={tag} label={tag} />
|
||||
{project.tags.map((tag, i) => (
|
||||
<TagChip key={tag} label={tag} showDot={i > 0} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -300,12 +489,12 @@ function SmallCard({ project, readLabel }: { project: Project; readLabel: string
|
||||
href={`/work/${project.slug}`}
|
||||
className="inline-flex items-center gap-1.5 text-xs font-medium text-primary-dark group/link"
|
||||
>
|
||||
<span className="underline underline-offset-4 decoration-primary/40 group-hover/link:decoration-primary-dark transition-colors duration-200">
|
||||
<span className="relative after:absolute after:bottom-0 after:left-0 after:h-px after:w-full after:bg-primary-dark after:origin-left after:scale-x-100 after:transition-transform after:duration-200">
|
||||
{readLabel}
|
||||
</span>
|
||||
<ArrowRight
|
||||
size={12}
|
||||
className="transition-transform duration-200 group-hover/link:translate-x-0.5"
|
||||
size={13}
|
||||
className="transition-transform duration-200 group-hover/link:translate-x-1"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -368,14 +557,21 @@ export default function SelectedWorks() {
|
||||
0% { background-position: 0 0, 100% 0, 100% 100%, 0 100%; }
|
||||
100% { background-position: 100% 0, 100% 100%, 0 100%, 0 0; }
|
||||
}
|
||||
@keyframes coming-soon-bg-pulse {
|
||||
0%, 100% { background-color: var(--color-surface-low); }
|
||||
50% { background-color: var(--color-surface); }
|
||||
}
|
||||
@keyframes coming-soon-fade {
|
||||
0%, 100% { opacity: 0; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
.coming-soon-card {
|
||||
animation: coming-soon-bg-pulse 4s ease-in-out infinite;
|
||||
}
|
||||
.coming-soon-pulse {
|
||||
background: radial-gradient(
|
||||
ellipse at center,
|
||||
rgba(91, 164, 217, 0.04) 0%,
|
||||
rgba(91, 164, 217, 0.06) 0%,
|
||||
transparent 70%
|
||||
);
|
||||
animation: coming-soon-fade 4s ease-in-out infinite;
|
||||
|
||||
Reference in New Issue
Block a user