/* ProofMark Studio — shared components */
const { useState, useEffect, useMemo, useRef, useCallback } = React;
/* ---------- Tiny monochrome Glyph (no imported icon libs) ---------- */
const Glyph = ({ name, size = 16, stroke = 1.6 }) => {
const s = size; const sw = stroke;
const common = {
width: s, height: s, viewBox: '0 0 24 24', fill: 'none',
stroke: 'currentColor', strokeWidth: sw, strokeLinecap: 'round', strokeLinejoin: 'round',
};
switch (name) {
case 'search': return ;
case 'cmd': return ;
case 'spark': return ;
case 'arrow': return ;
case 'check': return ;
case 'x': return ;
case 'dot': return ;
case 'plus': return ;
case 'chev': return ;
case 'chevD': return ;
case 'star': return ;
case 'pin': return ;
case 'bolt': return ;
case 'folder': return ;
case 'settings':return ;
case 'home': return ;
case 'grid': return ;
case 'list': return ;
case 'inbox': return ;
case 'clock': return ;
case 'pdf': return ;
case 'text': return ;
case 'merge': return ;
case 'split': return ;
case 'extract': return ;
case 'compress':return ;
case 'rotate': return ;
case 'minus': return ;
case 'pencil': return ;
case 'pen': return ;
case 'book': return ;
case 'hash': return ;
case 'crop': return ;
case 'square': return ;
case 'layers': return ;
case 'form': return ;
case 'docx': return ;
case 'xlsx': return ;
case 'pptx': return ;
case 'img': return ;
case 'txt': return ;
case 'md': return ;
case 'html': return ;
case 'ocr': return ;
case 'sig': return ;
case 'send': return ;
case 'unlock': return ;
case 'lock': return ;
case 'aa': return ;
case 'space': return ;
case 'quote': return ;
case 'report': return ;
case 'ai': return ;
case 'chat': return ;
case 'sum': return ;
case 'globe': return ;
case 'stack': return ;
case 'box': return ;
case 'ruler': return ;
case 'feed': return ;
case 'logo': return (
);
default: return ;
}
};
/* ---------- Status pill ---------- */
const StatusPill = ({ status, size='sm', paused=false }) => {
const map = {
live: { label:'Live', color:'var(--live)' },
beta: { label:'Beta', color:'var(--beta)' },
planned: { label:'Planned', color:'var(--planned)' },
paused: { label:'Paused', color:'var(--beta)' },
};
// Flag-downgraded live tools carry paused=true so the pill reads "Paused"
// instead of collapsing silently into "Planned".
const key = paused ? 'paused' : status;
const s = map[key] || map.planned;
const pad = size === 'sm' ? '2px 8px' : '4px 10px';
return (
{s.label}
);
};
/* ---------- Keyboard shortcut ---------- */
const Kbd = ({ children }) => (
{children}
);
/* ---------- Sidebar ---------- */
const Sidebar = ({ active, onSelect, onOpenPalette, density, isMobile, open, onClose, pinnedSlugs }) => {
const items = [
{ id:'home', label:'Home', g:'home', kbd:'H' },
{ id:'tools', label:'All tools', g:'grid', kbd:'G' },
{ id:'pinned', label:'Pinned', g:'pin', kbd:'P' },
{ id:'map', label:'Platform', g:'layers', kbd:'M' },
];
const bottom = [
{ id:'settings', label:'Settings', g:'settings' },
];
const pinnedTools = __pmVisible(window.PM_TOOLS).filter(t => pinnedSlugs.includes(t.slug));
const handleNav = (id) => {
onSelect(id);
if (isMobile) onClose();
};
return (