/* visdi-shared.jsx - VISDI by Minerva - Shared UI components Exports: WheelMark · NavBar · Btn · Eyebrow · Arrow · CircuitSVG · PageHero · SiteFooter · STAGE */ const WORDMARK = "assets/logo-minerva-km-dark.svg"; const KM_HORIZONTAL = "assets/logo-minerva-km-horizontal.svg"; /* color-on-white — master bar */ const KM_WHITECLEAR = "assets/logo-minerva-km-white-clear.svg"; /* white, transparent — pinned sub-bar */ const MARK_SRC = "assets/logo-minerva-km.svg"; const VISDI_ICON = "assets/logo-visdi-wheels-white.svg"; const NAV_SPECTRUM = "linear-gradient(90deg,#D51C29,#E0542A,#E0A230,#F2D12E,#8FBF3F,#069848,#1AA89A,#3FB1E5,#1C4DA1,#4A3BA8,#8B2CA8,#D20F8C)"; /* Standalone-bundle resolver: maps an asset path to its inlined blob URL when the page has been bundled (window.__resources present), else returns the path unchanged. No-op on the normal multi-file site. */ if (!window.__asset) window.__asset = function (p) { return (window.__resources && window.__resources[p]) || p; }; /* Stage color system - Brief §2.1: Diagnose=gold · Connect=blue · Operate=green */ const STAGE = { diagnose: { color:"#E0A230", bg:"rgba(224,162,48,0.08)", border:"rgba(224,162,48,0.22)", label:"Diagnose" }, connect: { color:"#3FB1E5", bg:"rgba(63,177,229,0.08)", border:"rgba(63,177,229,0.22)", label:"Connect" }, operate: { color:"#04975e", bg:"rgba(4,151,94,0.08)", border:"rgba(4,151,94,0.22)", label:"Operate" }, }; /* 2026 spectrum wheel - CSS-crop of logo-minerva-km.svg (61% height = wheel only) */ function WheelMark({ width = 360, style = {} }) { const aspect = 180.5 / 160.9; const fullH = Math.round(width / aspect); const cropH = Math.round(fullH * 0.61); return (
); } /* Global navigation */ const NAV_LINKS = [ { id:"method", label:"The Method", href:"visdi-method.html" }, { id:"products", label:"Products", href:"visdi-products.html"}, { id:"mingi", label:"Mingi", href:"visdi-mingi.html" }, ]; /* Persistent two-tier brand bar — Tier 1 master (firm, scrolls away) + Tier 2 General Intelligence sub-bar (sticky, pins). See the handoff spec. */ function NavBar({ page = "home" }) { const [pinned, setPinned] = React.useState(false); const [menuOpen, setMenuOpen] = React.useState(false); React.useEffect(() => { const onScroll = () => setPinned(window.scrollY > 60); onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); /* close the mobile menu if the viewport grows back to desktop */ React.useEffect(() => { const onResize = () => { if (window.innerWidth > 1024) setMenuOpen(false); }; window.addEventListener("resize", onResize); return () => window.removeEventListener("resize", onResize); }, []); /* lock body scroll while the overlay is open */ React.useEffect(() => { document.body.style.overflow = menuOpen ? "hidden" : ""; return () => { document.body.style.overflow = ""; }; }, [menuOpen]); const dim = "rgba(231,239,250,0.62)"; const SKY = "#3FB1E5"; /* master-bar division box — previews the destination site's theme. block=true → full-width stacked variant for the mobile menu (equal lengths). */ const divBox = ({ href, label, kind, active, block = false }) => { const box = kind === "gi" ? { background: active ? "#0A1426" : "#0E1A30", color: "#FFFFFF", border: `1px solid ${active ? SKY : "rgba(63,177,229,0.45)"}`, boxShadow: active ? "0 2px 14px rgba(63,177,229,0.30)" : "none", dot: SKY } : { background: "#FFFFFF", color: active ? "#067A3E" : "var(--ink-800)", border: `1px solid ${active ? "#069348" : "var(--ink-300)"}`, boxShadow: active ? "0 2px 14px rgba(6,147,72,0.20)" : "0 1px 2px rgba(15,26,46,0.06)", dot: "#069348" }; return ( setMenuOpen(false) : undefined} style={{ display: block ? "flex" : "inline-flex", alignItems:"center", justifyContent: block ? "center" : "flex-start", gap:9, cursor:"pointer", fontFamily:"var(--wix-text)", fontSize:15, fontWeight: active ? 700 : 600, letterSpacing:"-0.01em", whiteSpace:"nowrap", padding: block ? "14px 18px" : "10px 18px", borderRadius:"var(--radius-md)", width: block ? "100%" : "auto", boxSizing:"border-box", background:box.background, color:box.color, border:box.border, boxShadow:box.boxShadow }}> {active && } {label} ); }; /* hamburger / close toggle — hidden on desktop via .nav-burger CSS */ const burger = (color) => ( ); return ( {/* ── Tier 1 — Minerva master brand bar (white, frosted; scrolls away) ── */}
Minerva Knowledge Management
{divBox({ href:"/knowledge-governance/", label:"Knowledge Governance", kind:"kg", active:false })} {divBox({ href:"/general-intelligence/", label:"General Intelligence", kind:"gi", active:true })} Start a Diagnostic
{burger("#0A1426")}
{/* ── Tier 2 — General Intelligence sub-bar (dark, sticky; pins) ── */} {/* ── Mobile menu overlay (hamburger target; equal-width stacked actions) ── */}
Minerva Knowledge Management
Divisions {divBox({ href:"/knowledge-governance/", label:"Knowledge Governance", kind:"kg", active:false, block:true })} {divBox({ href:"/general-intelligence/", label:"General Intelligence", kind:"gi", active:true, block:true })} setMenuOpen(false)} style={{ display:"flex", justifyContent:"center", width:"100%", boxSizing:"border-box", fontSize:16, fontWeight:700, color:"#0A1426", background:"var(--minerva-gold)", fontFamily:"var(--wix-text)", padding:"14px 18px", borderRadius:"var(--radius-md)", marginTop:4, boxShadow:"0 2px 10px rgba(224,162,48,0.30)" }}>Start a Diagnostic
General Intelligence {NAV_LINKS.map(({ id, label, href }) => ( setMenuOpen(false)} style={{ fontFamily:"var(--wix-text)", fontSize:17, fontWeight: page===id ? 700 : 500, color: page===id ? "#fff" : "rgba(231,239,250,0.72)", padding:"12px 0", borderBottom:"1px solid rgba(255,255,255,0.06)" }}>{label} ))}
); } /* Button */ function Btn({ children, href="#", variant="primary", accent, textColor, shadow, xstyle={} }) { const base = { display:"inline-flex", alignItems:"center", gap:8, fontSize:17, fontFamily:"var(--wix-text)", fontWeight:700, padding:"12px 22px", borderRadius:"var(--radius-md)", letterSpacing:"-0.01em", cursor:"pointer", ...xstyle }; return variant==="primary" ? {children} : {children}; } /* Baroque ring-dot ornament - echoes Mingi's ring motifs (Arturo's approved A/B/C type system) */ function EyebrowMark({ color, flip=false }) { return ( ); } /* Art-nouveau wavy vine-scroll divider - sits beneath display headlines */ function HeadlineDivider({ color="var(--minerva-gold)", style={} }) { return ( ); } /* Eyebrow label */ function Eyebrow({ children, color="var(--minerva-gold)", center=false }) { return (
{children} {center && }
); } /* Inline Lucide-style icon set */ const ICONS = { users: [,,,], scale: [,,,,], 'alert-circle':[,,], eye: [,], 'layout-grid':[,,,], database: [,,], 'shield-check':[,], zap: [], package: [,,,], 'message-circle':[], layers: [,,], 'git-merge': [,,], 'book-open': [,], 'check-circle':[,], 'badge': [,], 'clipboard-check':[,,], activity: [], network: [,,,,], }; function Icon({ name, size=24, color="currentColor", strokeWidth=1.8 }) { const paths = ICONS[name]; if (!paths) return null; return ( {paths} ); } /* Arrow icon */ function Arrow() { return ( ); } /* Medical circuit motif - life sciences visual language. Gold rounded traces · IV drip bags · capsule pills · dot grid clusters. */ function CircuitSVG({ color="var(--minerva-gold)", opacity=0.40, style:ext={} }) { const c = color; const o = opacity; const sw = 1.3; return ( {[12,22,32,42].flatMap(x=>[28,38,48,58,68].map(y=>()))} {[540,550,560].flatMap(x=>[220,230,240,250].map(y=>()))} ); } /* Decorative side-border ornament - line-art in the Dark Minerva "blue version" vocabulary: crown rings, inward chevrons, rotated-square diamonds, tendril curls. Stroke-only in sky-blue (no gold), muted, tiles seamlessly down any height via an SVG pattern. Top/bottom mask-fade; sits behind content (z:0). */ function VineBorder({ side = "left", opacity = 0.5, color = "var(--minerva-sky)", mask }) { const m = mask || "linear-gradient(to bottom, transparent 0%, #000 14%, #000 86%, transparent 100%)"; const pid = `vb-${side}`; return ( ); } /* Inner-page hero splash - 55vh min, matches main hero energy */ function PageHero({ eyebrow, title, body, accent="var(--minerva-sky)", eyebrowColor, rightSlot, circuit=true, bgImage, ghost, minHeight="55vh", pad="96px 0 80px", align="center" }) { const ghostWord = ghost !== undefined ? ghost : (title ? title.split(' ').slice(0,3).join(' ') : ''); return (
{bgImage && }
{ghostWord}
{eyebrow}

{title}

{body &&

{body}

}
{rightSlot &&
{rightSlot}
}
); } /* Compact footer glossary - reachable from every page */ const GLOSSARY = [ ["VISDI", "Visual-Digital Knowledge - the architecture everything else is built on"], ["Mingi", "Minerva General Intelligence - the result of compliant integration between humans and AI"], ["The Ledger", "Auditable, append-only governance & comms layer - nothing ever overwritten"], ["CLV", "Context Language Validation - the context-layer counterpart to CSV"], ["Knowledge Execution","The category - the compliant AI-ready knowledge layer"], ["Trust gate", "Human verification checkpoint - nothing becomes knowledge without it"], ["knowledge packet", "The atomic unit - small, self-contained, machine-legible"], ["GxP", "The regulated standard in life sciences"], ]; /* Site footer */ function SiteFooter() { const dim="rgba(231,239,250,0.55)"; const cols = [ { label:"VISDI", links:[["The Method","visdi-method.html"],["Products","visdi-products.html"],["Mingi","visdi-mingi.html"],["Who It's For","visdi-products.html"],["Why General Intelligence","general-intelligence.html"]] }, { label:"Products", links:[["VISDI Diagnose","visdi-know.html"],["VISDI Connect","visdi-connect.html"],["VISDI Operate","visdi-operate.html"],["Start a Diagnostic","/knowledge-governance/Start%20Diagnostic.html"]] }, { label:"Minerva", links:[["Services ↗","https://minervakrm.com"],["Quality Systems","https://minervakrm.com"],["Investigations","https://minervakrm.com"],["Visualizations","https://minervakrm.com"]] }, ]; return ( ); } Object.assign(window, { WheelMark, NavBar, Btn, Eyebrow, EyebrowMark, HeadlineDivider, Arrow, Icon, CircuitSVG, VineBorder, PageHero, SiteFooter, STAGE, WORDMARK, MARK_SRC, VISDI_ICON }); /* ── Scroll-triggered animations - injected once, active on all pages ── IMPORTANT: this preview engine has a bug where a dynamically-injected attribute-selector CSS rule (e.g. [data-animate]{opacity:0}) wrongly beats an element's own inline style on React-rendered nodes - so a CSS hidden base state can leave content stuck invisible. We therefore use NO opacity CSS at all: the hidden state and the reveal are BOTH set as inline styles (which behave correctly), and a MutationObserver hides nodes the instant React inserts them so there is no first-paint flash. */ (function initAnim() { if (window.__vaInit) return; window.__vaInit = true; const SEL = '[data-animate],[data-stagger]'; const EASE = 'cubic-bezier(.2,.8,.2,1)'; const reduce = matchMedia('(prefers-reduced-motion:reduce)').matches; const targets = el => el.hasAttribute('data-stagger') ? [...el.children] : [el]; const prep = el => { if (el.__vaPrepped) return; el.__vaPrepped = true; if (reduce) return; // reduced motion → never hide const dur = el.hasAttribute('data-stagger') ? '.6s' : '.7s'; targets(el).forEach((t, i) => { t.style.transition = `opacity ${dur} ${EASE}`; if (el.hasAttribute('data-stagger')) t.style.transitionDelay = (i * 0.1) + 's'; t.style.opacity = '0'; }); }; const show = el => targets(el).forEach(t => { if (t.style.opacity !== '1') t.style.opacity = '1'; }); const inView = el => { const r = el.getBoundingClientRect(); const h = window.innerHeight || document.documentElement.clientHeight; return r.top < h * 0.92 && r.bottom > 0; }; const scan = () => document.querySelectorAll(SEL).forEach(el => { prep(el); if (reduce || inView(el)) show(el); }); /* Hide tagged nodes the moment React inserts them (kills first-paint flash). */ const mo = new MutationObserver(scan); const startMO = () => mo.observe(document.getElementById('root') || document.body, { childList: true, subtree: true }); startMO(); /* Poll ~5s to cover React's async render + reveal whatever is in view; the scroll/resize listeners then reveal everything below the fold, forever. */ let tries = 0; (function tick() { scan(); if (++tries < 50) setTimeout(tick, 100); })(); addEventListener('scroll', scan, { passive: true }); addEventListener('resize', scan, { passive: true }); /* Hard fallback - never leave content stuck invisible. */ setTimeout(() => document.querySelectorAll(SEL).forEach(show), 6000); })();