feat: compass/crosshair SVG decorations across landing page, fix email from noreply→hello

- CompassBg: 8 compass marks scattered across full page height with brand amber
  accent on inner ring, faded crosshair lines, cardinal ticks — z-index 0 (behind content)
- Index.tsx: CompassBg rendered as absolute layer inside relative wrapper
- email_service: EMAIL_FROM default hello@ (noreply triggers spam filters)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-05-23 23:06:42 +01:00
parent 969198adde
commit f4dc3074c0
3 changed files with 133 additions and 2 deletions

View file

@ -10,7 +10,7 @@ import httpx
logger = logging.getLogger(__name__)
RESEND_API_KEY = os.environ.get("RESEND_API_KEY", "")
FROM_EMAIL = os.environ.get("EMAIL_FROM", "Cohorta <noreply@ai-impress.com>")
FROM_EMAIL = os.environ.get("EMAIL_FROM", "Cohorta <hello@ai-impress.com>") # ai-impress.com verified in Resend; avoid noreply (spam filter)
APP_URL = os.environ.get("APP_URL", "http://localhost:5173")

View file

@ -0,0 +1,129 @@
import React from 'react';
interface CompassMarkProps {
uid: string;
size: number;
x: string; // CSS left value
y: number; // px from top of container
opacity: number;
rotate?: number;
}
function CompassMark({ uid, size, x, y, opacity, rotate = 0 }: CompassMarkProps) {
const cx = size / 2;
const r1 = size * 0.46; // outer ring
const r2 = size * 0.31; // middle dashed ring
const r3 = size * 0.15; // inner amber ring
const pad = size * 0.04;
return (
<div
aria-hidden="true"
style={{
position: 'absolute',
left: x,
top: y,
width: size,
height: size,
opacity,
transform: `translate(-50%, -50%) rotate(${rotate}deg)`,
pointerEvents: 'none',
}}
>
<svg viewBox={`0 0 ${size} ${size}`} fill="none" xmlns="http://www.w3.org/2000/svg" width={size} height={size}>
<defs>
<linearGradient id={`${uid}-h`} x1="0" y1="0.5" x2="1" y2="0.5" gradientUnits="objectBoundingBox">
<stop offset="0%" stopColor="white" stopOpacity="0" />
<stop offset="20%" stopColor="white" stopOpacity="0.8" />
<stop offset="50%" stopColor="white" stopOpacity="1" />
<stop offset="80%" stopColor="white" stopOpacity="0.8" />
<stop offset="100%" stopColor="white" stopOpacity="0" />
</linearGradient>
<linearGradient id={`${uid}-v`} x1="0.5" y1="0" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0%" stopColor="white" stopOpacity="0" />
<stop offset="20%" stopColor="white" stopOpacity="0.8" />
<stop offset="50%" stopColor="white" stopOpacity="1" />
<stop offset="80%" stopColor="white" stopOpacity="0.8" />
<stop offset="100%" stopColor="white" stopOpacity="0" />
</linearGradient>
<linearGradient id={`${uid}-d1`} x1="0" y1="0" x2="1" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0%" stopColor="white" stopOpacity="0" />
<stop offset="25%" stopColor="white" stopOpacity="0.6" />
<stop offset="75%" stopColor="white" stopOpacity="0.6" />
<stop offset="100%" stopColor="white" stopOpacity="0" />
</linearGradient>
<linearGradient id={`${uid}-d2`} x1="1" y1="0" x2="0" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0%" stopColor="white" stopOpacity="0" />
<stop offset="25%" stopColor="white" stopOpacity="0.6" />
<stop offset="75%" stopColor="white" stopOpacity="0.6" />
<stop offset="100%" stopColor="white" stopOpacity="0" />
</linearGradient>
</defs>
{/* Outer ring */}
<circle cx={cx} cy={cx} r={r1} stroke="white" strokeWidth={size * 0.003} strokeOpacity="0.18" />
{/* Middle dashed ring */}
<circle cx={cx} cy={cx} r={r2} stroke="white" strokeWidth={size * 0.002}
strokeOpacity="0.1" strokeDasharray={`${size * 0.008} ${size * 0.014}`} />
{/* Inner amber ring */}
<circle cx={cx} cy={cx} r={r3} stroke="#E07A2F" strokeWidth={size * 0.003} strokeOpacity="0.55" />
{/* Center dot */}
<circle cx={cx} cy={cx} r={size * 0.007} fill="#E07A2F" fillOpacity="0.6" />
{/* Crosshair lines */}
<line x1={pad} y1={cx} x2={size - pad} y2={cx}
stroke={`url(#${uid}-h)`} strokeWidth={size * 0.002} />
<line x1={cx} y1={pad} x2={cx} y2={size - pad}
stroke={`url(#${uid}-v)`} strokeWidth={size * 0.002} />
{/* Diagonal lines */}
<line x1={pad * 3} y1={pad * 3} x2={size - pad * 3} y2={size - pad * 3}
stroke={`url(#${uid}-d1)`} strokeWidth={size * 0.0015} />
<line x1={size - pad * 3} y1={pad * 3} x2={pad * 3} y2={size - pad * 3}
stroke={`url(#${uid}-d2)`} strokeWidth={size * 0.0015} />
{/* Cardinal ticks on outer ring — N S E W */}
{[0, 90, 180, 270].map(deg => {
const rad = (deg - 90) * Math.PI / 180;
const x1 = cx + (r1 - size * 0.015) * Math.cos(rad);
const y1 = cx + (r1 - size * 0.015) * Math.sin(rad);
const x2 = cx + (r1 + size * 0.025) * Math.cos(rad);
const y2 = cx + (r1 + size * 0.025) * Math.sin(rad);
return (
<line key={deg} x1={x1} y1={y1} x2={x2} y2={y2}
stroke="white" strokeWidth={size * 0.004} strokeOpacity="0.3" />
);
})}
</svg>
</div>
);
}
// Instances scattered across the full landing page height
const MARKS = [
{ uid: 'c0', size: 580, x: '88%', y: 340, opacity: 0.08, rotate: 12 },
{ uid: 'c1', size: 300, x: '-2%', y: 720, opacity: 0.055, rotate: -7 },
{ uid: 'c2', size: 440, x: '82%', y: 1200, opacity: 0.07, rotate: 20 },
{ uid: 'c3', size: 260, x: '22%', y: 1700, opacity: 0.05, rotate: 5 },
{ uid: 'c4', size: 500, x: '10%', y: 2200, opacity: 0.065, rotate: -15 },
{ uid: 'c5', size: 340, x: '75%', y: 2700, opacity: 0.06, rotate: 8 },
{ uid: 'c6', size: 220, x: '40%', y: 3100, opacity: 0.045, rotate: -20 },
{ uid: 'c7', size: 390, x: '92%', y: 3500, opacity: 0.055, rotate: 30 },
] as const;
export default function CompassBg() {
return (
<div
className="absolute inset-0 pointer-events-none overflow-hidden"
style={{ zIndex: 0 }}
aria-hidden="true"
>
{MARKS.map(m => (
<CompassMark key={m.uid} {...m} />
))}
</div>
);
}

View file

@ -1,4 +1,5 @@
import Hero from '@/components/landing/Hero';
import CompassBg from '@/components/landing/CompassBg';
import StatsBand from '@/components/landing/StatsBand';
import FeatureGrid from '@/components/landing/FeatureGrid';
import HowItWorks from '@/components/landing/HowItWorks';
@ -12,7 +13,8 @@ import FinalCTA from '@/components/landing/FinalCTA';
export default function Index() {
return (
<div className="bg-background overflow-hidden">
<div className="bg-background overflow-hidden relative">
<CompassBg />
<Hero />
<StatsBand />
<FeatureGrid />