/* Axon.ps website kit — shared primitives. Exported to window for cross-file use. */
const AXON_PRODUCTS = [
{ id: 'plexus', name: 'Plexus', tagline: 'AI-powered scientific research platform',
line: 'A workflow platform for researchers — AI-assisted writing, reference verification, and citation accuracy.',
features: ['AI-assisted paper writing', 'Reference verification', 'Citation accuracy checking'], status: 'live' },
{ id: 'nowah', name: 'Nowah', tagline: 'Smart platform for municipalities & local councils',
line: 'AI-powered updates on projects, grants and initiatives across Palestinian municipalities, with a full institution directory.',
features: ['Municipality project tracking', 'Grant notifications', 'Institution database'], status: 'live' },
{ id: 'synap', name: 'Synap', tagline: 'Local AI infrastructure & workflow solutions',
line: 'Run AI models on your own hardware. We supply specialized machines and build custom, sovereign workflows.',
features: ['Local model deployment', 'Specialized hardware', 'Custom automation'], status: 'live' },
{ id: 'madar', name: 'Madar', tagline: 'Privacy-first VPN for mobile & desktop',
line: 'A next-generation VPN built with privacy and performance at its core. Madar means "orbit".',
features: ['Mobile & desktop apps', 'No-logs policy', 'High-speed servers'], status: 'soon' },
];
function Eyebrow({ children }) { return {children}; }
function StatusChip({ status }) {
return status === 'live'
? Live
: Coming soon;
}
function Button({ variant = 'signal', children, href = '#', onClick, type }) {
const cls = 'btn btn-' + variant;
if (type === 'submit' || onClick) return ;
return {children};
}
/* Axon mark — recreation of components/AxonLogo.tsx, re-pigmented for the
manuscript palette. Signal waveform replays on hover + on an idle cycle. */
function AxonMark({ size = 40, wordmark = false, theme = 'paper', tone }) {
const ref = React.useRef(null);
const onPaper = theme === 'paper';
const ink = tone || (onPaper ? 'var(--ink-0)' : 'var(--night-text)');
const play = () => {
const el = ref.current; if (!el) return;
el.style.transition = 'none'; el.style.strokeDashoffset = '180';
void el.getBoundingClientRect();
el.style.transition = 'stroke-dashoffset 0.9s var(--ease)';
el.style.strokeDashoffset = '0';
};
React.useEffect(() => {
const t = setTimeout(play, 300);
const iv = setInterval(play, 9000);
return () => { clearTimeout(t); clearInterval(iv); };
}, []);
return (
{wordmark && (
axon
.ps
)}
);
}
/* Open a product detail sheet from anywhere — decoupled event so hero, orbit and
ecosystem (separate script files) all drive the same overlay. */
function openProduct(id, originEl) {
window.dispatchEvent(new CustomEvent('axon:product', { detail: { id, origin: originEl || null } }));
}
/* Product lens — the real product logo unified inside one Axon frame.
The img is zoomed slightly to crop each logo's mismatched native ring, then a
single consistent ink hairline (+ faint gold inner) is drawn on top. This is
how four different marks read as one coherent product system.
Interactive by default: click / Enter / Space opens the product sheet. */
function ProductLens({ id, size = 64, live = true, dim = false, interactive = true, name }) {
const Tag = interactive ? 'button' : 'span';
const handlers = interactive ? {
onClick: (e) => openProduct(id, e.currentTarget),
'aria-haspopup': 'dialog',
'aria-label': 'View ' + (name || id) + ' details',
type: 'button',
} : { 'aria-label': id + ' logo' };
return (
{live && }