// Shared UI primitives — pill, button, input, etc.
// Civic-tech aesthetic: off-white, dark text, navy accent, plain sans-serif.
const Pill = ({ tone = "neutral", children, mono = false }) => {
const map = {
neutral: { bg: "var(--pill-bg)", fg: "var(--pill-fg)", bd: "var(--pill-bd)" },
info: { bg: "var(--pill-info-bg)", fg: "var(--pill-info-fg)", bd: "var(--pill-info-bd)" },
ok: { bg: "var(--pill-ok-bg)", fg: "var(--pill-ok-fg)", bd: "var(--pill-ok-bd)" },
warn: { bg: "var(--pill-warn-bg)", fg: "var(--pill-warn-fg)", bd: "var(--pill-warn-bd)" },
danger: { bg: "var(--pill-danger-bg)", fg: "var(--pill-danger-fg)", bd: "var(--pill-danger-bd)" }
};
const c = map[tone] || map.neutral;
return (
{tone !== "neutral" && (
)}
{children}
);
};
const StatusPill = ({ status }) => {
const meta = window.STATUS_META[status] || { label: status, tone: "neutral" };
return {meta.label};
};
const Button = ({ variant = "primary", children, onClick, disabled, icon, full, size = "md", type = "button" }) => {
const styles = {
primary: { bg: "var(--accent)", fg: "#fff", bd: "var(--accent)" },
secondary: { bg: "var(--surface)", fg: "var(--text)", bd: "var(--rule)" },
ghost: { bg: "transparent", fg: "var(--text)", bd: "transparent" },
danger: { bg: "var(--surface)", fg: "var(--danger-fg)", bd: "var(--danger-fg)" }
};
const s = styles[variant];
const pad = size === "sm" ? "4px 10px" : "8px 14px";
const fs = size === "sm" ? 13 : 14;
return (
);
};
const Field = ({ label, hint, children, error }) => (
);
const TextInput = ({ value, onChange, placeholder, mono, ...rest }) => (
onChange && onChange(e.target.value)}
placeholder={placeholder}
style={{
width: "100%",
padding: "8px 10px",
fontSize: 14,
fontFamily: mono ? "var(--font-mono)" : "inherit",
color: "var(--text)",
background: "var(--surface)",
border: "1px solid var(--rule)",
borderRadius: 2,
outline: "none",
boxShadow: "inset 0 1px 0 rgba(0,0,0,0.03)"
}}
onFocus={(e) => e.currentTarget.style.borderColor = "var(--accent)"}
onBlur={(e) => e.currentTarget.style.borderColor = "var(--rule)"}
{...rest}
/>
);
const TextArea = ({ value, onChange, placeholder, rows = 6, mono }) => (