// Vecton primitives + icons for Voice-to-Form const V = { orange: "#FF5631", purple: "#7E43BA", brown: "#24140D", beige: "#E8E9D7", offWhite: "#F9FAF6", white: "#FFFFFF", brownLight: "#3D2A1F", brownMid: "#6B5147", brownFaded: "#9A8A82", orangeSubtle: "rgba(255,86,49,0.08)", orangeLight: "rgba(255,86,49,0.15)", purpleSubtle: "rgba(126,67,186,0.08)", purpleLight: "rgba(126,67,186,0.15)", borderLight: "rgba(36,20,13,0.10)", borderMed: "rgba(36,20,13,0.14)", success: "#16A34A", successBg: "rgba(22,163,74,0.10)", warning: "#D97706", warningBg: "rgba(217,119,6,0.12)", danger: "#DC2626", dangerBg: "rgba(220,38,38,0.10)", radius: "7px", radiusSm: "5px", radiusLg: "11px", radiusPill: "9999px", font: "'Instrument Sans', Arial, sans-serif", fw: { r: 400, m: 500, sb: 600 }, shadowSm: "0 1px 2px rgba(36,20,13,.08)", shadowMd: "0 4px 12px rgba(36,20,13,.10)", shadowLg: "0 12px 32px rgba(36,20,13,.15)", shadowOrange: "0 4px 16px rgba(255,86,49,.25)", }; // Lucide-style stroke icons (1.5px, round caps) const Icon = ({ name, size = 16, color = "currentColor", sw = 1.5, style }) => { const p = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: sw, strokeLinecap: "round", strokeLinejoin: "round", style: { display: "block", flexShrink: 0, ...style }, }; const paths = { mic: <>, micOff: <>, upload: <>, play: , pause: <>, stop: , check: , checkCircle: <>, x: <>, arrowRight: <>, arrowLeft: <>, alert: <>, info: <>, sparkles: <>, user: <>, briefcase: <>, file: <>, edit: <>, trash: <>, zap: , refresh: <>, download: <>, phone: , mail: <>, home: <>, creditCard: <>, coins: <>, shield: , lock: <>, hash: <>, circle: , chevDown: , chevUp: , volume: <>, eye: <>, wand: <>, clock: <>, building: <>, trendingUp: <>, waveform: <>, }; return {paths[name]}; }; const Button = ({ variant = "primary", size = "md", icon, iconRight, children, onClick, disabled, style, type = "button" }) => { const sizes = { sm: { padding: "7px 12px", fontSize: 12, gap: 6 }, md: { padding: "10px 18px", fontSize: 13, gap: 8 }, lg: { padding: "13px 24px", fontSize: 14, gap: 10 }, }; const variants = { primary: { background: V.orange, color: V.offWhite, border: "none", boxShadow: V.shadowOrange }, secondary: { background: V.brown, color: V.beige, border: "none" }, outline: { background: V.white, color: V.brown, border: `1px solid ${V.borderMed}` }, ghost: { background: "transparent", color: V.brownMid, border: "none", boxShadow: "none" }, }; return ( ); }; const Eyebrow = ({ children, style }) => (
{children}
); const FocusCorners = ({ color = V.orange, size = 10, thick = 1.5, inset = -4 }) => { const s = { position: "absolute", width: size, height: size, pointerEvents: "none" }; return ( <>
); }; // Confidence badge with color-coded dot + % const ConfidenceBadge = ({ score }) => { // score 0..1 let color, bg, label; if (score >= 0.9) { color = V.success; bg = V.successBg; label = "High"; } else if (score >= 0.7) { color = V.warning; bg = V.warningBg; label = "Med"; } else { color = V.danger; bg = V.dangerBg; label = "Low"; } const pct = Math.round(score * 100); return ( {pct}% ); }; // Status pill const StatusPill = ({ kind = "neutral", children, icon }) => { const map = { success: { bg: V.successBg, fg: V.success }, warning: { bg: V.warningBg, fg: V.warning }, danger: { bg: V.dangerBg, fg: V.danger }, info: { bg: V.purpleSubtle, fg: V.purple }, accent: { bg: V.orangeSubtle, fg: V.orange }, neutral: { bg: "rgba(36,20,13,.06)", fg: V.brownMid }, }; const s = map[kind] || map.neutral; return ( {icon && } {children} ); }; // Input field with optional confidence badge + status border const FormField = ({ label, value, onChange, placeholder, confidence, status, note, error, icon, type = "text", options, monospace, mask, readOnly, required, }) => { // status: "filled" | "missing" | "low" | "corrected" | "spelled" | null const statusColors = { filled: { border: V.borderMed, bg: V.white }, missing: { border: V.danger, bg: V.dangerBg }, low: { border: V.warning, bg: "rgba(217,119,6,0.04)" }, corrected: { border: V.purple, bg: V.purpleSubtle }, spelled: { border: V.purple, bg: V.purpleSubtle }, empty: { border: V.borderMed, bg: V.white }, }; const sc = statusColors[status] || statusColors.empty; const isFilled = value !== null && value !== undefined && value !== ""; return (
{confidence !== undefined && confidence !== null && isFilled && }
{icon && (
)} {options ? ( ) : ( onChange?.(e.target.value)} placeholder={placeholder} readOnly={readOnly} style={{ width: "100%", padding: icon ? "10px 12px 10px 32px" : "10px 12px", borderRadius: V.radiusSm, border: `1px solid ${sc.border}`, fontFamily: monospace ? "'JetBrains Mono', ui-monospace, Consolas, monospace" : V.font, fontSize: 13, color: isFilled ? V.brown : V.brownFaded, background: sc.bg, outline: "none", boxSizing: "border-box", fontWeight: monospace ? V.fw.sb : V.fw.r, letterSpacing: monospace ? "0.02em" : "normal", fontVariantNumeric: monospace ? "tabular-nums" : "normal", transition: "border-color 0.2s, background 0.2s", }} onFocus={e => e.target.style.borderColor = V.orange} onBlur={e => e.target.style.borderColor = sc.border} /> )}
{note && (
{note}
)} {error && (
{error}
)}
); }; // Section header with eyebrow + count const SectionHeader = ({ eyebrow, title, subtitle, count, total, right }) => (
{eyebrow && {eyebrow}}
{title}
{subtitle &&
{subtitle}
}
{(count !== undefined || right) && (
{count !== undefined && (
{count} / {total} filled
)} {right}
)}
); const Card = ({ children, style, pad = 28 }) => (
{children}
); // Step indicator chip for header const StepChip = ({ num, label, state }) => { // state: "done" | "active" | "pending" const cfg = { done: { bg: V.successBg, fg: V.success, border: "transparent" }, active: { bg: V.orangeLight, fg: V.orange, border: V.orange }, pending: { bg: "transparent", fg: V.brownFaded, border: V.borderMed }, }[state]; return (
{state === "done" ? : num} {label}
); }; // Minimal audio player widget — visual-only play/pause + duration display. const MiniPlayer = ({ duration }) => { const [playing, setPlaying] = React.useState(false); const fmt = (s) => { if (!s && s !== 0) return "--:--"; return `${String(Math.floor(s / 60)).padStart(2, "0")}:${String(Math.floor(s % 60)).padStart(2, "0")}`; }; return (
{fmt(duration)}
); }; Object.assign(window, { V, Icon, Button, Eyebrow, FocusCorners, ConfidenceBadge, StatusPill, FormField, SectionHeader, Card, StepChip, MiniPlayer });