// live-shared.jsx — Shared brand system + components for the Live Video Inspection A/B/C test. // Logo-only header (NO site nav), sticky CTA, the live-call hero mock, trust block, FAQ, // testimonials, how-it-works, price/risk-reversal, photo slots, and tracking hooks. const { useState, useEffect, useRef } = React; // ===== BRAND TOKENS (Lemon Squad) ===== const LV = { red: '#E63B2E', redDark: '#C42E22', redBg: '#FEF2F2', redBorder: '#FBD5D0', yellow: '#F5A623', yellowBg: '#FFF8EB', yellowText: '#92400E', yellowBorder: '#FCE4B6', ink: '#16202E', charcoal: '#1A202C', navy: '#222C3C', navyDeep: '#141B26', green: '#0F9D58', greenBg: '#ECFDF3', greenBorder: '#B7E4C7', g50: '#F8FAFB', g100: '#F1F4F7', g200: '#E4E9EF', g300: '#D2DAE3', g400: '#9AA6B4', g500: '#697686', g600: '#4D5969', g700: '#3A4453', white: '#FFFFFF' }; const FONT = "'Plus Jakarta Sans', system-ui, -apple-system, sans-serif"; const MAXW = 480; // mobile-first column const MAXW_D = 1120; // desktop content cap // Responsive hook: true when viewport is desktop-wide. function useIsWide(bp = 920) { const force = typeof window !== 'undefined' && /[?&]forcewide/.test(window.location.search); const [wide, setWide] = useState(force || (typeof window !== 'undefined' && window.innerWidth >= bp)); useEffect(() => { if (force) { setWide(true); return; } const f = () => setWide(window.innerWidth >= bp); f(); window.addEventListener('resize', f); return () => window.removeEventListener('resize', f); }, [bp, force]); return wide; } const phoneNumber = '(888) 231-7965'; // ===== ICONS (simple stroke paths only) ===== function Icon({ d, size = 20, color = 'currentColor', sw = 2, fill = 'none', style }) { return ( {Array.isArray(d) ? d.map((p, i) => ) : } ); } const ICON = { check: 'M20 6L9 17l-5-5', shield: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z', shieldCheck: ['M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z', 'M9 12l2 2 4-4'], video: ['M23 7l-7 5 7 5V7z', 'M14 5H3a2 2 0 00-2 2v10a2 2 0 002 2h11a2 2 0 002-2V7a2 2 0 00-2-2z'], phone: 'M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72c.13.96.36 1.9.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0122 16.92z', car: ['M5 17h14M6 17l-1.5-4.5A2 2 0 016.4 10h11.2a2 2 0 011.9 1.5L21 17', 'M7 17v2M17 17v2'], user: ['M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2', 'M12 3a4 4 0 100 8 4 4 0 000-8z'], clock: ['M12 22a10 10 0 100-20 10 10 0 000 20z', 'M12 7v5l3 2'], arrow: 'M5 12h14M13 6l6 6-6 6', chevron: 'M9 18l6-6-6-6', chevronDown: 'M6 9l6 6 6-6', star: 'M12 2l3 6.5 7 .9-5 4.8 1.2 7-6.4-3.4L5.6 21l1.2-7-5-4.8 7-.9L12 2z', spark: 'M12 2l2.4 7.2L22 12l-7.6 2.8L12 22l-2.4-7.2L2 12l7.6-2.8L12 2z', mic: ['M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z', 'M19 10v2a7 7 0 01-14 0v-2M12 19v4'], send: ['M22 2L11 13', 'M22 2l-7 20-4-9-9-4 20-7z'], map: ['M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z', 'M12 13a3 3 0 100-6 3 3 0 000 6z'], eye: ['M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z', 'M12 15a3 3 0 100-6 3 3 0 000 6z'], award: ['M12 15a7 7 0 100-14 7 7 0 000 14z', 'M8.2 13.9L7 22l5-3 5 3-1.2-8.1'], link: ['M10 13a5 5 0 007.5.5l3-3a5 5 0 00-7-7l-1.7 1.7', 'M14 11a5 5 0 00-7.5-.5l-3 3a5 5 0 007 7l1.7-1.7'], refresh: ['M23 4v6h-6', 'M1 20v-6h6', 'M3.5 9a9 9 0 0114.9-3.4L23 10M1 14l4.6 4.4A9 9 0 0020.5 15'], wallet: ['M21 12V7H5a2 2 0 010-4h14v4', 'M3 5v14a2 2 0 002 2h16v-5', 'M18 12a2 2 0 000 4h4v-4h-4z'] }; // ===== STARS ===== function Stars({ value = 5, size = 14, gap = 1 }) { return (
{[1, 2, 3, 4, 5].map((i) => )}
); } // ===== AVATAR (monogram) ===== const AV_TONES = [ ['#FDE7E3', '#C42E22'], ['#FEF0D6', '#92400E'], ['#E2F1EA', '#0F7A47'], ['#E4ECF7', '#2B4C7E'], ['#EDE6F5', '#5B3E86'], ['#F6E5EC', '#9B3B63']]; function Avatar({ name = 'A B', size = 44, ring = false }) { const init = name.split(' ').map((w) => w[0]).slice(0, 2).join('').toUpperCase(); const tone = AV_TONES[(name.charCodeAt(0) + (name.charCodeAt(name.length - 1) || 0)) % AV_TONES.length]; return (
{init}
); } // ===== PHOTO SLOT (clearly-marked, swappable placeholder) ===== function PhotoSlot({ label, ratio = '4 / 3', radius = 14, dark = false, warm = false, tag = 'PHOTO', minH, style, icon }) { const bg = dark ? 'repeating-linear-gradient(135deg, #20293A 0 14px, #232E41 14px 28px)' : warm ? 'linear-gradient(150deg, #F6E2D2 0%, #EFD3C0 55%, #E7C6AE 100%)' : 'repeating-linear-gradient(135deg, #EEF2F6 0 14px, #E6ECF2 14px 28px)'; const tagColor = dark ? 'rgba(255,255,255,0.55)' : warm ? 'rgba(120,78,52,0.7)' : LV.g400; const labelColor = dark ? 'rgba(255,255,255,0.7)' : warm ? '#8A5A3C' : LV.g500; return (
{icon &&
}
{tag}
{label}
); } // ===== HEADER (logo only — NO site nav) ===== function LiveHeader({ dark = false, showPhone = true, ctaLabel, onCta, track = 'header-cta' }) { return (
Lemon Squad {ctaLabel ? : showPhone ? {phoneNumber} : null}
); } // ===== PRICE + RISK REVERSAL line ===== function PriceLine({ dark = false, align = 'center', compact = false }) { const sub = dark ? 'rgba(255,255,255,0.72)' : LV.g600; return (
$59.99 · You're only charged after your session
); } // ===== TRUST CUE PILL (single, for above the fold) — no review ratings ===== function TrustPill({ dark = false }) { return (
America’s Largest & Most Trusted · since 2005
); } // ===== THE LIVE-CALL HERO MOCK ===== // A believable live video-inspection call. Photo content is a clearly-marked, swappable slot; // the call chrome (LIVE badge, timer, inspector lower-third, controls) + cycling inspector // captions sell the concept in ~3 seconds with sound off. const CALL_CAPTIONS = [ "Okay — pop the hood and pan slowly across the engine for me.", "See that seam? Factory paint. No accident on this corner — good sign.", "Now show me the driver-side front tire… tread's getting low there.", "Start it up and point at the dash — checking for warning lights.", "No leaks underneath. This one's looking solid so far."]; function VideoCallMock({ rounded = 24, cycle = true, label = "Live: you film the car, the inspector guides you", inspector = "Marcus T." }) { const [cap, setCap] = useState(0); const [secs, setSecs] = useState(252); useEffect(() => { if (!cycle) return; const a = setInterval(() => setCap((c) => (c + 1) % CALL_CAPTIONS.length), 3200); const b = setInterval(() => setSecs((s) => s + 1), 1000); return () => {clearInterval(a);clearInterval(b);}; }, [cycle]); const mm = String(Math.floor(secs / 60)).padStart(2, '0'); const ss = String(secs % 60).padStart(2, '0'); return (
{/* the "video" of the car (swappable) */}
{/* moving scan highlight */}
{/* top status bar */}
LIVE
{mm}:{ss}
{/* inspector PiP */}
{inspector}
{/* caption lower-third (inspector speaking) */}
{inspector} · Certified Inspector
“{CALL_CAPTIONS[cap]}”
{/* call controls */}
{/* honest caption */}
{label}
); } // ===== REAL EXPLAINER VIDEO (YouTube) ===== // The actual on-page explainer that's outperforming expectations. Two modes: // - "ambient": silent autoplay + loop, no controls (Variant A "show it" hero) // - "facade": branded poster + play button; tapping loads the iframe with sound const YT_ID = '-nhxJclhPHk'; const YT_THUMB = `https://i.ytimg.com/vi/${YT_ID}/hqdefault.jpg`; // Lightweight analytics hook: pushes to dataLayer (GA4) AND fires a DOM event. // Claude Code maps these to GA4 events at integration time (see dev handoff notes). function lvTrack(event, params) { try { const detail = Object.assign({ event: event }, params || {}); (window.dataLayer = window.dataLayer || []).push(detail); window.dispatchEvent(new CustomEvent('lv-track', { detail: detail })); } catch (e) {} } function ExplainerVideo({ mode = 'ambient', rounded = 18, label = 'See how it works', sub = '60-second explainer', variant = '' }) { // Native HTML5 player. Behavior: autoplay ONCE muted on view → on end, return to a // start screen with a Play button → tapping plays from the start WITH sound. const vref = useRef(null); const wrapRef = useRef(null); const [phase, setPhase] = useState('idle'); // 'idle' | 'intro' (muted once) | 'cover' (start screen) | 'playing' (sound) const poster = window.LS_VIDEO_POSTER || YT_THUMB; const srcAvail = !!window.LS_VIDEO_SRC; const seen = useRef({ q25: false, q50: false, q75: false, started: false }); // Autoplay muted once when scrolled into view (better for mobile + battery). useEffect(() => { const v = vref.current,w = wrapRef.current; if (!v || !w || !srcAvail) return; let started = false; const io = new IntersectionObserver((ents) => { ents.forEach((e) => { if (e.isIntersecting && !started) { started = true; v.muted = true;v.currentTime = 0; const p = v.play(); if (p && p.catch) p.catch(() => setPhase('cover')); setPhase('intro'); lvTrack('video_autoplay_start', { variant: variant, muted: true }); } }); }, { threshold: 0.5 }); io.observe(w); return () => io.disconnect(); }, [srcAvail]); const onEnded = () => { lvTrack('video_complete', { variant: variant, with_sound: phase === 'playing' }); setPhase('cover'); }; const onTime = () => { const v = vref.current;if (!v || !v.duration) return; const pct = v.currentTime / v.duration; const s = seen.current; if (pct >= 0.25 && !s.q25) {s.q25 = true;lvTrack('video_progress', { variant: variant, pct: 25 });} if (pct >= 0.5 && !s.q50) {s.q50 = true;lvTrack('video_progress', { variant: variant, pct: 50 });} if (pct >= 0.75 && !s.q75) {s.q75 = true;lvTrack('video_progress', { variant: variant, pct: 75 });} }; const playWithSound = () => { const v = vref.current;if (!v) return; v.muted = false;v.currentTime = 0; setPhase('playing'); lvTrack('video_sound_on', { variant: variant }); const p = v.play();if (p && p.catch) p.catch(() => {}); }; return (
{srcAvail ?