/** * Shared chart styling. All colors are CSS variables so charts follow light/dark themes. * Success/failed use status tokens (they *mean* good/bad); every chart pairs color with * a text legend and a table twin so identity is never carried by color alone. */ export const CHART_COLORS = { accent: "var(--accent)", success: "var(--success)", danger: "var(--danger)", warning: "var(--warning)", info: "var(--info)", muted: "var(--fg-subtle)", faint: "var(--border-strong)", grid: "var(--border)", surface: "var(--bg-elevated)", cursor: "var(--bg-muted)", } as const; /** Network classes get a fixed color per entity: residential (live) is emphasized, the rest are neutral. */ export const NETWORK_COLORS: Record = { residential: CHART_COLORS.accent, datacenter: CHART_COLORS.muted, isp: CHART_COLORS.faint, mobile: CHART_COLORS.info, }; export const AXIS_TICK = { fill: "var(--fg-subtle)", fontSize: 11, fontFamily: "var(--font-mono)" } as const; export const CHART_MARGIN = { top: 8, right: 8, bottom: 0, left: 0 } as const; export function formatTick(iso: string, bucket: "hour" | "day"): string { const d = new Date(iso); if (bucket === "hour") return new Intl.DateTimeFormat("en-US", { hour: "numeric", timeZone: "UTC" }).format(d); return new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", timeZone: "UTC" }).format(d); } export function formatBucketLabel(iso: string, bucket: "hour" | "day"): string { const d = new Date(iso); if (bucket === "hour") return `${new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", hour: "numeric", timeZone: "UTC" }).format(d)} UTC`; return new Intl.DateTimeFormat("en-US", { weekday: "short", month: "short", day: "numeric", timeZone: "UTC" }).format(d); }