'use client' import { useState, useEffect, useRef, useMemo } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { X } from 'lucide-react' import { type DetailItem } from './USPSlide.data' const MONO: React.CSSProperties = { fontFamily: '"JetBrains Mono","SF Mono",ui-monospace,monospace', fontVariantNumeric: 'tabular-nums', } // ── Light mode hook export function useIsLight() { const [isLight, setIsLight] = useState(false) useEffect(() => { const check = () => setIsLight(document.documentElement.classList.contains('theme-light')) check() const obs = new MutationObserver(check) obs.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }) return () => obs.disconnect() }, []) return isLight } // ── Ticker function useTicker(fn: () => void, min = 180, max = 420, skip = 0.1) { const ref = useRef(fn) ref.current = fn useEffect(() => { let t: ReturnType const loop = () => { if (Math.random() > skip) ref.current() t = setTimeout(loop, min + Math.random() * (max - min)) } loop() return () => clearTimeout(t) }, [min, max, skip]) } function TickerShell({ tint, isLight, children }: { tint: string; isLight: boolean; children: React.ReactNode }) { return (
{children}
) } export function TickTrace({ tint, isLight }: { tint: string; isLight: boolean }) { const [n, setN] = useState(12748) useTicker(() => setN(v => v + 1 + Math.floor(Math.random() * 3)), 250, 500) return ( trace {n.toLocaleString()} evidence-chain ) } export function TickEngine({ tint, isLight }: { tint: string; isLight: boolean }) { const [v, setV] = useState(428) const [rate, setRate] = useState(99.4) useTicker(() => { setV(x => x + 1 + Math.floor(Math.random() * 4)) setRate(r => Math.max(97, Math.min(99.9, r + (Math.random() - 0.5) * 0.3))) }, 220, 420) return ( validate {v.toLocaleString()} {rate.toFixed(1)}% ) } export function TickOptimizer({ tint, isLight }: { tint: string; isLight: boolean }) { const ops = ['ROI: 2.418 € / dev', 'gap → policy §4.2', 'dedup 128 tickets', 'sweet-spot: 22 KLOC', 'tradeoff: speed↔risk'] const [i, setI] = useState(0) useTicker(() => setI(x => (x + 1) % ops.length), 900, 1600, 0.05) return ( optimize {ops[i]} ) } export function TickStack({ tint, isLight }: { tint: string; isLight: boolean }) { const regs = ['DSGVO', 'NIS-2', 'DORA', 'EU AI Act', 'ISO 27001', 'BSI C5'] const [i, setI] = useState(0) const [c, setC] = useState(1208) useTicker(() => { setI(x => (x + 1) % regs.length); setC(v => v + Math.floor(Math.random() * 3)) }, 800, 1400, 0.05) return ( check {regs[i]} · {c.toLocaleString()} ) } // ── Pillar row export function PillarRow({ side, title, body, tint, onClick, active, isLight }: { side: 'left' | 'right'; title: string; body: string; tint: string onClick: () => void; active: boolean; isLight: boolean }) { const [hover, setHover] = useState(false) const lit = hover || active const isLeft = side === 'left' return (
setHover(true)} onMouseLeave={() => setHover(false)} style={{ display: 'flex', alignItems: 'flex-start', gap: 12, flexDirection: isLeft ? 'row-reverse' : 'row', textAlign: isLeft ? 'right' : 'left', padding: '10px 14px', borderRadius: 10, cursor: 'pointer', transition: 'transform .25s, background .25s, box-shadow .25s', background: lit ? `linear-gradient(${isLeft ? '270deg' : '90deg'}, ${tint}24 0%, ${tint}0a 70%, transparent 100%)` : 'transparent', boxShadow: lit ? `0 10px 30px ${tint}26, inset 0 0 0 1px ${tint}44` : 'inset 0 0 0 1px transparent', transform: lit ? (isLeft ? 'translateX(-3px)' : 'translateX(3px)') : 'translateX(0)', }}>
{title} {isLeft ? '\u2039' : '\u203A'}
{body}
) } // ── Column header export function ColHeader({ side, label, color, icon, sub, isLight }: { side: 'left' | 'right'; label: string; color: string; icon: string; sub: string; isLight: boolean }) { const isLeft = side === 'left' return (
{icon}
{label}
{sub}
) } // ── Central hub export function CentralHub({ caption, isLight }: { caption: string; isLight: boolean }) { return (
{caption}
) } // ─�� Bridge SVG connectors export function BridgeConnectors({ isLight }: { isLight: boolean }) { const rfpY = 130; const sub2Y = 250; const hubCx = 500; const hubR = 72 return ( {([rfpY, sub2Y] as number[]).map(y => ( ))} ) } // ── Feature card export function FeatureCard({ icon, title, body, tint, Ticker, onClick, active, isLight }: { icon: string; title: string; body: string; tint: string Ticker: React.ComponentType<{ tint: string; isLight: boolean }> onClick: () => void; active: boolean; isLight: boolean }) { const [hover, setHover] = useState(false) const lit = hover || active return (
setHover(true)} onMouseLeave={() => setHover(false)} style={{ position: 'relative', padding: '13px 15px', background: isLight ? lit ? `linear-gradient(180deg, ${tint}18 0%, ${tint}08 55%, rgba(248,250,252,.95) 100%)` : 'linear-gradient(180deg, #ffffff, #f8fafc)' : `linear-gradient(180deg, ${tint}${lit ? '2a' : '1a'} 0%, ${tint}07 55%, rgba(14,8,28,.85) 100%)`, border: `1px solid ${lit ? tint : isLight ? 'rgba(0,0,0,.1)' : tint + '4a'}`, borderRadius: 12, boxShadow: lit ? `0 18px 40px ${tint}33, 0 0 0 1px ${tint}66, inset 0 1px 0 ${tint}60` : isLight ? '0 2px 8px rgba(0,0,0,.08), inset 0 1px 0 rgba(255,255,255,.8)' : `0 10px 24px rgba(0,0,0,.4), inset 0 1px 0 ${tint}35`, minWidth: 0, cursor: 'pointer', transform: lit ? 'translateY(-3px)' : 'translateY(0)', transition: 'transform .25s, box-shadow .25s, background .25s, border-color .25s', }}>
{icon} {title}
{body}
) } // ── Detail modal export function DetailModal({ item, onClose, isLight }: { item: DetailItem | null; onClose: () => void; isLight: boolean }) { useEffect(() => { if (!item) return const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } window.addEventListener('keydown', onKey) return () => window.removeEventListener('keydown', onKey) }, [item, onClose]) return ( {item && ( e.stopPropagation()} style={{ width: 560, maxWidth: '88%', background: isLight ? `linear-gradient(180deg, ${item.tint}10 0%, rgba(255,255,255,.98) 50%, rgba(248,250,252,.99) 100%)` : `linear-gradient(180deg, ${item.tint}18 0%, rgba(20,10,40,.96) 50%, rgba(14,8,28,.98) 100%)`, border: `1px solid ${item.tint}${isLight ? '44' : '66'}`, borderRadius: 16, boxShadow: isLight ? `0 20px 60px rgba(0,0,0,.12), 0 0 40px ${item.tint}18, inset 0 1px 0 rgba(255,255,255,.9)` : `0 30px 80px rgba(0,0,0,.6), 0 0 60px ${item.tint}33, inset 0 1px 0 ${item.tint}55`, padding: '22px 26px', color: isLight ? '#1a1a2e' : '#ece9f7', }}>
{item.icon}
{item.kicker}
{item.title}
{item.body}
{item.bullets && (
{item.bullets.map((b, i) => (
{b}
))}
)} {item.stat && (
{item.stat.k} {item.stat.v}
)}
)}
) } // ── Star field export function StarField({ isLight }: { isLight: boolean }) { const stars = useMemo(() => { let s = 41 const r = () => { s = (s * 9301 + 49297) % 233280; return s / 233280 } return Array.from({ length: 90 }, () => ({ x: r() * 100, y: r() * 100, size: r() * 1.4 + 0.3, op: r() * 0.5 + 0.15 })) }, []) if (isLight) return null return (
{stars.map((st, i) => (
))}
) }