/* Brand Lens — app shell + navigation. The chrome matches the published Proper Sky Brand Guide pages (Imagery.html et al.): shared sidebar nav, topbar crumb, page hero, underline tab strip. All workflow views (Library / Review / Scoreboard / StyleGuide / Playbook) are untouched — this file is presentation only. */ function App() { const [recs, setRecs] = useState(null); const [tab, setTab] = useState('library'); const [layout, setLayoutState] = useState(() => localStorage.getItem('lens-layout') || 'focus'); const [navOpen, setNavOpen] = useState(false); const reload = useCallback(async () => { const all = await window.LensDB.getAll(); setRecs(all); }, []); useEffect(() => { reload(); }, [reload]); const setLayout = (l) => { setLayoutState(l); localStorage.setItem('lens-layout', l); }; // navigate + refresh from DB so every tab sees the latest verdicts const go = useCallback((t) => { reload(); setTab(t); }, [reload]); // mobile drawer (same behavior as mobile-nav.js on the published pages, // but React-owned so it survives re-renders) useEffect(() => { document.body.classList.toggle('mnav-open', navOpen); return () => document.body.classList.remove('mnav-open'); }, [navOpen]); useEffect(() => { const onKey = (e) => { if (e.key === 'Escape') setNavOpen(false); }; document.addEventListener('keydown', onKey); return () => document.removeEventListener('keydown', onKey); }, []); if (recs === null) { return
Loading your library…
; } const unrev = recs.filter((r) => !r.user).length; const reviewed = recs.filter((r) => r.user && r.ai).length; const tabs = [ { k: 'library', label: 'Repository', icon: 'cards', badge: recs.length || null }, { k: 'review', label: 'Calibrate', icon: 'scale', badge: unrev || null }, { k: 'scoreboard', label: 'Scoreboard', icon: 'scale', badge: null }, { k: 'guide', label: 'Style guide', icon: 'sparkle', badge: null }, { k: 'playbook', label: 'Social playbook', icon: 'share', badge: null }, ]; return (
{/* mobile app bar + scrim (hidden on desktop via guide-shell.css) */}
In Practice / Brand Lens
{reviewed} reviewed · {unrev} to go Imagery guidelines

In Practice · Imagery & Social

Brand Lens

The judge that learns our eye. The AI calls each image first — you agree or disagree and say why. Your comments re-teach it between rounds, until its calls match ours.

{tab === 'library' && go('review')} />} {tab === 'review' && go('library')} goScore={() => go('scoreboard')} />} {tab === 'scoreboard' && go('review')} goGuide={() => go('guide')} />} {tab === 'guide' && go('review')} />} {tab === 'playbook' && go('review')} />}
); } ReactDOM.createRoot(document.getElementById('root')).render();