/* app-sections-top.jsx — Nav, faux Jira product window, Hero, Trust, Pillars */ const { useState, useEffect, useRef } = React; const TINT = { P: ['var(--P-surface)', 'var(--P-text)'], B: ['var(--B50)', '#0747A6'], R: ['var(--R-surface)', 'var(--R-text)'], T: ['var(--T-surface)', 'var(--T-text)'], G: ['var(--G-surface)', 'var(--G-text)'], Y: ['var(--Y-surface)', '#8a6d00'] }; function Ico({ name, ...rest }) { const C = window.Icons[name]; return C ? : null; } /* ---------------- NAV ---------------- */ function Nav({ darkHero, onDemo }) { const [scrolled, setScrolled] = useState(false); useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 24); onScroll(); window.addEventListener('scroll', onScroll, { passive: true }); return () => window.removeEventListener('scroll', onScroll); }, []); const onDark = darkHero && !scrolled; const logo = asset(onDark ? 'assets/qity-logo-dark.png' : 'assets/qity-logo-light.png'); return (
Qity
); } /* ---------------- FAUX JIRA WINDOW ---------------- */ function Donut({ pct, color }) { return (
{pct}%
); } function JiraWindow() { const nav = [ { icon: 'FileCheck', label: 'Document Control', active: true }, { icon: 'Ruler', label: 'Design Control' }, { icon: 'AlertTriangle', label: 'Risk Management' }, { icon: 'ClipboardCheck', label: 'Audit Management' }, { icon: 'Cap', label: 'Training' }]; return (
{Array.from({ length: 9 }).map((_, i) => )}
Qity
Search quality records
My quality dashboard
Wednesday, 19 Jun 2025 · Evidence is up to date
DC-123, DC-125 and 2 others are waiting for your review. Review now
Document Control
8 documents pending your approval
55 in a long review cycle
Use-related risks
3 risks need mitigation
24 controlled this quarter
Design Control — traceability
WI-231Firmware OTA update requirementReleased
DOC-55Risk control verification reportQA approval
CC-15Change request — sensor calibrationDoc approval
); } /* ---------------- PRODUCT SCREENSHOT (real app) ---------------- */ function ProductShot({ src, alt }) { return (
{alt}
); } /* ---------------- HERO ---------------- */ function Hero({ tweaks, onDemo }) { const layout = tweaks.heroLayout; // 'right' | 'below' const motion = 'tilt'; // settled hero scroll motion const visualRef = useRef(null); useEffect(() => { const wrap = visualRef.current;if (!wrap) return; const win = wrap.querySelector('.window');if (!win) return; const cards = [ { el: wrap.querySelector('.float-bl'), at: 0.07 }, { el: wrap.querySelector('.float-tr'), at: 0.18 }]; if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { cards.forEach((c) => c.el && c.el.classList.add('popped')); return; } let raf = 0; let baseTop = null; const upd = () => { raf = 0; const r = wrap.getBoundingClientRect(); const vh = window.innerHeight || 800; const prog = Math.max(0, Math.min(1.2, (vh - r.top) / (vh * 0.85))); const p1 = Math.min(prog, 1); if (motion === 'tilt') { // leaning forward at the top, standing flat as you scroll down win.style.setProperty('--win-origin', 'bottom center'); win.style.setProperty('--win-tiltX', (Math.max(0, 1 - prog) * 26).toFixed(2) + 'deg'); win.style.setProperty('--win-lift', (-((prog - 0.5) * 14)).toFixed(1) + 'px'); win.style.setProperty('--win-scale', (0.95 + p1 * 0.05).toFixed(3)); } else if (motion === 'rise') { // rises up from below and scales into place win.style.setProperty('--win-origin', 'center center'); win.style.setProperty('--win-tiltX', '0deg'); win.style.setProperty('--win-lift', ((1 - p1) * 70 - 10).toFixed(1) + 'px'); win.style.setProperty('--win-scale', (0.9 + p1 * 0.1).toFixed(3)); } else { // lift (default): subtle settle win.style.setProperty('--win-origin', 'center center'); win.style.setProperty('--win-tiltX', (Math.max(0, 1 - prog) * 5).toFixed(2) + 'deg'); win.style.setProperty('--win-lift', (-((prog - 0.4) * 34)).toFixed(1) + 'px'); win.style.setProperty('--win-scale', (0.965 + p1 * 0.035).toFixed(3)); } if (baseTop === null) baseTop = r.top; const scrolled = baseTop - r.top; // how far the hero has scrolled up from its initial spot cards.forEach((c) => c.el && c.el.classList.toggle('popped', scrolled > vh * c.at)); }; const onScroll = () => {if (!raf) raf = requestAnimationFrame(upd);}; upd(); window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll); return () => {window.removeEventListener('scroll', onScroll);window.removeEventListener('resize', onScroll);cancelAnimationFrame(raf);}; }, [layout, tweaks.heroSpot, motion]); return (
Qity

Quality built-in, not bolted on.

Qity's apps for Jira & Confluence turn your team’s everyday work into compliance evidence and documentation. Integrated with the tools you already use, built for regulated industries.

See how it works
Coming soon to Atlassian Marketplace
Document Review Agent
DC-332 Design & Development SOP reviewed against ISO 13485 clauses
CI/CD pipeline
Release build #1284 passed — detailed design and test descriptions updated in Jira
); } /* ---------------- TRUST ---------------- */ function Trust() { const logos = [ { name: 'Wyss Zurich', file: 'wyss', h: 26 }, { name: 'FBGS', file: 'fbgs-mark', h: 28 }, { name: 'Trince', file: 'trince', h: 26 }, { name: 'Agricells', file: 'agricells', h: 34 }, { name: 'Mantyx', file: 'mantyx', h: 32 }, { name: 'Samplid', file: 'samplid', h: 28 }, { name: 'Robovision', file: 'robovision', h: 40 }, { name: 'NHa Normandy Hadrontherapy', file: 'nha', h: 32 }]; const trackRef = useRef(null); const [copies, setCopies] = useState(2); const [ready, setReady] = useState(false); useEffect(() => { const track = trackRef.current;if (!track) return; const marquee = track.parentElement;if (!marquee) return; let cancelled = false; const measure = () => { if (cancelled) return; const kids = [...track.children].slice(0, logos.length); if (kids.length < logos.length) return; let setW = 0; kids.forEach((k) => {setW += k.getBoundingClientRect().width + (parseFloat(getComputedStyle(k).marginRight) || 0);}); if (!setW) return; // enough copies that (copies-1) sets always exceed the viewport → never a gap const need = Math.ceil((marquee.clientWidth + setW) / setW) + 1; setCopies((c) => Math.max(2, need) === c ? c : Math.max(2, need)); track.style.setProperty('--set-w', setW + 'px'); track.style.setProperty('--marq-dur', (setW / 40).toFixed(1) + 's'); // ~40px/s setReady(true); }; const imgs = [...track.querySelectorAll('img')]; let pending = imgs.filter((im) => !im.complete).length; const onOne = () => {if (--pending <= 0) measure();}; if (pending === 0) measure();else imgs.forEach((im) => {if (!im.complete) {im.addEventListener('load', onOne);im.addEventListener('error', onOne);}}); const ro = new ResizeObserver(() => measure()); ro.observe(marquee); return () => {cancelled = true;ro.disconnect();}; }, []); const sets = Array.from({ length: copies }, () => logos).flat(); return (

TRUSTED BY

{sets.map((l, i) => {i= logos.length} style={{ height: l.h }} /> )}
); } function ComplianceStrip() { return (

Built for regulated industries

{window.STANDARDS.map((s) => {s.img ? : } {s.label} )}
); } /* ---------------- PILLARS ---------------- */ function PillarIllo({ i }) { const illos = [ // Jira items flowing into a document , // Pipeline of dots + robot producing documentation , // AI icon — sparkle ]; return illos[i % illos.length]; } function Pillars({ tweaks }) { const variant = 'tiles'; // settled on icon tiles const illo = true; // settled on flat illustrations return (

Quality evidence that builds itself

Stop managing your quality in disconnected Word and Excel files. Your documentation gets generated in the system where the work happens, with the help of automation and agentic AI.

{window.PILLARS.map((p, i) =>
{variant === 'rows' && {p.n}} {illo ? : } {variant === 'rows' ? <>

{p.title}

{p.body}

: <>

{p.title}

{p.body}

}
)}
); } Object.assign(window, { Nav, Hero, JiraWindow, ProductShot, Trust, ComplianceStrip, Pillars, Ico, TINT });