2025-08-27 13:34:10 +08:00

428 lines
28 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="scroll-smooth">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>A1 — Product Resources · Leitan GPS</title>
<meta name="description" content="Model A1 resources: brief intro, key specifications, manuals & documents, software & firmware, knowledge base articles, and videos." />
<meta name="theme-color" content="#0ea5e9" />
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='46' fill='%230ea5e9'/%3E%3Cpath d='M50 20a30 30 0 1030 30A30 30 0 0050 20zm0 10a20 20 0 11-20 20A20 20 0 0150 30z' fill='white'/%3E%3C/svg%3E" />
<!-- Tailwind v4 Play CDN -->
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script type="tailwind-config">
export default {
darkMode: 'class',
theme: {
extend: {
colors: {
brand: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a'
}
},
boxShadow: { soft: '0 10px 30px rgba(0,0,0,0.06)' }
}
}
}
</script>
<style>
html { scroll-behavior: smooth; }
::selection { background: #bfdbfe; }
</style>
</head>
<body class="bg-white text-gray-800 antialiased dark:bg-gray-950 dark:text-gray-100">
<!-- Decorative BG -->
<div aria-hidden="true" class="pointer-events-none fixed inset-0 -z-10 overflow-hidden">
<div class="absolute -top-32 left-1/2 h-80 w-[1100px] -translate-x-1/2 rounded-full bg-gradient-to-r from-brand-400/30 via-sky-400/20 to-cyan-400/30 blur-3xl dark:from-brand-600/30 dark:via-sky-600/20 dark:to-cyan-600/30"></div>
</div>
<!-- Header -->
<header id="top" class="sticky top-0 z-50 backdrop-blur supports-[backdrop-filter]:bg-white/60 bg-white/80 border-b border-gray-200/70 dark:bg-gray-950/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex h-16 items-center justify-between">
<a href="/index.html" class="flex items-center gap-2">
<span class="inline-flex h-8 w-8 items-center justify-center rounded-lg bg-brand-600 text-white shadow-soft">L</span>
<span class="font-semibold">Leitan GPS</span>
</a>
<nav class="hidden md:flex items-center gap-8 text-sm">
<a href="/index.html#support" class="hover:text-brand-600 dark:hover:text-brand-400">Support</a>
<a href="/index.html#catalog" class="hover:text-brand-600 dark:hover:text-brand-400">Catalog</a>
<span class="h-5 w-px bg-gray-300/60 dark:bg-gray-700"></span>
<a href="/employee/index.html" class="hover:text-brand-600 dark:hover:text-brand-400">Employee</a>
<span class="h-5 w-px bg-gray-300/60 dark:bg-gray-700"></span>
<!-- Language (no real switch yet) -->
<div class="flex items-center gap-3" role="group" aria-label="Language">
<button type="button" class="text-xs px-2 py-1 rounded border border-gray-300/80 hover:border-brand-500 hover:text-brand-600 dark:border-gray-700 dark:hover:border-brand-500" title="Italiano (not implemented)">IT</button>
<button type="button" class="text-xs px-2 py-1 rounded border border-brand-500 text-brand-700 dark:text-brand-300" aria-pressed="true" title="English">EN</button>
</div>
</nav>
<div class="flex items-center gap-3">
<button id="themeToggle" aria-label="Toggle theme" class="inline-flex h-9 w-9 items-center justify-center rounded-lg border border-gray-300 bg-white shadow-sm hover:border-brand-500 dark:bg-gray-900 dark:border-gray-700">
<svg id="iconSun" class="h-5 w-5 hidden" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2m0 14v2m9-9h-2M5 12H3m15.364-6.364l-1.414 1.414M7.05 16.95l-1.414 1.414m0-11.314l1.414 1.414M16.95 16.95l1.414 1.414"/><circle cx="12" cy="12" r="4"/></svg>
<svg id="iconMoon" class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
</button>
</div>
</div>
</div>
</header>
<!-- Breadcrumb & Context -->
<div class="bg-gray-50/70 dark:bg-gray-900/30 border-b border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-3 text-sm text-gray-600 dark:text-gray-300">
<nav class="flex items-center gap-2" aria-label="Breadcrumb">
<a href="/index.html" class="hover:underline">Home</a>
<span>/</span>
<a href="/index.html#support" class="hover:underline">Support</a>
<span>/</span>
<span id="crumbModel" class="font-medium">A1</span>
<span class="ml-auto inline-flex items-center gap-2"><span id="empState" class="rounded-full border border-gray-300 px-2 py-0.5 text-[11px] text-gray-600 dark:border-gray-700 dark:text-gray-300">Mode: Visitor</span></span>
</nav>
</div>
</div>
<!-- Hero: Product summary -->
<section class="relative">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="grid lg:grid-cols-[1.1fr_0.9fr] gap-10 py-10 lg:py-14 items-center">
<div>
<h1 class="text-3xl sm:text-4xl font-bold tracking-tight"><span id="modelName">A1</span> — MultiGNSS Positioning Unit</h1>
<div class="mt-2 flex flex-wrap items-center gap-2 text-sm">
<span class="inline-flex items-center gap-1 rounded-full bg-brand-50 px-2.5 py-1 text-brand-700 dark:bg-brand-900/30 dark:text-brand-300">Positioning unit</span>
<span class="inline-flex items-center gap-1 rounded-full bg-gray-100 px-2.5 py-1 text-gray-700 dark:bg-gray-800 dark:text-gray-300">CE</span>
<span class="inline-flex items-center gap-1 rounded-full bg-gray-100 px-2.5 py-1 text-gray-700 dark:bg-gray-800 dark:text-gray-300">RoHS</span>
</div>
<p class="mt-4 text-gray-600 dark:text-gray-300 max-w-2xl">A rugged, multifrequency GNSS receiver for construction machinery. Millimetrelevel positioning with CAN/RS485 interfaces, designed for dusty, highvibration environments.</p>
<!-- Quick specs badges -->
<dl class="mt-6 grid gap-3 sm:grid-cols-3 text-sm">
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Accuracy</dt><dd class="font-medium">RTK cmlevel</dd></div>
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Interfaces</dt><dd class="font-medium">CAN / RS485</dd></div>
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Ingress</dt><dd class="font-medium">IP67</dd></div>
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Power</dt><dd class="font-medium">936 V DC</dd></div>
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Constellations</dt><dd class="font-medium">GPS/GLONASS/Galileo/BeiDou</dd></div>
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Update rate</dt><dd class="font-medium">Up to 20 Hz</dd></div>
</dl>
<!-- CTAs -->
<div class="mt-6 flex flex-wrap gap-3">
<a href="#documents" class="inline-flex items-center justify-center rounded-xl bg-brand-600 px-5 py-3 text-white shadow-soft hover:bg-brand-700 focus:outline-none focus:ring-2 focus:ring-brand-500">Manuals</a>
<a href="#software" class="inline-flex items-center justify-center rounded-xl border border-gray-300 bg-white px-5 py-3 text-gray-900 shadow-sm hover:border-brand-500 dark:bg-gray-900 dark:text-gray-100 dark:border-gray-700">Software / Firmware</a>
</div>
</div>
<div class="relative">
<div class="relative rounded-2xl border border-gray-200 bg-white p-3 shadow-soft dark:bg-gray-900 dark:border-gray-800">
<div class="aspect-video w-full overflow-hidden rounded-xl bg-gray-100 dark:bg-gray-800">
<img src="https://images.pexels.com/photos/280140/pexels-photo-280140.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=1600" alt="Construction cranes — Pexels" class="h-full w-full object-cover"/>
</div>
<div class="mt-3 flex items-center justify-between">
<div class="text-sm text-gray-600 dark:text-gray-300">Field install preview</div>
<a href="https://www.pexels.com/video/time-lapse-video-of-an-excavator-5342014/" target="_blank" rel="noopener" class="inline-flex items-center gap-1 rounded-lg px-3 py-1.5 text-sm border border-gray-300 hover:border-brand-500 dark:border-gray-700">
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.26a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/></svg>
Watch on Pexels
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Specs table -->
<section id="specs" class="py-6">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<h2 class="text-xl sm:text-2xl font-semibold">Technical specifications</h2>
<div class="mt-4 grid gap-6 lg:grid-cols-2">
<div class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800">
<dl class="grid grid-cols-[160px_1fr] gap-x-6 gap-y-3 text-sm">
<dt class="text-gray-500">Positioning</dt><dd>RTK, SBAS, PPP (option)</dd>
<dt class="text-gray-500">Update rate</dt><dd>1/5/10/20 Hz</dd>
<dt class="text-gray-500">Latency</dt><dd>< 20 ms</dd>
<dt class="text-gray-500">Interfaces</dt><dd>CAN 2.0B, RS485, UART, Ethernet (option)</dd>
<dt class="text-gray-500">I/O</dt><dd>2× DI, 1× DO, 1× PPS</dd>
<dt class="text-gray-500">Power</dt><dd>936 V DC, < 5 W</dd>
<dt class="text-gray-500">Ingress</dt><dd>IP67, MILSTD810 vibration</dd>
<dt class="text-gray-500">Operating temp</dt><dd>30…+70 ℃</dd>
</dl>
</div>
<div class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800">
<dl class="grid grid-cols-[160px_1fr] gap-x-6 gap-y-3 text-sm">
<dt class="text-gray-500">Antenna</dt><dd>External, 3.35 V bias</dd>
<dt class="text-gray-500">Mounting</dt><dd>DIN rail / plate</dd>
<dt class="text-gray-500">Dimensions</dt><dd>120×90×45 mm</dd>
<dt class="text-gray-500">Weight</dt><dd>450 g</dd>
<dt class="text-gray-500">Certifications</dt><dd>CE, RoHS</dd>
<dt class="text-gray-500">SKU</dt><dd>A1EUBASE</dd>
<dt class="text-gray-500">Compatibility</dt><dd>AX5 antenna, IMUPRO</dd>
</dl>
</div>
</div>
</div>
</section>
<!-- Divider & Local nav -->
<div class="border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<nav class="flex flex-wrap gap-4 py-4 text-sm">
<a href="#documents" class="rounded-lg border border-gray-300 px-3 py-1.5 hover:border-brand-500 dark:border-gray-700">Documents</a>
<a href="#software" class="rounded-lg border border-gray-300 px-3 py-1.5 hover:border-brand-500 dark:border-gray-700">Software & firmware</a>
<a href="#kb" class="rounded-lg border border-gray-300 px-3 py-1.5 hover:border-brand-500 dark:border-gray-700">Knowledge base</a>
<a href="#videos" class="rounded-lg border border-gray-300 px-3 py-1.5 hover:border-brand-500 dark:border-gray-700">Videos</a>
</nav>
</div>
</div>
<!-- Documents -->
<section id="documents" class="py-10">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex items-end justify-between gap-4">
<div>
<h2 class="text-xl sm:text-2xl font-semibold">Manuals & documents</h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">Searchable by language and version. Internal items are marked and require employee access.</p>
</div>
<div class="flex items-center gap-2 text-sm">
<select id="docLang" class="rounded-lg border border-gray-300 bg-white px-2.5 py-1.5 dark:bg-gray-950 dark:border-gray-800"><option value="">All languages</option><option value="en">English</option><option value="zh">中文</option><option value="it">Italiano</option></select>
<select id="docVer" class="rounded-lg border border-gray-300 bg-white px-2.5 py-1.5 dark:bg-gray-950 dark:border-gray-800"><option value="">Latest & history</option><option value="latest">Latest only</option></select>
</div>
</div>
<div id="docList" class="mt-6 grid gap-4"></div>
</div>
</section>
<!-- Software / Firmware -->
<section id="software" class="py-10 border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex items-end justify-between gap-4">
<div>
<h2 class="text-xl sm:text-2xl font-semibold">Software & firmware</h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">Platform filters and compatibility hints. Firmware downloads may require confirmation.</p>
</div>
<div class="flex items-center gap-2 text-sm">
<select id="swPlatform" class="rounded-lg border border-gray-300 bg-white px-2.5 py-1.5 dark:bg-gray-950 dark:border-gray-800"><option value="">All platforms</option><option value="win">Windows</option><option value="mac">macOS</option><option value="linux">Linux</option><option value="all">All</option></select>
</div>
</div>
<div id="swList" class="mt-6 grid gap-4"></div>
</div>
</section>
<!-- Knowledge base -->
<section id="kb" class="py-10 border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<h2 class="text-xl sm:text-2xl font-semibold">Knowledge base</h2>
<div id="kbList" class="mt-6 grid gap-4 lg:grid-cols-2"></div>
</div>
</section>
<!-- Videos -->
<section id="videos" class="py-10 border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex items-end justify-between gap-4">
<h2 class="text-xl sm:text-2xl font-semibold">Videos</h2>
<div class="text-xs text-gray-500">Demo player — replace with HLS in production</div>
</div>
<div id="videoList" class="mt-6 grid gap-6 lg:grid-cols-2"></div>
</div>
</section>
<!-- Footer -->
<footer class="mt-12 border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-10">
<div class="grid gap-8 sm:grid-cols-2 lg:grid-cols-4">
<div>
<div class="flex items-center gap-2">
<span class="inline-flex h-8 w-8 items-center justify-center rounded-lg bg-brand-600 text-white shadow-soft">L</span>
<span class="font-semibold">Leitan GPS</span>
</div>
<p class="mt-3 text-sm text-gray-600 dark:text-gray-300">This is a static prototype page for product resources.</p>
</div>
<div>
<div class="font-semibold">Product</div>
<ul class="mt-3 space-y-2 text-sm text-gray-600 dark:text-gray-300">
<li><a href="/index.html#support" class="hover:underline">Support & downloads</a></li>
<li><a href="/index.html#catalog" class="hover:underline">Catalog</a></li>
</ul>
</div>
<div>
<div class="font-semibold">Compliance</div>
<ul class="mt-3 space-y-2 text-sm text-gray-600 dark:text-gray-300">
<li><a href="#" class="hover:underline">Privacy policy</a></li>
<li><a href="#" class="hover:underline">Cookie preferences</a></li>
</ul>
</div>
<div>
<div class="font-semibold">Support</div>
<ul class="mt-3 space-y-2 text-sm text-gray-600 dark:text-gray-300">
<li>support@example.com</li>
<li>MonFri, 09:0018:00</li>
<li>Italy / Singapore</li>
</ul>
</div>
</div>
<div class="mt-8 flex flex-col sm:flex-row items-center justify-between gap-4 text-xs text-gray-500">
<div>© 2025 Leitan Tech. All rights reserved.</div>
<a href="#top" class="inline-flex items-center gap-1 hover:text-brand-600 dark:hover:text-brand-400">Back to top <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M5 15l7-7 7 7"/></svg></a>
</div>
</div>
</footer>
<!-- Scripts -->
<script>
// Theme init
(function() {
const stored = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (stored === 'dark' || (!stored && prefersDark)) document.documentElement.classList.add('dark');
})();
const themeBtn = document.getElementById('themeToggle');
const sun = document.getElementById('iconSun');
const moon = document.getElementById('iconMoon');
function syncIcons(){ const d=document.documentElement.classList.contains('dark'); sun?.classList.toggle('hidden',!d); moon?.classList.toggle('hidden',d); }
themeBtn?.addEventListener('click',()=>{ document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark')?'dark':'light'); syncIcons(); });
syncIcons();
// Parse query and employee mode
const params = new URLSearchParams(location.search);
const q = params.get('q') || '';
const modelParam = params.get('model') || '';
const isEmp = !!localStorage.getItem('employee');
document.getElementById('empState').textContent = 'Mode: ' + (isEmp ? 'Employee' : 'Visitor');
// Demo mapping: if serial like SN-A1-… -> A1
function resolveModel(input){
if (!input) return 'A1';
const s = input.toUpperCase();
if (s.startsWith('SN-A1')) return 'A1';
if (['A1','A1-PRO'].includes(s)) return 'A1';
return 'A1';
}
const model = modelParam || resolveModel(q);
document.getElementById('crumbModel').textContent = model;
document.getElementById('modelName').textContent = model;
// Demo data (normally fetched from /data/*.json)
const DOCS = [
{ id:'doc-001', productId:'A1', title:'A1 Wiring & Installation', type:'manual', version:'v1.8', lang:'en', size:'2.3MB', updatedAt:'2025-07-08', checksum:'SHA256-…d9c', url:'#', visibility:'public' },
{ id:'doc-002', productId:'A1', title:'A1 Service Manual', type:'service', version:'v1.7', lang:'en', size:'4.7MB', updatedAt:'2025-07-22', checksum:'SHA256-…9ab', url:'#', visibility:'internal' },
{ id:'doc-003', productId:'A1', title:'Declaration of Conformity (DoC)', type:'certificate', version:'2025', lang:'en', size:'0.6MB', updatedAt:'2025-06-02', checksum:'SHA256-…123', url:'#', visibility:'public' }
];
const SW = [
{ id:'sw-101', productId:'A1', title:'A1 Config Tool', kind:'software', version:'v2.2.0', platform:'win', size:'18.4MB', updatedAt:'2025-06-20', checksum:'SHA256-…6a5', notesUrl:'#', compat:'A1 hw v2.x+', url:'#', visibility:'public', risk:false },
{ id:'sw-102', productId:'A1', title:'A1 Firmware', kind:'firmware', version:'v2.3.1', platform:'all', size:'21.0MB', updatedAt:'2025-08-02', checksum:'MD5-…1c3', notesUrl:'#', compat:'A1 hw v2.x+', url:'#', visibility:'internal', risk:true }
];
const KB = [
{ id:'kb-301', productId:'A1', title:'Position drift under vibration — checklist', summary:'Mounting, antenna grounding, EMI, power ripple limits, and field photos…', tags:['Troubleshooting','Installation'], url:'#', visibility:'internal' },
{ id:'kb-302', productId:'A1', title:'Quick start — first fix in 60s', summary:'A minimal path to first RTK fix with recommended antenna placement.', tags:['Quickstart'], url:'#', visibility:'public' }
];
const VIDS = [
{ id:'vid-501', productId:'A1', title:'A1 quick install (2:13)', duration:'02:13', poster:'https://images.pexels.com/photos/14452156/pexels-photo-14452156.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=1600', sources:[{src:'/media/a1-install-720.mp4',label:'720p'},{src:'/media/a1-install-1080.mp4',label:'1080p'}], visibility:'public' },
{ id:'vid-502', productId:'A1', title:'Internal: wiring pitfalls (3:40)', duration:'03:40', poster:'https://images.pexels.com/photos/159306/pexels-photo-159306.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=1600', sources:[{src:'/media/a1-internal-720.mp4',label:'720p'}], visibility:'internal' }
];
// Render helpers
function badgeInternal(v){ return v==='internal' ? '<span class="inline-flex items-center gap-1 rounded bg-gray-100 px-2 py-1 text-[11px] text-gray-600 dark:bg-gray-800 dark:text-gray-300">\uD83D\uDD12 Internal</span>' : ''; }
function lockIfNoAccess(v){ return v==='internal' && !isEmp ? 'opacity-40 pointer-events-none' : ''; }
function renderDocs(){
const lang = document.getElementById('docLang').value;
const latestOnly = document.getElementById('docVer').value==='latest';
let items = DOCS.filter(d=>d.productId===model && (!lang || d.lang===lang));
if (latestOnly){
const byType = {};
for (const d of items){ if (!byType[d.type] || new Date(d.updatedAt) > new Date(byType[d.type].updatedAt)) byType[d.type] = d; }
items = Object.values(byType);
}
document.getElementById('docList').innerHTML = items.map(d=>`
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-4 rounded-2xl border border-gray-200 bg-white p-4 shadow-soft dark:bg-gray-900 dark:border-gray-800 ${lockIfNoAccess(d.visibility)}">
<div class="flex min-w-0 flex-1 items-center gap-4">
<div class="flex h-12 w-12 items-center justify-center rounded-xl bg-brand-50 text-brand-700 dark:bg-brand-900/30 dark:text-brand-300">
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6m0 0l-3-3m3 3l3-3M4 18h16"/></svg>
</div>
<div class="min-w-0">
<div class="font-medium truncate">${d.title} (${d.version.toUpperCase()} · ${d.lang.toUpperCase()})</div>
<div class="text-xs text-gray-500">${d.type} · ${d.size} · Updated: ${d.updatedAt} · ${d.checksum}</div>
</div>
</div>
<div class="flex shrink-0 items-center gap-3">
${badgeInternal(d.visibility)}
<a href="${d.url}" class="inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700">Download</a>
<button class="inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700" onclick="alert('Version history — demo');">Version history</button>
</div>
</div>`).join('');
}
function renderSW(){
const plat = document.getElementById('swPlatform').value;
const items = SW.filter(s=>s.productId===model && (!plat || s.platform===plat || s.platform==='all'));
document.getElementById('swList').innerHTML = items.map(s=>`
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-4 rounded-2xl border border-gray-200 bg-white p-4 shadow-soft dark:bg-gray-900 dark:border-gray-800 ${lockIfNoAccess(s.visibility)}">
<div class="flex min-w-0 flex-1 items-center gap-4">
<div class="flex h-12 w-12 items-center justify-center rounded-xl ${s.kind==='firmware'?'bg-amber-50 text-amber-700 dark:bg-amber-900/20 dark:text-amber-300':'bg-brand-50 text-brand-700 dark:bg-brand-900/30 dark:text-brand-300'}">
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M4 4h16v12H4z"/><path stroke-linecap="round" stroke-linejoin="round" d="M4 20h16"/></svg>
</div>
<div class="min-w-0">
<div class="font-medium truncate">${s.title} (${s.version}) — ${s.kind}</div>
<div class="text-xs text-gray-500">${s.platform.toUpperCase()} · ${s.size} · Updated: ${s.updatedAt} · ${s.checksum} · Compat: ${s.compat}</div>
</div>
</div>
<div class="flex shrink-0 items-center gap-3">
${badgeInternal(s.visibility)}
<a href="${s.notesUrl}" class="inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700">Release notes</a>
<button class="inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700" onclick="${s.kind==='firmware'?'confirmFirmware()':'void 0'};">Download</button>
</div>
</div>`).join('');
}
function renderKB(){
const items = KB.filter(k=>k.productId===model);
document.getElementById('kbList').innerHTML = items.map(k=>`
<article class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800 ${lockIfNoAccess(k.visibility)}">
<div class="text-xs text-gray-500">${k.tags.join(' · ')}</div>
<h3 class="mt-1 font-semibold">${k.title}</h3>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">${k.summary}</p>
<div class="mt-3 flex items-center gap-3">
${badgeInternal(k.visibility)}
<a href="${k.url}" class="inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700">View</a>
</div>
</article>`).join('');
}
function renderVideos(){
const items = VIDS.filter(v=>v.productId===model);
document.getElementById('videoList').innerHTML = items.map(v=>`
<div class="rounded-2xl border border-gray-200 bg-white p-3 shadow-soft dark:bg-gray-900 dark:border-gray-800 ${lockIfNoAccess(v.visibility)}">
<div class="aspect-video w-full overflow-hidden rounded-xl bg-gray-100 dark:bg-gray-800">
<video controls preload="metadata" poster="${v.poster}" class="h-full w-full">
${v.sources.map(s=>`<source src="${s.src}" type="video/mp4" />`).join('')}
</video>
</div>
<div class="mt-3 flex items-center justify-between">
<div class="text-sm text-gray-600 dark:text-gray-300">${v.title}</div>
${badgeInternal(v.visibility)}
</div>
</div>`).join('');
}
function confirmFirmware(){
const ok = confirm('Firmware download — confirm you have read compatibility and rollback instructions.');
if (!ok) return; alert('Download started (demo)');
}
document.getElementById('docLang').addEventListener('change', renderDocs);
document.getElementById('docVer').addEventListener('change', renderDocs);
document.getElementById('swPlatform').addEventListener('change', renderSW);
// initial render
renderDocs(); renderSW(); renderKB(); renderVideos();
</script>
</body>
</html>