diff --git a/.gitignore b/.gitignore
index d9f248e..2a8dc06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,10 @@ client/devtools_options.yaml
# Flutter 构建产物
client/build/
+
+# 营销站构建产物
+web/dist/
+web/node_modules/
client/.dart_tool/
client/.flutter-plugins
client/.flutter-plugins-dependencies
diff --git a/web/.eleventy.js b/web/.eleventy.js
new file mode 100644
index 0000000..9e7f194
--- /dev/null
+++ b/web/.eleventy.js
@@ -0,0 +1,22 @@
+module.exports = function(cfg) {
+ // 静态资源直接复制
+ cfg.addPassthroughCopy("assets");
+
+ // scan.html 面向消费者,独立维护,直接复制不经模板
+ cfg.addPassthroughCopy("scan.html");
+ cfg.addPassthroughCopy("features");
+
+ return {
+ dir: {
+ input: ".",
+ output: "dist",
+ includes: "_includes",
+ data: "_data",
+ layouts: "_includes",
+ },
+ // 同时支持 .html 和 .njk 作为模板格式
+ templateFormats: ["njk", "html", "md"],
+ htmlTemplateEngine: "njk",
+ markdownTemplateEngine: "njk",
+ };
+};
diff --git a/web/.eleventyignore b/web/.eleventyignore
new file mode 100644
index 0000000..9b0e65c
--- /dev/null
+++ b/web/.eleventyignore
@@ -0,0 +1,6 @@
+scan.html
+content/
+features/approval.html
+features/inventory.html
+node_modules
+dist
diff --git a/web/_data/changelog.js b/web/_data/changelog.js
new file mode 100644
index 0000000..8730072
--- /dev/null
+++ b/web/_data/changelog.js
@@ -0,0 +1,44 @@
+const fs = require('fs');
+const path = require('path');
+
+module.exports = function() {
+ const raw = fs.readFileSync(path.join(__dirname, '../../CHANGELOG.md'), 'utf8');
+ const lines = raw.split('\n');
+ const versions = [];
+ let current = null;
+ let currentSection = null;
+
+ for (const line of lines) {
+ const versionMatch = line.match(/^## \[([^\]]+)\] - (\d{4}-\d{2}-\d{2})/);
+ if (versionMatch) {
+ if (current) versions.push(current);
+ if (versions.length >= 3) break;
+ current = { version: versionMatch[1], date: versionMatch[2], sections: [], intro: '' };
+ currentSection = null;
+ continue;
+ }
+
+ const sectionMatch = line.match(/^### (.+)/);
+ if (sectionMatch && current) {
+ currentSection = { type: sectionMatch[1], items: [] };
+ current.sections.push(currentSection);
+ continue;
+ }
+
+ const itemMatch = line.match(/^- (.+)/);
+ if (itemMatch && current) {
+ if (currentSection) {
+ currentSection.items.push(itemMatch[1]);
+ }
+ continue;
+ }
+
+ // Free-form text before first section (e.g. v1.0.0 intro paragraph)
+ if (line.trim() && current && !currentSection && !line.startsWith('#')) {
+ current.intro = current.intro ? current.intro + ' ' + line.trim() : line.trim();
+ }
+ }
+ if (current && versions.length < 3) versions.push(current);
+
+ return versions;
+};
diff --git a/web/_data/docs.js b/web/_data/docs.js
new file mode 100644
index 0000000..7205c58
--- /dev/null
+++ b/web/_data/docs.js
@@ -0,0 +1,51 @@
+const fs = require('fs');
+const path = require('path');
+const md = require('markdown-it')({ html: false, breaks: false, linkify: false });
+
+const TOC_GROUPS = [
+ { group: '快速开始', nums: [1, 2, 3] },
+ { group: '业务操作', nums: [4, 5, 6, 7, 8, 9] },
+ { group: '基础设置', nums: [10, 11, 12] },
+];
+
+module.exports = function() {
+ const raw = fs.readFileSync(path.join(__dirname, '../content/docs.md'), 'utf8');
+ const lines = raw.split('\n');
+
+ // Split into chapters by "## {n}. {title}" headings
+ const chapters = [];
+ let current = null;
+
+ for (const line of lines) {
+ const match = line.match(/^## (\d+)\. (.+)/);
+ if (match) {
+ if (current) chapters.push(current);
+ const num = parseInt(match[1], 10);
+ current = { num, id: 'ch-' + num, title: match[2].trim(), bodyLines: [] };
+ } else if (current) {
+ current.bodyLines.push(line);
+ }
+ }
+ if (current) chapters.push(current);
+
+ // Render each chapter's body to HTML
+ const rendered = chapters.map(ch => ({
+ num: ch.num,
+ id: ch.id,
+ title: ch.title,
+ html: md.render(ch.bodyLines.join('\n')),
+ }));
+
+ // Build TOC
+ const chapterMap = {};
+ rendered.forEach(ch => { chapterMap[ch.num] = ch; });
+
+ const toc = TOC_GROUPS.map(g => ({
+ group: g.group,
+ items: g.nums
+ .filter(n => chapterMap[n])
+ .map(n => ({ id: chapterMap[n].id, num: n, title: chapterMap[n].title })),
+ }));
+
+ return { toc, chapters: rendered };
+};
diff --git a/web/_data/site.json b/web/_data/site.json
new file mode 100644
index 0000000..9da0c12
--- /dev/null
+++ b/web/_data/site.json
@@ -0,0 +1,12 @@
+{
+ "name": "岩美酒库管理系统",
+ "tagline": "为酒行与酒店设计的库存管理平台",
+ "copyright": "© 2026 岩美科技 · 保留所有权利",
+ "icp": "沪 ICP 备 2026000000 号 · 沪公网安备 31010000000000 号",
+ "support": {
+ "email": "support@yanmei.app",
+ "phone": "400-880-8888"
+ },
+ "appUrl": "/app/",
+ "lucideVersion": "0.469.0"
+}
diff --git a/web/_data/sysreq.js b/web/_data/sysreq.js
new file mode 100644
index 0000000..585d869
--- /dev/null
+++ b/web/_data/sysreq.js
@@ -0,0 +1,8 @@
+const fs = require('fs');
+const path = require('path');
+const md = require('markdown-it')({ html: false, breaks: false });
+
+module.exports = function() {
+ const content = fs.readFileSync(path.join(__dirname, '../content/system-requirements.md'), 'utf8');
+ return md.render(content);
+};
diff --git a/web/_includes/base.njk b/web/_includes/base.njk
new file mode 100644
index 0000000..dcb9b47
--- /dev/null
+++ b/web/_includes/base.njk
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+{% if title %}{{ title }} · {% endif %}{{ site.name }}
+{% if description %}{% endif %}
+
+
+{% if pageExtraCss %}{% endif %}
+
+
+
+
+{% if pageStyle %}{% endif %}
+
+
+
+{% include "nav.njk" %}
+
+{{ content | safe }}
+
+{% include "footer.njk" %}
+
+
+
+
diff --git a/web/_includes/footer.njk b/web/_includes/footer.njk
new file mode 100644
index 0000000..7edf189
--- /dev/null
+++ b/web/_includes/footer.njk
@@ -0,0 +1,55 @@
+
diff --git a/web/_includes/nav.njk b/web/_includes/nav.njk
new file mode 100644
index 0000000..5102063
--- /dev/null
+++ b/web/_includes/nav.njk
@@ -0,0 +1,15 @@
+
diff --git a/web/assets/color.css b/web/assets/color.css
new file mode 100644
index 0000000..9574df8
--- /dev/null
+++ b/web/assets/color.css
@@ -0,0 +1,261 @@
+/* =========================================================================
+ 岩美 Design System — Foundations
+ Tokens for color, type, spacing, radius, shadow.
+ Import once at root:
+ ========================================================================= */
+
+:root {
+ color-scheme: light;
+
+ /* ---------- Brand: Primary (Slate Blue) ---------- */
+ /* Trustworthy enterprise blue with a slight slate cast. */
+ --brand-50: #EEF4FB;
+ --brand-100: #D6E5F5;
+ --brand-200: #ADC9EA;
+ --brand-300: #7FA8DA;
+ --brand-400: #4F86C6;
+ --brand-500: #2563AC; /* Primary action */
+ --brand-600: #1B4F8E; /* Hover */
+ --brand-700: #154072; /* Pressed */
+ --brand-800: #0F3057;
+ --brand-900: #0A1F3B; /* Brand ink — headers, logo on light bg */
+
+ /* ---------- Neutrals (cool slate gray) ---------- */
+ --gray-0: #FFFFFF;
+ --gray-25: #FBFCFD;
+ --gray-50: #F5F7FA;
+ --gray-100: #ECEFF4;
+ --gray-200: #DCE2EB;
+ --gray-300: #C2CAD6;
+ --gray-400: #99A3B3;
+ --gray-500: #6E7888;
+ --gray-600: #4F5867;
+ --gray-700: #353C48;
+ --gray-800: #232934;
+ --gray-900: #141821;
+
+ /* ---------- Accent (bordeaux / 酒红) ---------- */
+ /* Used sparingly: brand context cue (wine), key highlights, marketing only. */
+ --accent-50: #FAEEF0;
+ --accent-100: #F1D2D7;
+ --accent-300: #C97B86;
+ --accent-500: #8B2331;
+ --accent-700: #5F1621;
+
+ /* ---------- Semantic ---------- */
+ --success-50: #E8F5EE;
+ --success-500: #2E8B57;
+ --success-700: #1F6B41;
+
+ --warning-50: #FFF4DB;
+ --warning-500: #E08E00;
+ --warning-700: #A66700;
+
+ --danger-50: #FDECEC;
+ --danger-500: #D14343;
+ --danger-700: #9E2A2A;
+
+ --info-50: #E5F1FB;
+ --info-500: #2F7BD0;
+ --info-700: #1F5C9F;
+
+ /* ---------- Semantic foreground / background ---------- */
+ --bg-app: var(--gray-50);
+ --bg-surface: var(--gray-0);
+ --bg-raised: var(--gray-0);
+ --bg-sunken: var(--gray-100);
+ --bg-overlay: rgba(20, 24, 33, 0.45);
+
+ --fg-default: var(--gray-800);
+ --fg-muted: var(--gray-600);
+ --fg-subtle: var(--gray-500);
+ --fg-disabled: var(--gray-400);
+ --fg-on-brand: #FFFFFF;
+ --fg-link: var(--brand-500);
+
+ --border-subtle: var(--gray-100);
+ --border-default: var(--gray-200);
+ --border-strong: var(--gray-300);
+ --border-focus: var(--brand-500);
+
+ /* ---------- Typography ---------- */
+ /* Chinese-primary stack with PingFang on macOS/iOS, Microsoft YaHei on Windows,
+ Noto Sans SC as web fallback (loaded via Google Fonts in index files). */
+ --font-sans: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
+ "Source Han Sans CN", "Noto Sans SC", -apple-system,
+ BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
+ --font-display: var(--font-sans);
+ --font-mono: "JetBrains Mono", "SF Mono", "Roboto Mono", Menlo, Consolas,
+ "Microsoft YaHei", monospace;
+
+ /* Type scale — mobile-first, scales up for desktop dashboards */
+ --text-2xs: 11px;
+ --text-xs: 12px;
+ --text-sm: 13px;
+ --text-md: 14px; /* dashboard body default */
+ --text-lg: 16px;
+ --text-xl: 18px;
+ --text-2xl: 22px;
+ --text-3xl: 28px;
+ --text-4xl: 36px;
+ --text-5xl: 48px;
+
+ --leading-tight: 1.25;
+ --leading-snug: 1.4;
+ --leading-normal: 1.55;
+ --leading-loose: 1.75;
+
+ --weight-regular: 400;
+ --weight-medium: 500;
+ --weight-semibold: 600;
+ --weight-bold: 700;
+
+ /* Tracking — Chinese reads better with subtle positive tracking */
+ --tracking-tight: -0.01em;
+ --tracking-normal: 0;
+ --tracking-wide: 0.02em;
+ --tracking-cn-display: 0.04em; /* Chinese display headers */
+
+ /* ---------- Spacing (4px base) ---------- */
+ --space-0: 0;
+ --space-1: 4px;
+ --space-2: 8px;
+ --space-3: 12px;
+ --space-4: 16px;
+ --space-5: 20px;
+ --space-6: 24px;
+ --space-8: 32px;
+ --space-10: 40px;
+ --space-12: 48px;
+ --space-16: 64px;
+ --space-20: 80px;
+ --space-24: 96px;
+
+ /* ---------- Radius — restrained, enterprise-grade ---------- */
+ --radius-xs: 2px;
+ --radius-sm: 4px;
+ --radius-md: 6px; /* default for inputs, buttons, badges */
+ --radius-lg: 10px; /* cards */
+ --radius-xl: 14px;
+ --radius-pill: 999px;
+
+ /* ---------- Elevation — soft, neutral, no colored shadows ---------- */
+ --shadow-xs: 0 1px 2px rgba(20, 24, 33, 0.04);
+ --shadow-sm: 0 1px 2px rgba(20, 24, 33, 0.06), 0 1px 3px rgba(20, 24, 33, 0.04);
+ --shadow-md: 0 2px 4px rgba(20, 24, 33, 0.06), 0 4px 8px rgba(20, 24, 33, 0.05);
+ --shadow-lg: 0 4px 12px rgba(20, 24, 33, 0.08), 0 12px 24px rgba(20, 24, 33, 0.06);
+ --shadow-xl: 0 8px 20px rgba(20, 24, 33, 0.10), 0 20px 40px rgba(20, 24, 33, 0.08);
+ --shadow-inset: inset 0 1px 0 rgba(255,255,255,0.6), inset 0 -1px 0 rgba(20,24,33,0.04);
+ --ring-focus: 0 0 0 3px rgba(37, 99, 172, 0.22);
+
+ /* ---------- Motion ---------- */
+ --ease-standard: cubic-bezier(0.2, 0, 0, 1);
+ --ease-emphasized: cubic-bezier(0.2, 0, 0, 1.2);
+ --ease-decelerate: cubic-bezier(0, 0, 0.2, 1);
+ --duration-fast: 120ms;
+ --duration-base: 180ms;
+ --duration-slow: 240ms;
+
+ /* ---------- Layout ---------- */
+ --layout-sidebar: 240px;
+ --layout-sidebar-collapsed: 64px;
+ --layout-topbar: 56px;
+ --layout-content-max: 1440px;
+}
+
+/* =========================================================================
+ Semantic element styles — apply to base elements within design system docs.
+ These do NOT bleed into ui_kits / pages with their own styles.
+ ========================================================================= */
+.ds-typography {
+ font-family: var(--font-sans);
+ color: var(--fg-default);
+ font-feature-settings: "tnum" 1, "ss01" 1;
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+}
+
+.ds-typography h1,
+.ds-h1 {
+ font-size: var(--text-4xl);
+ font-weight: var(--weight-semibold);
+ line-height: var(--leading-tight);
+ letter-spacing: var(--tracking-cn-display);
+ color: var(--brand-900);
+ margin: 0 0 var(--space-4);
+}
+.ds-typography h2,
+.ds-h2 {
+ font-size: var(--text-3xl);
+ font-weight: var(--weight-semibold);
+ line-height: var(--leading-tight);
+ letter-spacing: var(--tracking-cn-display);
+ color: var(--brand-900);
+ margin: 0 0 var(--space-3);
+}
+.ds-typography h3,
+.ds-h3 {
+ font-size: var(--text-2xl);
+ font-weight: var(--weight-semibold);
+ line-height: var(--leading-snug);
+ color: var(--gray-900);
+ margin: 0 0 var(--space-3);
+}
+.ds-typography h4,
+.ds-h4 {
+ font-size: var(--text-xl);
+ font-weight: var(--weight-semibold);
+ line-height: var(--leading-snug);
+ color: var(--gray-900);
+ margin: 0 0 var(--space-2);
+}
+.ds-typography h5,
+.ds-h5 {
+ font-size: var(--text-lg);
+ font-weight: var(--weight-semibold);
+ line-height: var(--leading-snug);
+ color: var(--gray-800);
+ margin: 0 0 var(--space-2);
+}
+.ds-typography p,
+.ds-body {
+ font-size: var(--text-md);
+ font-weight: var(--weight-regular);
+ line-height: var(--leading-normal);
+ color: var(--fg-default);
+ margin: 0 0 var(--space-3);
+}
+.ds-typography small,
+.ds-caption {
+ font-size: var(--text-xs);
+ color: var(--fg-muted);
+ line-height: var(--leading-snug);
+}
+.ds-typography code,
+.ds-mono {
+ font-family: var(--font-mono);
+ font-size: 0.93em;
+ background: var(--gray-100);
+ padding: 1px 6px;
+ border-radius: var(--radius-sm);
+ color: var(--gray-800);
+}
+.ds-num {
+ font-variant-numeric: tabular-nums;
+ font-feature-settings: "tnum" 1;
+}
+.ds-label {
+ font-size: var(--text-xs);
+ font-weight: var(--weight-medium);
+ letter-spacing: var(--tracking-wide);
+ text-transform: none; /* Chinese never uppercases */
+ color: var(--fg-muted);
+}
+
+/* Focus ring shared across the system */
+.ds-focusable:focus-visible,
+:focus-visible {
+ outline: none;
+ box-shadow: var(--ring-focus);
+ border-color: var(--border-focus);
+}
diff --git a/web/assets/docs.css b/web/assets/docs.css
new file mode 100644
index 0000000..3d41bca
--- /dev/null
+++ b/web/assets/docs.css
@@ -0,0 +1,347 @@
+/* ====================================================================
+ DOCS SUB-HEADER
+ ==================================================================== */
+.docs-subnav {
+ background: var(--gray-25);
+ border-bottom: 1px solid var(--border-subtle);
+ position: sticky;
+ top: 64px;
+ z-index: 40;
+}
+.docs-subnav-inner {
+ max-width: 1440px;
+ margin: 0 auto;
+ padding: 12px 32px;
+ display: flex; align-items: center; gap: 24px;
+}
+.breadcrumb {
+ display: flex; align-items: center; gap: 8px;
+ font-size: var(--text-sm);
+ color: var(--fg-muted);
+}
+.breadcrumb .sep { color: var(--gray-300); }
+.breadcrumb a { color: var(--fg-muted); }
+.breadcrumb a:hover { color: var(--brand-500); }
+.breadcrumb .current { color: var(--gray-900); font-weight: 500; }
+
+.docs-search {
+ flex: 1; max-width: 480px;
+ position: relative;
+}
+.docs-search input {
+ width: 100%;
+ height: 36px;
+ padding: 0 12px 0 38px;
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-md);
+ background: var(--gray-0);
+ font-family: inherit;
+ font-size: var(--text-sm);
+ color: var(--gray-800);
+ outline: none;
+ transition: border-color var(--duration-fast) var(--ease-standard),
+ box-shadow var(--duration-fast) var(--ease-standard);
+}
+.docs-search input:focus { border-color: var(--brand-500); box-shadow: var(--ring-focus); }
+.docs-search input::placeholder { color: var(--fg-subtle); }
+.docs-search .search-icon {
+ position: absolute;
+ left: 12px; top: 50%;
+ transform: translateY(-50%);
+ width: 16px; height: 16px;
+ color: var(--fg-subtle);
+}
+.docs-search .kbd {
+ position: absolute;
+ right: 8px; top: 50%;
+ transform: translateY(-50%);
+ background: var(--gray-100);
+ border: 1px solid var(--border-default);
+ border-radius: 3px;
+ padding: 2px 6px;
+ font-size: 11px;
+ color: var(--fg-muted);
+ font-family: var(--font-mono);
+}
+
+.docs-version {
+ display: flex; align-items: center; gap: 6px;
+ background: var(--gray-0);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-md);
+ padding: 6px 12px;
+ font-size: var(--text-sm);
+ color: var(--gray-700);
+}
+.docs-version .icon { width: 14px; height: 14px; }
+.docs-version-label { color: var(--fg-subtle); font-size: var(--text-xs); }
+
+/* ====================================================================
+ DOCS LAYOUT (three-column)
+ ==================================================================== */
+.docs-layout {
+ max-width: 1440px;
+ margin: 0 auto;
+ padding: 32px;
+ display: grid;
+ grid-template-columns: 240px 1fr 240px;
+ gap: 48px;
+ align-items: start;
+}
+
+/* ====================================================================
+ LEFT TOC
+ ==================================================================== */
+.docs-toc {
+ position: sticky;
+ top: 132px;
+ max-height: calc(100vh - 152px);
+ overflow-y: auto;
+ font-size: var(--text-sm);
+}
+.toc-section { margin-bottom: 18px; }
+.toc-section-title {
+ font-size: 11px;
+ font-weight: 600;
+ letter-spacing: 0.06em;
+ color: var(--fg-subtle);
+ text-transform: uppercase;
+ margin: 0 0 10px;
+ padding-left: 12px;
+}
+.toc-link {
+ display: flex; align-items: center; gap: 10px;
+ padding: 7px 12px;
+ border-radius: var(--radius-sm);
+ color: var(--gray-700);
+ font-weight: 400;
+ transition: background var(--duration-fast) var(--ease-standard),
+ color var(--duration-fast) var(--ease-standard);
+}
+.toc-link:hover { background: var(--gray-100); color: var(--brand-900); }
+.toc-link .toc-num {
+ font-family: var(--font-mono);
+ font-size: 11px;
+ color: var(--fg-subtle);
+ min-width: 16px;
+ font-weight: 500;
+}
+.toc-link.active {
+ background: var(--brand-50);
+ color: var(--brand-700);
+ font-weight: 500;
+}
+.toc-link.active .toc-num { color: var(--brand-500); }
+
+/* ====================================================================
+ MAIN CONTENT
+ ==================================================================== */
+.docs-main { min-width: 0; max-width: 760px; }
+
+.docs-chapter { padding-bottom: 48px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 48px; }
+.docs-chapter:last-child { border-bottom: none; margin-bottom: 0; }
+
+.docs-main h2 {
+ font-size: var(--text-2xl);
+ font-weight: 600;
+ color: var(--brand-900);
+ margin: 0 0 16px;
+ letter-spacing: 0.02em;
+ scroll-margin-top: 132px;
+ padding-bottom: 12px;
+ border-bottom: 2px solid var(--brand-100);
+}
+.docs-main h3 {
+ font-size: var(--text-lg);
+ font-weight: 600;
+ color: var(--gray-900);
+ margin: 32px 0 12px;
+ scroll-margin-top: 132px;
+}
+.docs-main p {
+ font-size: var(--text-md);
+ color: var(--gray-700);
+ line-height: 1.75;
+ margin: 0 0 16px;
+}
+.docs-main strong { color: var(--brand-900); font-weight: 600; }
+.docs-main em { color: var(--brand-700); font-style: normal; font-weight: 500; }
+.docs-main code {
+ font-family: var(--font-mono);
+ font-size: 0.92em;
+ background: var(--gray-100);
+ color: var(--brand-700);
+ padding: 1px 6px;
+ border-radius: var(--radius-sm);
+}
+.docs-main a {
+ color: var(--brand-500);
+ font-weight: 500;
+ border-bottom: 1px solid var(--brand-200);
+}
+.docs-main a:hover { color: var(--brand-700); border-color: var(--brand-500); }
+
+.docs-main ol, .docs-main ul {
+ margin: 0 0 16px;
+ padding-left: 24px;
+}
+.docs-main li {
+ font-size: var(--text-md);
+ color: var(--gray-700);
+ line-height: 1.75;
+ margin-bottom: 6px;
+}
+.docs-main ol li::marker {
+ color: var(--brand-500);
+ font-weight: 600;
+}
+
+/* Rendered markdown tables */
+.docs-main table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0 24px;
+ font-size: var(--text-sm);
+ background: var(--gray-0);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-md);
+ overflow: hidden;
+}
+.docs-main th, .docs-main td {
+ padding: 10px 14px;
+ text-align: left;
+ border-bottom: 1px solid var(--border-subtle);
+ line-height: 1.55;
+}
+.docs-main thead th {
+ background: var(--gray-50);
+ font-size: var(--text-xs);
+ font-weight: 600;
+ color: var(--gray-700);
+ letter-spacing: 0.02em;
+ text-transform: uppercase;
+ border-bottom: 1px solid var(--border-default);
+}
+.docs-main tbody tr:last-child td { border-bottom: none; }
+.docs-main tbody tr:hover { background: var(--gray-25); }
+
+/* Rendered markdown code blocks */
+.docs-main pre {
+ background: var(--gray-25);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-md);
+ padding: 16px 20px;
+ overflow-x: auto;
+ margin: 16px 0 24px;
+}
+.docs-main pre code {
+ background: none;
+ color: var(--gray-800);
+ padding: 0;
+ font-size: var(--text-sm);
+ line-height: 1.6;
+ border-radius: 0;
+}
+
+/* Blockquote → callout-style */
+.docs-main blockquote {
+ background: var(--info-50);
+ border-left: 3px solid var(--info-500);
+ border-radius: var(--radius-md);
+ padding: 14px 18px;
+ margin: 16px 0 24px;
+ color: var(--info-700);
+}
+.docs-main blockquote p { color: var(--gray-700); margin: 0; font-size: var(--text-sm); line-height: 1.6; }
+
+/* ====================================================================
+ RIGHT RAIL
+ ==================================================================== */
+.docs-rail {
+ position: sticky;
+ top: 132px;
+ font-size: var(--text-sm);
+}
+.rail-title {
+ font-size: 11px;
+ font-weight: 600;
+ letter-spacing: 0.06em;
+ color: var(--fg-subtle);
+ text-transform: uppercase;
+ margin: 0 0 12px;
+}
+.rail-list { display: flex; flex-direction: column; gap: 2px; list-style: none; padding: 0; margin: 0 0 24px; }
+.rail-list a {
+ display: block;
+ padding: 5px 10px;
+ border-radius: var(--radius-sm);
+ color: var(--fg-muted);
+ font-size: 13px;
+ border-left: 2px solid transparent;
+}
+.rail-list a:hover { color: var(--brand-700); }
+.rail-list a.active {
+ color: var(--brand-700);
+ border-left-color: var(--brand-500);
+ font-weight: 500;
+}
+.rail-actions {
+ padding-top: 16px;
+ border-top: 1px solid var(--border-subtle);
+ display: flex; flex-direction: column; gap: 6px;
+}
+.rail-action {
+ display: flex; align-items: center; gap: 8px;
+ padding: 6px 10px;
+ font-size: 13px;
+ color: var(--fg-muted);
+ border-radius: var(--radius-sm);
+ cursor: pointer;
+ background: none;
+ border: none;
+ font-family: inherit;
+ width: 100%;
+ text-align: left;
+}
+.rail-action:hover { background: var(--gray-50); color: var(--brand-700); }
+.rail-action .icon { width: 14px; height: 14px; }
+
+/* ====================================================================
+ FEEDBACK WIDGET
+ ==================================================================== */
+.docs-feedback {
+ margin-top: 40px;
+ padding: 24px;
+ background: var(--gray-25);
+ border-radius: var(--radius-lg);
+ display: flex; align-items: center; justify-content: space-between;
+}
+.feedback-q { font-size: var(--text-md); color: var(--gray-800); }
+.feedback-actions { display: flex; gap: 8px; }
+.feedback-btn {
+ display: inline-flex; align-items: center; gap: 6px;
+ background: var(--gray-0);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-md);
+ padding: 6px 14px;
+ font-size: var(--text-sm);
+ color: var(--gray-700);
+ cursor: pointer;
+ font-family: inherit;
+}
+.feedback-btn:hover { border-color: var(--brand-500); color: var(--brand-700); }
+.feedback-btn .icon { width: 14px; height: 14px; }
+
+/* ====================================================================
+ RESPONSIVE
+ ==================================================================== */
+@media (max-width: 1200px) {
+ .docs-layout { grid-template-columns: 220px 1fr; gap: 32px; }
+ .docs-rail { display: none; }
+}
+@media (max-width: 880px) {
+ .docs-layout { grid-template-columns: 1fr; gap: 24px; padding: 16px; }
+ .docs-toc { position: static; max-height: none; border: 1px solid var(--border-subtle); border-radius: var(--radius-md); padding: 16px; margin-bottom: 8px; }
+ .docs-subnav-inner { padding: 10px 16px; }
+ .docs-search { max-width: none; }
+}
diff --git a/web/assets/nav.js b/web/assets/nav.js
new file mode 100644
index 0000000..e68d26e
--- /dev/null
+++ b/web/assets/nav.js
@@ -0,0 +1,90 @@
+(function() {
+ var KEYS = ['access_token','refresh_token','username','real_name','shop_no','shop_id','role'];
+
+ function getAuthUser() {
+ var token = localStorage.getItem('flutter.access_token');
+ var username = localStorage.getItem('flutter.username');
+ if (!token || !username) return null;
+ return {
+ username: username,
+ realName: localStorage.getItem('flutter.real_name') || '',
+ role: localStorage.getItem('flutter.role') || '',
+ shopNo: localStorage.getItem('flutter.shop_no') || '',
+ };
+ }
+
+ function doLogout() {
+ KEYS.forEach(function(k) { localStorage.removeItem('flutter.' + k); });
+ location.reload();
+ }
+
+ function toggleUserMenu() {
+ var el = document.getElementById('userDropdown');
+ if (el) el.classList.toggle('open');
+ }
+
+ // 点击外部关闭 dropdown
+ document.addEventListener('click', function(e) {
+ var menu = document.getElementById('userDropdown');
+ if (!menu) return;
+ var navUser = menu.closest('.nav-user');
+ if (navUser && !navUser.contains(e.target)) menu.classList.remove('open');
+ });
+
+ function renderNav() {
+ var cta = document.getElementById('nav-cta');
+ if (!cta) return;
+ var user = getAuthUser();
+ if (user) {
+ var display = user.realName || user.username;
+ var initial = display.charAt(0).toUpperCase();
+ var roleMap = { admin: '管理员', user: '成员', readonly: '只读' };
+ var roleLabel = roleMap[user.role] || user.role;
+ cta.innerHTML =
+ ''
+ + '
'
+ + '
'
+ + '
'
+ + '
' + display + '
'
+ + '
'
+ + (user.shopNo ? user.shopNo + ' · ' : '') + roleLabel
+ + '
'
+ + '
'
+ + '
进入管理端'
+ + '
'
+ + '
'
+ + '
';
+ } else {
+ cta.innerHTML =
+ '登录'
+ + '免费试用';
+ }
+ if (window.lucide) lucide.createIcons();
+ }
+
+ // 暴露给 onclick 调用
+ window.toggleUserMenu = toggleUserMenu;
+ window.doLogout = doLogout;
+
+ document.addEventListener('DOMContentLoaded', function() {
+ renderNav();
+ if (window.lucide) lucide.createIcons();
+
+ // 页内锚点平滑滚动
+ document.querySelectorAll('a[href^="#"]').forEach(function(a) {
+ a.addEventListener('click', function(e) {
+ var id = a.getAttribute('href');
+ if (!id || id.length < 2) return;
+ var target = document.querySelector(id);
+ if (target) {
+ e.preventDefault();
+ target.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ }
+ });
+ });
+ });
+})();
diff --git a/web/assets/shared.css b/web/assets/shared.css
new file mode 100644
index 0000000..20e8f9f
--- /dev/null
+++ b/web/assets/shared.css
@@ -0,0 +1,183 @@
+/* ================================================================
+ shared.css — 跨页面公用样式
+ 设计 token 由 colors_and_type.css 提供
+ ================================================================ */
+
+* { box-sizing: border-box; }
+html, body {
+ margin: 0; padding: 0;
+ font-family: var(--font-sans);
+ color: var(--fg-default);
+ background: var(--gray-25);
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ font-feature-settings: "tnum" 1;
+}
+img, svg { display: block; max-width: 100%; }
+a { color: inherit; text-decoration: none; }
+button { font-family: inherit; cursor: pointer; }
+
+/* ----------------------------------------------------------------
+ Buttons
+ ---------------------------------------------------------------- */
+.btn {
+ display: inline-flex; align-items: center; gap: 8px;
+ height: 40px; padding: 0 18px;
+ border-radius: var(--radius-md);
+ font-size: var(--text-md); font-weight: 500;
+ border: 1px solid transparent;
+ transition: background var(--duration-fast) var(--ease-standard),
+ border-color var(--duration-fast) var(--ease-standard),
+ color var(--duration-fast) var(--ease-standard);
+ white-space: nowrap;
+}
+.btn-primary { background: var(--brand-500); color: #fff; }
+.btn-primary:hover { background: var(--brand-600); }
+.btn-primary:active { background: var(--brand-700); }
+.btn-secondary { background: var(--gray-0); color: var(--brand-900); border-color: var(--border-default); }
+.btn-secondary:hover { background: var(--gray-50); border-color: var(--border-strong); }
+.btn-ghost { background: transparent; color: var(--fg-default); }
+.btn-ghost:hover { background: var(--gray-100); }
+.btn-lg { height: 48px; padding: 0 24px; font-size: var(--text-lg); }
+.btn .icon { width: 18px; height: 18px; }
+
+/* ----------------------------------------------------------------
+ Layout helpers
+ ---------------------------------------------------------------- */
+.container {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 0 32px;
+}
+.section { padding: 96px 0; }
+.section-tight { padding: 64px 0; }
+.eyebrow {
+ font-size: var(--text-xs);
+ font-weight: 600;
+ letter-spacing: 0.12em;
+ color: var(--brand-500);
+ text-transform: uppercase;
+ margin: 0 0 12px;
+}
+.section-title {
+ font-size: var(--text-4xl);
+ font-weight: 600;
+ line-height: 1.18;
+ letter-spacing: var(--tracking-cn-display);
+ color: var(--brand-900);
+ margin: 0 0 16px;
+ max-width: 720px;
+}
+.section-sub {
+ font-size: var(--text-lg);
+ line-height: 1.6;
+ color: var(--fg-muted);
+ margin: 0;
+ max-width: 640px;
+}
+
+/* ----------------------------------------------------------------
+ Top Nav
+ ---------------------------------------------------------------- */
+.topnav {
+ position: sticky; top: 0; z-index: 50;
+ background: rgba(255,255,255,0.85);
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
+ border-bottom: 1px solid var(--border-subtle);
+}
+.topnav-inner {
+ height: 64px;
+ display: flex; align-items: center; justify-content: space-between;
+ max-width: 1440px; margin: 0 auto; padding: 0 32px;
+}
+.topnav-brand { display: flex; align-items: center; gap: 10px; }
+.topnav-brand img { height: 32px; }
+.topnav-links {
+ display: flex; align-items: center; gap: 4px;
+ font-size: var(--text-md); color: var(--gray-700);
+}
+.topnav-links a {
+ padding: 8px 14px;
+ border-radius: var(--radius-md);
+ transition: background var(--duration-fast) var(--ease-standard);
+}
+.topnav-links a:hover { background: var(--gray-100); color: var(--brand-900); }
+.topnav-cta { display: flex; gap: 10px; align-items: center; }
+
+/* Nav user dropdown */
+.nav-user { position: relative; }
+.nav-user-btn {
+ display: flex; align-items: center; gap: 8px;
+ height: 36px; padding: 0 12px;
+ background: var(--gray-0); border: 1px solid var(--border-default);
+ border-radius: var(--radius-pill); cursor: pointer;
+ font-size: var(--text-md); color: var(--gray-800); font-weight: 500;
+ transition: border-color var(--duration-fast) var(--ease-standard);
+}
+.nav-user-btn:hover { border-color: var(--border-strong); }
+.nav-avatar {
+ width: 22px; height: 22px; border-radius: 50%;
+ background: var(--brand-500); color: #fff;
+ display: grid; place-items: center;
+ font-size: 10px; font-weight: 700; flex-shrink: 0;
+}
+.nav-user-btn .icon { width: 14px; height: 14px; color: var(--fg-muted); }
+.nav-dropdown {
+ display: none; position: absolute; top: calc(100% + 8px); right: 0;
+ min-width: 160px; background: var(--gray-0);
+ border: 1px solid var(--border-default); border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-lg); overflow: hidden; z-index: 100;
+}
+.nav-dropdown.open { display: block; }
+.nav-dropdown a, .nav-dropdown button {
+ display: flex; align-items: center; gap: 8px;
+ width: 100%; padding: 10px 14px;
+ font-size: var(--text-sm); color: var(--gray-800);
+ background: none; border: none; cursor: pointer;
+ text-decoration: none; font-family: inherit;
+ transition: background var(--duration-fast) var(--ease-standard);
+}
+.nav-dropdown a:hover, .nav-dropdown button:hover { background: var(--gray-50); }
+.nav-dropdown .icon { width: 14px; height: 14px; color: var(--fg-muted); }
+.nav-dropdown-divider { height: 1px; background: var(--border-subtle); margin: 4px 0; }
+.nav-dropdown .logout { color: var(--danger-600); }
+
+/* ----------------------------------------------------------------
+ Footer
+ ---------------------------------------------------------------- */
+footer {
+ background: var(--gray-25);
+ border-top: 1px solid var(--border-subtle);
+ padding: 64px 0 40px;
+}
+.footer-grid {
+ display: grid;
+ grid-template-columns: 1.5fr repeat(4, 1fr);
+ gap: 48px;
+ margin-bottom: 48px;
+}
+.footer-brand img { height: 32px; margin-bottom: 16px; }
+.footer-brand p { margin: 0 0 16px; max-width: 320px; line-height: 1.6; color: var(--fg-muted); }
+.footer-contact { font-size: var(--text-sm); color: var(--gray-700); line-height: 1.8; }
+.footer-col h5 {
+ font-size: var(--text-xs); font-weight: 600;
+ color: var(--brand-900); letter-spacing: 0.06em;
+ margin: 0 0 16px; text-transform: uppercase;
+}
+.footer-col ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
+.footer-col li a { color: var(--gray-600); }
+.footer-col li a:hover { color: var(--brand-500); }
+.footer-bottom {
+ border-top: 1px solid var(--border-subtle); padding-top: 24px;
+ display: flex; justify-content: space-between;
+ font-size: var(--text-xs); color: var(--fg-subtle);
+}
+
+/* ----------------------------------------------------------------
+ Responsive
+ ---------------------------------------------------------------- */
+@media (max-width: 1024px) {
+ .footer-grid { grid-template-columns: 1fr 1fr; }
+ .container { padding: 0 20px; }
+}
diff --git a/web/assets/style.css b/web/assets/style.css
new file mode 100644
index 0000000..d527ed7
--- /dev/null
+++ b/web/assets/style.css
@@ -0,0 +1,459 @@
+/* ================================================================
+ style.css — 全局样式
+ Token 由 color.css 提供
+ 分三层:① Reset & 基础 ② 组件 ③ 工具类
+ ================================================================ */
+
+/* ----------------------------------------------------------------
+ ① Reset & 基础
+ ---------------------------------------------------------------- */
+* { box-sizing: border-box; }
+html, body {
+ margin: 0; padding: 0;
+ font-family: var(--font-sans);
+ color: var(--fg-default);
+ background: var(--gray-25);
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ font-feature-settings: "tnum" 1;
+}
+img, svg { display: block; max-width: 100%; }
+a { color: inherit; text-decoration: none; }
+button { font-family: inherit; cursor: pointer; }
+
+/* ----------------------------------------------------------------
+ ② 组件
+ ---------------------------------------------------------------- */
+
+/* -- Buttons -- */
+.btn {
+ display: inline-flex; align-items: center; gap: 8px;
+ height: 40px; padding: 0 18px;
+ border-radius: var(--radius-md);
+ font-size: var(--text-md); font-weight: 500;
+ border: 1px solid transparent;
+ transition: background var(--duration-fast) var(--ease-standard),
+ border-color var(--duration-fast) var(--ease-standard),
+ color var(--duration-fast) var(--ease-standard);
+ white-space: nowrap;
+}
+.btn-primary { background: var(--brand-500); color: #fff; }
+.btn-primary:hover { background: var(--brand-600); }
+.btn-primary:active { background: var(--brand-700); }
+.btn-secondary { background: var(--gray-0); color: var(--brand-900); border-color: var(--border-default); }
+.btn-secondary:hover { background: var(--gray-50); border-color: var(--border-strong); }
+.btn-ghost { background: transparent; color: var(--fg-default); }
+.btn-ghost:hover { background: var(--gray-100); }
+.btn-lg { height: 48px; padding: 0 24px; font-size: var(--text-lg); }
+.btn .icon { width: 18px; height: 18px; }
+
+/* -- Layout helpers -- */
+.container { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
+.section { padding: 96px 0; }
+.section-tight { padding: 64px 0; }
+.eyebrow {
+ font-size: var(--text-xs); font-weight: 600;
+ letter-spacing: 0.12em; color: var(--brand-500);
+ text-transform: uppercase; margin: 0 0 12px;
+}
+.section-title {
+ font-size: var(--text-4xl); font-weight: 600;
+ line-height: 1.18; letter-spacing: var(--tracking-cn-display);
+ color: var(--brand-900); margin: 0 0 16px; max-width: 720px;
+}
+.section-sub {
+ font-size: var(--text-lg); line-height: 1.6;
+ color: var(--fg-muted); margin: 0; max-width: 640px;
+}
+
+/* -- Top Nav -- */
+.topnav {
+ position: sticky; top: 0; z-index: 50;
+ background: rgba(255,255,255,0.85);
+ backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
+ border-bottom: 1px solid var(--border-subtle);
+}
+.topnav-inner {
+ height: 64px; display: flex; align-items: center; justify-content: space-between;
+ max-width: 1440px; margin: 0 auto; padding: 0 32px;
+}
+.topnav-brand { display: flex; align-items: center; gap: 10px; }
+.topnav-brand img { height: 32px; }
+.topnav-links {
+ display: flex; align-items: center; gap: 4px;
+ font-size: var(--text-md); color: var(--gray-700);
+}
+.topnav-links a {
+ padding: 8px 14px; border-radius: var(--radius-md);
+ transition: background var(--duration-fast) var(--ease-standard);
+}
+.topnav-links a:hover { background: var(--gray-100); color: var(--brand-900); }
+.topnav-cta { display: flex; gap: 10px; align-items: center; }
+
+/* Nav user dropdown */
+.nav-user { position: relative; }
+.nav-user-btn {
+ display: flex; align-items: center; gap: 8px;
+ height: 36px; padding: 0 12px;
+ background: var(--gray-0); border: 1px solid var(--border-default);
+ border-radius: var(--radius-pill); cursor: pointer;
+ font-size: var(--text-md); color: var(--gray-800); font-weight: 500;
+ transition: border-color var(--duration-fast) var(--ease-standard);
+}
+.nav-user-btn:hover { border-color: var(--border-strong); }
+.nav-avatar {
+ width: 22px; height: 22px; border-radius: 50%;
+ background: var(--brand-500); color: #fff;
+ display: grid; place-items: center;
+ font-size: 10px; font-weight: 700; flex-shrink: 0;
+}
+.nav-user-btn .icon { width: 14px; height: 14px; color: var(--fg-muted); }
+.nav-dropdown {
+ display: none; position: absolute; top: calc(100% + 8px); right: 0;
+ min-width: 160px; background: var(--gray-0);
+ border: 1px solid var(--border-default); border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-lg); overflow: hidden; z-index: 100;
+}
+.nav-dropdown.open { display: block; }
+.nav-dropdown a, .nav-dropdown button {
+ display: flex; align-items: center; gap: 8px;
+ width: 100%; padding: 10px 14px;
+ font-size: var(--text-sm); color: var(--gray-800);
+ background: none; border: none; cursor: pointer;
+ text-decoration: none; font-family: inherit;
+ transition: background var(--duration-fast) var(--ease-standard);
+}
+.nav-dropdown a:hover, .nav-dropdown button:hover { background: var(--gray-50); }
+.nav-dropdown .icon { width: 14px; height: 14px; color: var(--fg-muted); }
+.nav-dropdown-divider { height: 1px; background: var(--border-subtle); margin: 4px 0; }
+.nav-dropdown .logout { color: var(--danger-600); }
+
+/* -- Footer -- */
+footer {
+ background: var(--gray-25);
+ border-top: 1px solid var(--border-subtle);
+ padding: 64px 0 40px;
+}
+.footer-grid {
+ display: grid; grid-template-columns: 1.5fr repeat(4, 1fr);
+ gap: 48px; margin-bottom: 48px;
+}
+.footer-brand img { height: 32px; margin-bottom: 16px; }
+.footer-brand p { margin: 0 0 16px; max-width: 320px; line-height: 1.6; color: var(--fg-muted); }
+.footer-contact { font-size: var(--text-sm); color: var(--gray-700); line-height: 1.8; }
+.footer-col h5 {
+ font-size: var(--text-xs); font-weight: 600;
+ color: var(--brand-900); letter-spacing: 0.06em;
+ margin: 0 0 16px; text-transform: uppercase;
+}
+.footer-col ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
+.footer-col li a { color: var(--gray-600); }
+.footer-col li a:hover { color: var(--brand-500); }
+.footer-bottom {
+ border-top: 1px solid var(--border-subtle); padding-top: 24px;
+ display: flex; justify-content: space-between;
+ font-size: var(--text-xs); color: var(--fg-subtle);
+}
+
+/* ----------------------------------------------------------------
+ ③ 工具类
+ 命名规则:{属性}-{值}
+ 间距值直接对应像素:p-8 = padding:8px,gap-16 = gap:16px
+ ---------------------------------------------------------------- */
+
+/* -- Display -- */
+.d-flex { display: flex }
+.d-inline-flex { display: inline-flex }
+.d-grid { display: grid }
+.d-block { display: block }
+.d-inline { display: inline }
+.d-inline-block{ display: inline-block }
+.d-none { display: none }
+.place-center { display: grid; place-items: center } /* 图标容器常用 */
+
+/* -- Flex -- */
+.flex-col { flex-direction: column }
+.flex-wrap { flex-wrap: wrap }
+.flex-1 { flex: 1 }
+.flex-shrink-0 { flex-shrink: 0 }
+.items-center { align-items: center }
+.items-start { align-items: flex-start }
+.items-end { align-items: flex-end }
+.items-baseline { align-items: baseline }
+.justify-center { justify-content: center }
+.justify-between { justify-content: space-between }
+.justify-end { justify-content: flex-end }
+.justify-start { justify-content: flex-start }
+
+/* -- Grid 列模板 -- */
+.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr) }
+.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr) }
+.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr) }
+.grid-5 { display: grid; grid-template-columns: repeat(5, 1fr) }
+
+/* -- Gap -- */
+.gap-2 { gap: 2px }
+.gap-4 { gap: 4px }
+.gap-6 { gap: 6px }
+.gap-8 { gap: 8px }
+.gap-10 { gap: 10px }
+.gap-12 { gap: 12px }
+.gap-14 { gap: 14px }
+.gap-16 { gap: 16px }
+.gap-18 { gap: 18px }
+.gap-24 { gap: 24px }
+.gap-32 { gap: 32px }
+.gap-48 { gap: 48px }
+.gap-64 { gap: 64px }
+
+/* -- Padding(全方向) -- */
+.p-0 { padding: 0 }
+.p-4 { padding: 4px }
+.p-6 { padding: 6px }
+.p-8 { padding: 8px }
+.p-10 { padding: 10px }
+.p-12 { padding: 12px }
+.p-14 { padding: 14px }
+.p-16 { padding: 16px }
+.p-18 { padding: 18px }
+.p-20 { padding: 20px }
+.p-24 { padding: 24px }
+.p-28 { padding: 28px }
+.p-32 { padding: 32px }
+.p-48 { padding: 48px }
+.p-56 { padding: 56px }
+.p-64 { padding: 64px }
+
+/* px / py */
+.px-4 { padding-left: 4px; padding-right: 4px }
+.px-6 { padding-left: 6px; padding-right: 6px }
+.px-8 { padding-left: 8px; padding-right: 8px }
+.px-10 { padding-left: 10px; padding-right: 10px }
+.px-12 { padding-left: 12px; padding-right: 12px }
+.px-14 { padding-left: 14px; padding-right: 14px }
+.px-16 { padding-left: 16px; padding-right: 16px }
+.px-20 { padding-left: 20px; padding-right: 20px }
+.px-24 { padding-left: 24px; padding-right: 24px }
+.px-28 { padding-left: 28px; padding-right: 28px }
+.px-32 { padding-left: 32px; padding-right: 32px }
+
+.py-2 { padding-top: 2px; padding-bottom: 2px }
+.py-4 { padding-top: 4px; padding-bottom: 4px }
+.py-6 { padding-top: 6px; padding-bottom: 6px }
+.py-8 { padding-top: 8px; padding-bottom: 8px }
+.py-10 { padding-top: 10px; padding-bottom: 10px }
+.py-12 { padding-top: 12px; padding-bottom: 12px }
+.py-14 { padding-top: 14px; padding-bottom: 14px }
+.py-16 { padding-top: 16px; padding-bottom: 16px }
+.py-20 { padding-top: 20px; padding-bottom: 20px }
+.py-24 { padding-top: 24px; padding-bottom: 24px }
+.py-32 { padding-top: 32px; padding-bottom: 32px }
+
+/* pt / pb / pl / pr */
+.pt-4 { padding-top: 4px } .pb-4 { padding-bottom: 4px }
+.pt-6 { padding-top: 6px } .pb-6 { padding-bottom: 6px }
+.pt-8 { padding-top: 8px } .pb-8 { padding-bottom: 8px }
+.pt-12 { padding-top: 12px } .pb-12 { padding-bottom: 12px }
+.pt-14 { padding-top: 14px } .pb-14 { padding-bottom: 14px }
+.pt-16 { padding-top: 16px } .pb-16 { padding-bottom: 16px }
+.pt-24 { padding-top: 24px } .pb-24 { padding-bottom: 24px }
+.pt-32 { padding-top: 32px } .pb-32 { padding-bottom: 32px }
+.pl-12 { padding-left: 12px } .pr-12 { padding-right: 12px }
+.pl-16 { padding-left: 16px } .pr-16 { padding-right: 16px }
+.pl-24 { padding-left: 24px } .pr-24 { padding-right: 24px }
+
+/* -- Margin -- */
+.m-0 { margin: 0 }
+.mx-auto { margin-left: auto; margin-right: auto }
+
+.mb-0 { margin-bottom: 0 }
+.mb-2 { margin-bottom: 2px }
+.mb-4 { margin-bottom: 4px }
+.mb-6 { margin-bottom: 6px }
+.mb-8 { margin-bottom: 8px }
+.mb-10 { margin-bottom: 10px }
+.mb-12 { margin-bottom: 12px }
+.mb-14 { margin-bottom: 14px }
+.mb-16 { margin-bottom: 16px }
+.mb-18 { margin-bottom: 18px }
+.mb-24 { margin-bottom: 24px }
+.mb-32 { margin-bottom: 32px }
+.mb-48 { margin-bottom: 48px }
+
+.mt-2 { margin-top: 2px }
+.mt-4 { margin-top: 4px }
+.mt-6 { margin-top: 6px }
+.mt-8 { margin-top: 8px }
+.mt-12 { margin-top: 12px }
+.mt-16 { margin-top: 16px }
+.mt-24 { margin-top: 24px }
+.mt-32 { margin-top: 32px }
+.mt-48 { margin-top: 48px }
+
+.ml-4 { margin-left: 4px }
+.ml-8 { margin-left: 8px }
+.mr-4 { margin-right: 4px }
+.mr-8 { margin-right: 8px }
+
+/* -- Font size(复用 token) -- */
+.fs-xs { font-size: var(--text-xs) }
+.fs-sm { font-size: var(--text-sm) }
+.fs-md { font-size: var(--text-md) }
+.fs-lg { font-size: var(--text-lg) }
+.fs-xl { font-size: var(--text-xl) }
+.fs-2xl { font-size: var(--text-2xl) }
+.fs-3xl { font-size: var(--text-3xl) }
+.fs-4xl { font-size: var(--text-4xl) }
+
+/* -- Font weight -- */
+.fw-4 { font-weight: 400 }
+.fw-5 { font-weight: 500 }
+.fw-6 { font-weight: 600 }
+.fw-7 { font-weight: 700 }
+
+/* -- Line height -- */
+.lh-1 { line-height: 1 }
+.lh-12 { line-height: 1.2 }
+.lh-14 { line-height: 1.4 }
+.lh-15 { line-height: 1.5 }
+.lh-16 { line-height: 1.6 }
+.lh-17 { line-height: 1.7 }
+.lh-18 { line-height: 1.8 }
+
+/* -- Letter spacing -- */
+.ls-1 { letter-spacing: 0.04em }
+.ls-2 { letter-spacing: 0.06em }
+.ls-3 { letter-spacing: 0.10em }
+.ls-4 { letter-spacing: 0.12em }
+.ls-disp { letter-spacing: var(--tracking-cn-display) }
+
+/* -- Text color -- */
+.text-brand { color: var(--brand-500) }
+.text-brand-hi { color: var(--brand-700) }
+.text-brand-900{ color: var(--brand-900) }
+.text-default { color: var(--fg-default) }
+.text-muted { color: var(--fg-muted) }
+.text-subtle { color: var(--fg-subtle) }
+.text-gray-6 { color: var(--gray-600) }
+.text-gray-7 { color: var(--gray-700) }
+.text-gray-8 { color: var(--gray-800) }
+.text-gray-9 { color: var(--gray-900) }
+.text-white { color: #fff }
+.text-success { color: var(--success-700) }
+.text-warning { color: var(--warning-700) }
+.text-danger { color: var(--danger-700) }
+.text-info { color: var(--info-700) }
+
+/* -- Background -- */
+.bg-0 { background: var(--gray-0) }
+.bg-25 { background: var(--gray-25) }
+.bg-50 { background: var(--gray-50) }
+.bg-100 { background: var(--gray-100) }
+.bg-brand { background: var(--brand-500) }
+.bg-brand-50 { background: var(--brand-50) }
+.bg-brand-900{ background: var(--brand-900) }
+.bg-success-50 { background: var(--success-50) }
+.bg-warning-50 { background: var(--warning-50) }
+.bg-danger-50 { background: var(--danger-50) }
+.bg-info-50 { background: var(--info-50) }
+
+/* -- Border -- */
+.border { border: 1px solid var(--border-default) }
+.border-top { border-top: 1px solid var(--border-default) }
+.border-bottom { border-bottom: 1px solid var(--border-default) }
+.border-left { border-left: 1px solid var(--border-default) }
+.border-subtle { border-color: var(--border-subtle) }
+.border-strong { border-color: var(--border-strong) }
+.border-brand { border-color: var(--brand-500) }
+.border-0 { border: none }
+
+/* -- Border radius -- */
+.rounded-sm { border-radius: var(--radius-sm) }
+.rounded-md { border-radius: var(--radius-md) }
+.rounded-lg { border-radius: var(--radius-lg) }
+.rounded-xl { border-radius: var(--radius-xl) }
+.rounded-pill { border-radius: var(--radius-pill) }
+.rounded-full { border-radius: 50% }
+
+/* -- Shadow -- */
+.shadow-sm { box-shadow: var(--shadow-sm) }
+.shadow-md { box-shadow: var(--shadow-md) }
+.shadow-lg { box-shadow: var(--shadow-lg) }
+.shadow-xl { box-shadow: var(--shadow-xl) }
+
+/* -- Text helpers -- */
+.text-upper { text-transform: uppercase }
+.text-center { text-align: center }
+.text-right { text-align: right }
+.text-nowrap { white-space: nowrap }
+.font-mono { font-family: var(--font-mono) }
+.tabular { font-variant-numeric: tabular-nums }
+
+/* -- Sizing & position -- */
+.w-full { width: 100% }
+.h-full { height: 100% }
+.min-w-0 { min-width: 0 }
+.pos-relative { position: relative }
+.pos-absolute { position: absolute }
+.pos-sticky { position: sticky }
+.overflow-hidden { overflow: hidden }
+.overflow-x-auto { overflow-x: auto }
+
+/* -- Transition(常用属性组合) -- */
+.transition {
+ transition: background var(--duration-fast) var(--ease-standard),
+ border-color var(--duration-fast) var(--ease-standard),
+ color var(--duration-fast) var(--ease-standard),
+ box-shadow var(--duration-fast) var(--ease-standard);
+}
+
+/* ----------------------------------------------------------------
+ Card & Badge 高频组合
+ ---------------------------------------------------------------- */
+
+/* card:bg-0 + border + rounded-lg,三个页面共用 15+ 次 */
+.card {
+ background: var(--gray-0);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-lg);
+}
+
+/* badge:状态标签小胶囊 */
+.badge {
+ display: inline-block;
+ padding: 2px 10px;
+ border-radius: var(--radius-pill);
+ font-size: var(--text-xs);
+ font-weight: 600;
+}
+.badge-brand { background: var(--brand-50); color: var(--brand-700) }
+.badge-success { background: var(--success-50); color: var(--success-700) }
+.badge-warning { background: var(--warning-50); color: var(--warning-700) }
+.badge-danger { background: var(--danger-50); color: var(--danger-700) }
+.badge-info { background: var(--info-50); color: var(--info-700) }
+.badge-gray { background: var(--gray-100); color: var(--gray-700) }
+.badge-solid { background: var(--brand-500); color: #fff }
+
+/* icon 尺寸 */
+.icon-sm { width: 14px; height: 14px }
+.icon-md { width: 18px; height: 18px }
+.icon-lg { width: 22px; height: 22px }
+.icon-xl { width: 28px; height: 28px }
+.icon-2xl { width: 36px; height: 36px }
+
+/* icon-box:方形图标容器(带背景色时使用) */
+.icon-box-sm { width: 28px; height: 28px; border-radius: var(--radius-sm); display: grid; place-items: center }
+.icon-box-md { width: 36px; height: 36px; border-radius: 8px; display: grid; place-items: center }
+.icon-box-lg { width: 40px; height: 40px; border-radius: 10px; display: grid; place-items: center }
+.icon-box-xl { width: 56px; height: 56px; border-radius: var(--radius-md); display: grid; place-items: center }
+
+/* ----------------------------------------------------------------
+ Responsive
+ ---------------------------------------------------------------- */
+@media (max-width: 1024px) {
+ .footer-grid { grid-template-columns: 1fr 1fr; }
+ .container { padding: 0 20px; }
+}
+@media (max-width: 768px) {
+ .grid-3, .grid-4, .grid-5 { grid-template-columns: repeat(2, 1fr); }
+}
diff --git a/web/content/docs.md b/web/content/docs.md
new file mode 100644
index 0000000..685bc84
--- /dev/null
+++ b/web/content/docs.md
@@ -0,0 +1,487 @@
+# 岩美酒库管理系统 · 使用手册
+
+> 适用版本:v1.x · 受众:酒行管理员及工作人员
+
+---
+
+## 1. 系统概述
+
+岩美酒库管理系统专为酒行门店设计,将入库、出库、库存查询、财务往来等日常业务整合到一个平台,支持多人协同操作,数据实时同步。
+
+**核心功能一览**
+
+| 模块 | 主要用途 |
+|------|---------|
+| 入库管理 | 新建入库单、提交审核、审批通过后自动更新库存 |
+| 出库管理 | 新建出库单、提交审核、审批时自动扣减库存 |
+| 库存管理 | 查询实时库存、库存盘点、打印标签 |
+| 财务管理 | 查看应付款(欠供应商)和应收款(客户欠款)、标记结清 |
+| 往来单位 | 管理供应商和客户的基本信息 |
+| 基础数据 | 维护商品名称、系列、规格字典 |
+| 系统设置 | 用户管理、仓库管理、编号规则、数据导入 |
+
+**支持平台**:Web 浏览器(现已上线);Windows、macOS、iOS、Android 客户端即将推出。
+
+---
+
+## 2. 登录与退出
+
+### 2.1 登录
+
+1. 打开系统,进入登录页面。
+2. 在「门店编号」栏输入酒行的门店代号(例如 `S001`)。
+3. 输入「用户名」和「密码」。
+4. 点击「登录」按钮。
+
+登录成功后,系统自动跳转到「入库管理」页面。
+
+**提示**:系统会记录最近登录过的用户名,点击输入框可从候选列表中快速选择。
+
+### 2.2 退出登录
+
+点击顶部右侧用户名旁的下拉箭头,选择「退出登录」。
+
+### 2.3 查看当前登录信息
+
+点击顶部左侧「岩美」标题或右侧「门店编号」区域,弹出门店信息面板,显示门店编号、登录账号、姓名、系统版本。
+
+---
+
+## 3. 界面说明
+
+系统主界面由三个区域组成:
+
+```
+┌──────────────────────────────────────────────────────────┐
+│ 顶部导航栏(标题、门店编号、用户名、退出) │
+├──────────┬───────────────────────────────────────────────┤
+│ │ │
+│ 左侧 │ 主内容区域 │
+│ 侧边栏 │ │
+│ │ │
+├──────────┴───────────────────────────────────────────────┤
+│ 状态栏(门店、用户、登录时间、当前时间、连接状态) │
+└──────────────────────────────────────────────────────────┘
+```
+
+**左侧侧边栏导航项**
+
+| 导航项 | 功能 |
+|--------|------|
+| 入库管理 | 入库单录入与审核 |
+| 出库管理 | 出库单录入与审核 |
+| 库存管理 | 库存查询与盘点 |
+| 财务管理 | 应付款和应收款 |
+| 往来单位 | 供应商与客户 |
+| 基础数据 | 商品名称、系列、规格字典 |
+| 系统设置 | 用户、仓库、编号规则等配置 |
+
+点击侧边栏顶部的菜单图标可收起或展开侧边栏,节省屏幕空间。
+
+**更新提示**:有新版本时,内容区顶部会显示黄色提示横幅;如果是必须更新的版本,会弹出对话框要求立即更新。
+
+**离线提示**:网络断开时,顶部显示红色横幅「网络连接已断开」,状态栏变红,此时展示上次加载的缓存数据。
+
+---
+
+## 4. 角色与权限
+
+系统有四种角色,权限从高到低依次为:
+
+| 角色 | 说明 | 可执行操作 |
+|------|------|------------|
+| 超级管理员 | 系统最高权限账号 | 全部操作,含数据清空 |
+| 管理员 | 门店管理人员 | 全部操作,含用户管理、酒行信息编辑 |
+| 操作员 | 日常录入审核人员 | 新建、编辑、提交、审核单据,查询数据 |
+| 只读 | 仅查看数据 | 只能查看,不能新建、修改、删除任何数据 |
+
+**权限说明**
+
+- 只读账号点击任何写操作按钮时,系统将直接提示「无权限」。
+- 新增或编辑用户、重置密码仅管理员可操作。
+- 修改酒行基本信息仅管理员可操作。
+- 数据清空仅超级管理员可操作。
+
+---
+
+## 5. 入库管理
+
+入库管理页面包含两个标签页:**入库审核**(新建和待审核)和**入库单**(已完成记录)。
+
+### 5.1 入库单状态说明
+
+单据状态按以下流程流转:
+
+**草稿** → **待审核** → **已审批**(库存增加)
+
+待审核阶段也可被拒绝,变为**已拒绝**状态(库存不变)。
+
+| 状态 | 含义 |
+|------|------|
+| 草稿 | 已保存但未提交,可继续编辑或删除 |
+| 待审核 | 已提交等待审批,不可再编辑 |
+| 已审批 | 审批通过,库存已增加,同时生成应付账款记录 |
+| 已拒绝 | 审批不通过,库存不变 |
+
+### 5.2 新建入库单
+
+1. 点击左侧「入库管理」,切换到「入库审核」标签页。
+2. 点击右上角「新建入库审核单」按钮。
+3. 填写入库基本信息:
+ - **仓库**(必填):选择货物入库的目标仓库。
+ - **供应商**(必填):选择供货的往来单位。
+ - **入库日期**(必填):默认为今天,可修改。
+ - **备注**(选填):填写本批次入库说明。
+4. 在商品明细区域填写每一行商品:
+ - **商品名称**(必填):从字典中选择或直接输入。
+ - **系列**(必填):选择商品系列。
+ - **规格**(必填):选择商品规格,如 500ml×6。
+ - **生产日期**(必填):点击日历图标选择。
+ - **批次号**(选填):填写批次编号,用于后续追踪查询。
+ - **数量**(必填):填写入库数量。
+ - **单价**(必填):填写进货单价,系统自动计算总金额。
+5. 点击「添加商品」可继续增加商品行,点击行末「删除」可移除该行。
+6. 完成后选择操作:
+ - **保存草稿**:保存后可以继续修改。
+ - **保存并提交审核**:提交后进入待审核状态,不可再编辑。
+
+### 5.3 提交审核
+
+草稿状态的入库单,在列表中点击「提交」按钮,确认后单据进入「待审核」状态。
+
+### 5.4 审批入库单
+
+操作员及以上权限的用户均可审批。
+
+1. 在「入库审核」标签页中找到待审核的入库单。
+2. 点击「通过」:弹窗确认,确认后系统自动将商品入库,库存增加,同时生成一笔应付账款记录。
+3. 点击「拒绝」:弹窗确认,拒绝后库存不变,单据进入「已拒绝」状态。
+
+**注意**:审批通过后操作不可撤销,请仔细核对商品数量和单价后再确认。
+
+### 5.5 查看入库单详情
+
+点击入库单号(蓝色链接)可弹出详情页,显示完整的商品明细、数量、金额及审核信息。详情页右上角有打印按钮,可直接打印入库单。
+
+### 5.6 打印入库单
+
+在列表中点击对应行的「打印」按钮,直接调用打印机打印入库单据。
+
+### 5.7 打印商品标签
+
+1. 在列表中点击对应行的「打标签」按钮。
+2. 弹出商品标签打印对话框,列出本次入库的所有商品。
+3. 勾选需要打印标签的商品(默认全选)。
+4. 点击「打印选中」,系统逐张打印选中商品的标签。
+
+标签内容包括:商品名称、编码、系列、规格、批次号、生产日期、酒行名称及联系方式、二维码。
+
+### 5.8 标记货款结清
+
+审批通过的入库单会自动生成应付账款记录。货款付清后,在列表中点击「结清」按钮,确认后将对应财务记录标记为已结清。
+
+### 5.9 筛选与导出
+
+- **仓库筛选**:点击列头「仓库」的筛选图标,选择仓库进行过滤。
+- **供应商筛选**:点击列头「供应商」的筛选图标,选择供应商进行过滤。
+- **日期筛选**:点击「选择日期」按钮,选择日期范围。
+- **导出**:点击「导出」按钮,将当前列表导出为 Excel 文件。
+
+---
+
+## 6. 出库管理
+
+出库管理与入库管理操作流程类似,包含**出库审核**(待处理)和**出库单**(已完成)两个标签页。
+
+### 6.1 出库单状态说明
+
+出库单状态流转与入库单相同:草稿 → 待审核 → 已审批或已拒绝。
+
+审批通过后:
+- 系统会先检查库存是否充足,库存不足时审批失败并给出提示,库存不变。
+- 库存充足时自动扣减库存,并生成应收账款记录。
+
+### 6.2 新建出库单
+
+1. 点击左侧「出库管理」,切换到「出库审核」标签页。
+2. 点击右上角「新建出库审核单」按钮。
+3. 填写基本信息:
+ - **仓库**(必填):选择出货仓库。
+ - **客户**(必填):选择购买方(往来单位中的客户类型)。
+ - **出库日期**(必填):默认今天,可修改。
+4. 填写商品明细:商品名称、系列、规格、数量、单价(操作方式同入库单)。
+5. 保存草稿或保存并提交审核。
+
+**注意**:出库数量不能超过当前库存,审批时系统会自动检查,库存不足会提示失败。
+
+### 6.3 审批出库单
+
+操作步骤与入库审批相同。审批通过后库存自动扣减,同时生成应收账款记录。
+
+### 6.4 打印出库单
+
+在列表中点击「打印」按钮,打印出库单据。
+
+### 6.5 标记货款结清
+
+出库单审批通过后生成应收账款。收到货款后,在列表中点击「结清」按钮,将对应财务记录标记为已结清。
+
+---
+
+## 7. 库存管理
+
+### 7.1 查询库存
+
+点击左侧「库存管理」进入库存列表。
+
+列表显示每个商品的实时库存数量、所在仓库、单价、金额、生产日期、批次等信息。
+
+- **搜索**:在搜索框输入商品名称关键字(也支持拼音或拼音首字母),实时过滤结果。
+- **仓库筛选**:点击列头「仓库」的筛选图标,按仓库查看库存。
+- **导出**:点击「导出」按钮,将当前库存列表导出为 Excel 文件。
+
+### 7.2 修改备注
+
+在库存列表中,点击「备注」列对应单元格(显示铅笔图标或现有备注内容),弹出编辑框,填写后点击「保存」即可。
+
+### 7.3 打印商品标签
+
+在库存列表中点击某商品行的「打印标签」按钮,可单独打印该商品的标签。
+
+### 7.4 库存盘点
+
+1. 在库存管理页面切换到「库存盘点」标签页。
+2. 选择要盘点的**仓库**,系统自动加载该仓库所有商品的账面库存数量。
+3. 选择盘点类型(全盘)。
+4. 逐行填写**实际盘点数量**(与账面不符时修改数量)。
+5. 点击「提交盘点」完成。
+
+盘点单编号由系统自动生成。
+
+### 7.5 库存流水
+
+「库存流水」标签页可查看每次库存变动记录,包括入库、出库的时间、变动数量等。
+
+---
+
+## 8. 财务管理
+
+### 8.1 财务记录说明
+
+系统在以下情况自动生成财务记录:
+- 入库单审批通过 → 自动生成**应付账款**(欠供应商的货款)
+- 出库单审批通过 → 自动生成**应收账款**(客户欠的货款)
+
+点击左侧「财务管理」进入财务页面,包含三个标签:
+
+| 标签 | 内容 |
+|------|------|
+| 全部记录 | 所有财务流水 |
+| 应付账款 | 需要向供应商付款的记录 |
+| 应收账款 | 客户尚未付款的记录 |
+
+### 8.2 查看财务记录
+
+- 默认显示当前月份的记录,可通过月份选择器查看历史月份。
+- 支持按「类型」和「往来单位」列头筛选。
+- 点击「导出」可导出当月数据为 Excel 文件。
+
+### 8.3 标记结清
+
+**方式一**:在入库单或出库单列表中点击「结清」按钮,直接结清该单据对应的账款。
+
+**方式二**:在财务管理列表中找到对应记录,点击「结清」按钮,单笔结清。
+
+结清后该记录状态从「未结清」变为「已结清」。
+
+### 8.4 财务汇总
+
+财务管理页面显示当期应付和应收总额,便于掌握资金往来概况。
+
+---
+
+## 9. 往来单位
+
+往来单位管理**供应商**和**客户**两类信息,新建入库单时选择供应商,新建出库单时选择客户。
+
+### 9.1 查看往来单位
+
+点击左侧「往来单位」,通过「供应商」和「客户」标签页分别查看。列表支持按名称搜索和导出。
+
+### 9.2 新建往来单位
+
+1. 在对应标签页点击右上角「新建」按钮。
+2. 填写信息:
+ - **名称**(必填)
+ - **联系电话**(选填)
+ - **地址**(选填)
+ - **卡号**(选填,如有账户绑定)
+ - **初始余额**(选填,导入历史数据时填写)
+ - **备注**(选填)
+3. 点击「保存」。
+
+### 9.3 编辑往来单位
+
+在列表中点击「编辑」按钮,修改信息后保存。
+
+### 9.4 删除往来单位
+
+在列表中点击「删除」按钮,确认后删除。
+
+**注意**:已关联入库单或出库单的往来单位不可删除。
+
+---
+
+## 10. 基础数据(商品管理)
+
+点击左侧「基础数据」,进入商品字典管理页面,包含三个标签:**商品名称**、**系列**、**规格**。
+
+这些字典数据是新建入库或出库单时选择商品的基础,需要先在此处维护好商品信息。
+
+### 10.1 商品名称管理
+
+商品名称是酒品的主名称,例如「茅台飞天 53°」。
+
+1. 在「商品名称」标签页,点击「新建」按钮。
+2. 填写商品名称(必填)、编号(选填)、备注(选填)。
+3. 点击「保存」。
+
+支持按名称或编号搜索,支持分页浏览,支持编辑和删除。
+
+### 10.2 系列管理
+
+系列是商品所属的系列或品牌线,例如「飞天系列」「王子系列」。操作步骤与商品名称相同。
+
+### 10.3 规格管理
+
+规格用于描述包装规格,例如「500ml×6」「1000ml×1」。新建时可填写「单品数量」(即一箱包含的单瓶数量)。
+
+### 10.4 商品详情与二维码
+
+每个商品都有唯一的二维码,可通过扫码访问商品公开信息页面。在商品详情页可查看或上传商品图片。
+
+---
+
+## 11. 系统设置
+
+点击左侧「系统设置」,包含七个标签页。
+
+### 11.1 酒行信息
+
+显示本门店的基本信息:门店编号、门店名称、地址、联系电话、负责人。
+
+**编辑**(仅管理员):点击「编辑信息」按钮,修改门店名称、地址、电话、负责人后保存。门店编号不可修改。
+
+### 11.2 用户管理(仅管理员)
+
+**查看用户**:显示本门店所有用户的姓名、用户名、角色、启用状态。
+
+**新增用户**:
+1. 点击「新增用户」按钮。
+2. 填写用户名(登录账号,不可重复)、姓名、手机号、初始密码。
+3. 选择角色(操作员、管理员、只读、超级管理员)。
+4. 点击「保存」。
+
+**编辑用户**:点击用户行的「编辑」按钮,可修改姓名、手机号、角色(用户名不可修改)。
+
+**重置密码**:点击「重置密码」按钮,输入新密码后确认,下次登录时使用新密码。
+
+**启用或停用**:在用户列表中拨动状态开关。停用后该用户无法登录。
+
+### 11.3 仓库管理
+
+**查看仓库**:显示所有仓库名称、位置、是否为默认仓库。
+
+**新建仓库**:
+1. 点击「新建」按钮。
+2. 填写仓库名称(必填)、位置(选填)。
+3. 可勾选「设为默认仓库」,新建单据时将自动选择此仓库。
+4. 点击「保存」。
+
+**编辑或删除**:点击对应按钮操作。已有库存的仓库不可删除。
+
+### 11.4 编号规则
+
+系统为每类单据自动生成唯一编号,格式由前缀、日期和序号组成,例如入库单编号 `RK20260523001`。
+
+**查看当前规则**:列表显示每种单据的前缀、当前序号及下一编号示例。
+
+**修改规则**:
+1. 点击对应规则行的「编辑」按钮。
+2. 可修改「前缀」和「当前序号」。
+3. 点击「保存」,修改后对新建单据生效。
+
+**注意**:请勿将序号调小至已使用过的范围,否则可能导致编号重复。
+
+### 11.5 系统参数
+
+配置系统的全局参数:
+
+- **系统名称、货币单位、日期格式、时区**(通常无需修改)
+- **入库单需要审核**:关闭后提交即视为通过,无需审批
+- **出库单需要审核**:关闭后同上
+- **允许超量出库**:开启后,出库数量超过库存时仍可审批通过
+
+修改后点击「保存设置」生效,点击「重置默认」恢复出厂默认值。
+
+### 11.6 数据导入
+
+通过 Excel 文件批量导入历史数据。支持以下数据类型:往来单位、商品名称、商品系列、商品规格、商品编码、库存。
+
+各类型的 Excel 格式要求详见系统内「系统设置 → 数据导入」页面说明。
+
+**操作步骤**:
+1. 在对应数据类型行点击「选择文件」,选择 Excel(.xls 或 .xlsx)文件。
+2. 全部文件选择完成后,点击「全部导入」按钮。
+3. 系统依次处理每个文件并显示导入结果(新增、跳过重复、失败数量)。
+4. 如有失败,根据错误提示修正文件后重新导入。
+
+**导入规则**:以名称去重,已存在的记录不重复导入。导入过程中请勿切换页面。
+
+**数据清空(仅超级管理员)**:在数据导入页面下方「危险操作」区域,选择要清空的数据表,点击确认后输入「确认清空」完成操作。**此操作不可撤销,请务必提前做好数据备份。**
+
+### 11.7 关于
+
+- **版本信息**:显示当前系统版本。有新版本时可点击「立即更新」。
+- **授权信息**:显示授权类型(试用、月付、年付、买断)、授权状态、到期时间。授权剩余不足 30 天时会显示倒计时提醒。
+- **意见反馈**:点击「反馈 Bug」或「功能建议」,通过邮件向开发团队反馈。
+
+---
+
+## 12. 常见问题
+
+**Q:入库单提交后发现填错了,怎么办?**
+
+单据提交(待审核状态)后不可再修改。请联系管理员将该单据拒绝,然后重新新建一张正确的入库单。
+
+**Q:出库审批时提示「库存不足」,怎么处理?**
+
+出库数量超过当前仓库库存时,系统会拒绝审批。请检查出库数量,或确认对应商品的入库单是否已审批通过、库存已更新。
+
+**Q:结清了财务记录但发现结清错了,如何撤销?**
+
+目前系统不支持撤销结清操作。如需处理,请联系技术支持。
+
+**Q:如何查找某批商品是从哪张入库单入库的?**
+
+在库存管理列表中查看商品的批次号,然后在入库管理中按批次号搜索对应的入库单。
+
+**Q:导入数据时提示「格式错误」,怎么处理?**
+
+请检查 Excel 文件的列顺序是否与「系统设置 → 数据导入」页面说明的格式一致,且第一行为数据行(无需填写表头)。如问题持续,可将文件发送给技术支持排查。
+
+**Q:用户无法登录,怎么处理?**
+
+请管理员在「系统设置 → 用户管理」中检查该用户是否处于启用状态,并使用「重置密码」功能为其设置新密码。
+
+**Q:操作时提示「无权限」,是什么原因?**
+
+当前账号角色为「只读」,不允许执行写操作。如需操作,请联系管理员调整账号角色。
+
+**Q:系统显示「网络连接已断开」,数据还准确吗?**
+
+网络断开时,系统展示上次加载的缓存数据,可能不是最新状态。请恢复网络连接后刷新页面获取最新数据。
+
+**Q:如何联系技术支持?**
+
+进入「系统设置 → 关于」查看联系邮箱和技术支持时间。工作日(周一至周五)9:00 - 18:00 可获得响应。
diff --git a/web/content/system-requirements.md b/web/content/system-requirements.md
new file mode 100644
index 0000000..bf375df
--- /dev/null
+++ b/web/content/system-requirements.md
@@ -0,0 +1,36 @@
+## Web 版(已上线)
+
+| 要求 | 最低 | 推荐 |
+|---|---|---|
+| 浏览器 | Chrome 90 / Firefox 90 / Safari 15 / Edge 90 | 最新稳定版 |
+| 网络 | 任意宽带 | 10 Mbps+ |
+
+## Windows(敬请期待)
+
+| 要求 | 版本 |
+|---|---|
+| 系统 | Windows 10(64 位)及以上 |
+| 内存 | 4 GB RAM |
+| 存储 | 500 MB 可用空间 |
+
+## macOS(敬请期待)
+
+| 要求 | 版本 |
+|---|---|
+| 系统 | macOS 12 及以上 |
+| 内存 | 4 GB RAM |
+| 存储 | 500 MB 可用空间 |
+
+## iOS(敬请期待)
+
+| 要求 | 版本 |
+|---|---|
+| 系统 | iOS 15 及以上 |
+| 设备 | iPhone 8 / iPad 第 6 代及以上 |
+
+## Android(敬请期待)
+
+| 要求 | 版本 |
+|---|---|
+| 系统 | Android 9 及以上 |
+| 内存 | 3 GB RAM |
diff --git a/web/docs.html b/web/docs.html
deleted file mode 100644
index bff373e..0000000
--- a/web/docs.html
+++ /dev/null
@@ -1,1167 +0,0 @@
-
-
-
-
-
-文档 · 岩美酒库管理系统
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ⌘ K
-
-
-
- 手册版本
- v1.6.2
-
-
-
-
-
-
-
-
-
-
-
-
-
- 第 5 章
- 入库管理
-
- 入库管理是货物进入门店的起点。本章介绍如何录入入库单、提交审核、审批通过自动更新库存与应付账款的完整流程。所有入库操作均需审核驱动,单据状态不可跳过、不可撤销。
-
-
- 5.1 入库单状态说明
- 每张入库单都在一个固定的状态流中流转。状态变化由系统记录,不可手动跳过。
-
-
-
-
-
- | 状态 | 含义 | 可执行操作 |
-
-
-
- | 草稿 |
- 已保存但未提交 |
- 编辑、删除、提交审核 |
-
-
- | 待审核 |
- 已提交等待审批,不可再编辑 |
- 审批通过、审批拒绝 |
-
-
- | 已审批 |
- 库存已增加,并生成应付账款 |
- 查看详情、打印、打标签、结清 |
-
-
- | 已拒绝 |
- 审批不通过,库存与账款不变 |
- 查看详情 |
-
-
-
-
-
-
-
-
审批通过不可撤销
-
「已审批」状态的单据无法回退到「草稿」或「待审核」。如发现错误,请由具备权限的用户新建反向调整单据(红冲入库)进行修正,以保留完整审计链。
-
-
-
- 5.2 新建入库单
- 新建入库单的入口在「入库管理 → 入库审核」标签页,点击右上角新建入库审核单按钮即可打开录入面板。
-
-
- 点击左侧「入库管理」,切换到 入库审核 标签页。
- 点击右上角 新建入库审核单 按钮,弹出录入面板。
- 填写表头信息(见下方字段说明)。
- 在商品明细区逐行录入商品。点击 添加商品 增加新行,行末 删除 移除。
- 完成后可保存草稿(继续修改)或保存并提交审核(进入待审核)。
-
-
- 表头字段
-
-
- 仓库
- 必填
- 货物入库的目标仓库。系统默认选中设置中的「默认仓库」。
-
-
- 供应商
- 必填
- 供货的往来单位。需提前在「往来单位 → 供应商」中维护。
-
-
- 入库日期
- 必填
- 默认为当天,可修改为历史日期(不能晚于今天)。
-
-
- 备注
- 选填
- 本批次入库的说明,最多 200 字符。
-
-
-
- 商品明细字段
-
-
- 商品名称
- 必填
- 从「基础数据 → 商品名称」字典中选择,支持模糊搜索。
-
-
- 系列
- 必填
- 商品所属的系列或品牌线,如「飞天系列」。
-
-
- 规格
- 必填
- 包装规格,如 500ml×6。
-
-
- 生产日期
- 必填
- 点击日历图标选择,用于批次追溯与过期预警。
-
-
- 批次号
- 选填
- 用于后续追踪、出库时按批次先进先出。
-
-
- 数量 · 单价
- 必填
- 入库数量与进货单价,系统自动计算金额 = 数量 × 单价。
-
-
-
-
-
-
-
小技巧:复制上一行
-
从 v1.6.2 起,明细行右侧出现 复制 按钮,可快速复制上一行的商品 / 规格 / 单价,连续录入同系列商品更快。
-
-
-
- 5.4 审批入库单
- 具有操作员及以上权限的用户均可审批。审批通过后,系统会自动完成两件事:
-
- - 将所有商品按数量加入对应仓库的库存;
- - 按供应商生成一笔应付账款,金额等于入库单合计。
-
-
- 审批接口示例
- 若需通过 API 触发审批,使用如下请求:
- POST /api/v1/stockin/{id}/approve
-Content-Type: application/json
-Authorization: Bearer {token}
-
-{
- "decision": "approve", // approve | reject
- "operator": "李建国",
- "remark": "已核对数量与单价"
-}
-
- 审批成功后返回:
- {
- "ok": true,
- "stockin_no": "RK20260523000007",
- "status": "approved",
- "effects": {
- "inventory_delta": 36,
- "payable_id": "AP20260523000012",
- "payable_amount": 48400.00
- }
-}
-
-
-
-
-
审批前请核对数量与单价
-
审批一旦通过即不可撤销,库存与应付账款将立即变动。如确实需要修正,唯一的合法路径是新建反向调整单(红冲入库),原始单据将完整保留以供审计。
-
-
-
- 5.7 打印商品标签
- 审批通过的入库单,可批量打印商品标签。标签内容包括:
-
- - 商品名称、编码、系列、规格
- - 批次号、生产日期
- - 酒行名称、地址、联系电话
- - 商品二维码(扫码可访问公开信息页)
-
-
- 操作步骤:
-
- 在入库单列表中找到对应行,点击 打标签 按钮。
- 弹出对话框列出本次入库的所有商品,默认全部勾选。
- 勾选需打印的商品(可批量取消),点击 打印选中。
- 系统依次将每张标签发送给已连接的标签打印机。
-
-
-
-
-
-
支持的标签打印机
-
已验证支持佳博 GP-1124T、芯烨 XP-365B、汉印 N31。蓝牙打印机需先在系统设置 → 外设管理中配对。完整型号见 硬件支持文档。
-
-
-
-
-
-
-
-
-
这一节对你有帮助吗?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/web/docs.njk b/web/docs.njk
new file mode 100644
index 0000000..8a481f0
--- /dev/null
+++ b/web/docs.njk
@@ -0,0 +1,194 @@
+---
+layout: base.njk
+title: 使用手册
+description: 岩美酒库管理系统使用手册,覆盖入库、出库、库存、财务等全功能操作说明。
+pageExtraCss: /assets/docs.css
+---
+
+
+
+
+
+
+
+
+
+ ⌘K
+
+
+
+
+ 版本
+ v{{ changelog[0].version }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {% for chapter in docs.chapters %}
+
+ {{ chapter.num }}. {{ chapter.title }}
+ {{ chapter.html | safe }}
+
+ {% endfor %}
+
+
+
这篇文档对您有帮助吗?
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/download.html b/web/download.html
deleted file mode 100644
index 7c2d996..0000000
--- a/web/download.html
+++ /dev/null
@@ -1,1218 +0,0 @@
-
-
-
-
-
-下载 · 岩美酒库管理系统
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
系统要求
-
- 在以下环境中均经过测试与验证。低于最低要求的环境可能影响功能可用性。
-
-
-
-
-
平台
-
最低要求
-
推荐配置
-
状态
-
-
-
Windows
-
Win 10 · 4GB RAM · 1GB 存储
-
Win 11 · 8GB RAM · SSD
-
已验证
-
-
-
macOS
-
macOS 12 · 4GB RAM
-
macOS 14+ · M1/M2 芯片
-
已验证
-
-
-
iOS
-
iOS 15 · iPhone 8 及以上
-
iOS 17+ · iPhone 12+
-
已验证
-
-
-
Android
-
Android 9 · 3GB RAM
-
Android 13+ · 6GB RAM
-
已验证
-
-
-
Web
-
Chrome 110 · Edge 110 · Safari 15
-
最新版 Chrome / Edge
-
已验证
-
-
-
-
-
-
-
硬件外设支持 · 打印机:USB / 网络 ESC/POS · 标签机:佳博、芯烨、汉印 · 扫码枪:USB / 蓝牙 HID 模式。完整外设兼容列表参见
文档 · 硬件支持。
-
-
-
-
-
-
-
-
-
版本更新日志
-
- 每月一次小版本,每季度一次大更新。完整变更见 GitHub Releases。
-
-
-
-
-
-
-
-
加载中...
-
-
新功能
-
- - 「库存盘点」支持跨仓库联动盘点,一次盘完多仓数据
- - 新增「只读账号」可独立配置导出权限
- - 商品标签支持自定义二维码内容与门店 logo 水印
-
-
-
-
体验改进
-
- - 入库单明细行支持复制上一行,连续录入更快
- - 财务列表新增「往来单位余额」一列
- - 移动端扫码识别速度提升约 30%
-
-
-
-
问题修复
-
- - 修复 macOS 14.4 下打印对话框偶发卡死
- - 修复数据导入时空行被计入失败计数
-
-
-
-
-
-
-
-
-
-
财务模块大幅升级
-
-
新功能
-
- - 财务管理新增「应付应收对账单」模块,按月按往来单位汇总
- - 支持「部分结清」与「批量结清」操作
- - 报表新增损耗趋势分析
-
-
-
-
体验改进
-
- - 侧边栏支持收起与图标导航模式
- - 商品字典三级联动(名称/系列/规格)下拉响应更顺滑
-
-
-
-
-
-
-
-
-
-
稳定性更新
-
-
问题修复
-
- - 修复连续高频提交单据时的偶发重复编号问题
- - 修复 Windows 7 系统下中文输入法弹出的兼容问题
- - 提升弱网环境下数据同步的可靠性
-
-
-
-
-
-
-
-
-
-
引入移动端 App
-
-
新功能
-
- - 正式发布 iOS 与 Android 移动端 App
- - 支持蓝牙扫码枪与蓝牙标签打印
- - 离线缓存机制:断网时仍可查询库存与录入单据
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- BETA · 内测通道
-
-
抢先体验下一个版本
-
v1.7 内测包含智能补货建议、AI 单据识别、批次过期预警等新特性。Beta 渠道独立部署,不影响正式环境数据。
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/web/download.njk b/web/download.njk
new file mode 100644
index 0000000..782e1d9
--- /dev/null
+++ b/web/download.njk
@@ -0,0 +1,506 @@
+---
+layout: base.njk
+title: 下载
+description: 下载岩美酒库管理系统,Web 版现已上线,Windows / macOS / iOS / Android 客户端即将推出。
+pageStyle: |
+ /* ── Page header ── */
+ .page-header {
+ padding: 72px 0 56px;
+ background:
+ radial-gradient(700px 360px at 80% 20%, rgba(37, 99, 172, 0.06), transparent 60%),
+ linear-gradient(180deg, #FBFCFD 0%, #FFFFFF 80%);
+ border-bottom: 1px solid var(--border-subtle);
+ }
+ .ph-inner {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 64px;
+ align-items: center;
+ }
+ .ph-eyebrow {
+ font-size: var(--text-xs); font-weight: 600;
+ letter-spacing: 0.12em; color: var(--brand-500);
+ text-transform: uppercase;
+ margin: 0 0 12px;
+ display: flex; align-items: center; gap: 8px;
+ }
+ .ph-eyebrow .version-badge {
+ background: var(--brand-500); color: #fff;
+ padding: 3px 8px; border-radius: var(--radius-sm);
+ font-family: var(--font-mono);
+ letter-spacing: 0.02em; font-size: 11px;
+ }
+ .ph-title {
+ font-size: 44px; font-weight: 700; line-height: 1.15;
+ letter-spacing: var(--tracking-cn-display);
+ color: var(--brand-900); margin: 0 0 18px;
+ }
+ .ph-lead {
+ font-size: var(--text-lg); color: var(--gray-600);
+ line-height: 1.6; margin: 0 0 24px; max-width: 480px;
+ }
+ .ph-meta {
+ display: flex; gap: 24px;
+ font-size: var(--text-sm); color: var(--fg-muted);
+ border-top: 1px solid var(--border-subtle);
+ padding-top: 16px;
+ }
+ .ph-meta-item { display: flex; flex-direction: column; gap: 2px; }
+ .ph-meta-label { font-size: 11px; color: var(--fg-subtle); letter-spacing: 0.04em; }
+ .ph-meta-val { font-size: var(--text-sm); color: var(--gray-800); font-weight: 500; }
+
+ /* ── Auto-detect card ── */
+ .detect-card {
+ background: var(--gray-0);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-md);
+ overflow: hidden;
+ }
+ .detect-card-head {
+ padding: 14px 20px;
+ background: var(--gray-50);
+ border-bottom: 1px solid var(--border-subtle);
+ font-size: var(--text-xs); color: var(--fg-muted);
+ display: flex; justify-content: space-between; align-items: center;
+ }
+ .detect-card-head .head-left { display: flex; align-items: center; gap: 6px; }
+ .detect-card-head .head-left svg { width: 14px; height: 14px; color: var(--success-500); }
+ .detect-card-body {
+ padding: 28px;
+ display: flex; gap: 24px; align-items: center;
+ }
+ .detect-icon {
+ width: 72px; height: 72px;
+ background: var(--brand-50); border-radius: 16px;
+ display: grid; place-items: center;
+ color: var(--brand-500); flex-shrink: 0;
+ }
+ .detect-icon svg { width: 38px; height: 38px; }
+ .detect-info { flex: 1; }
+ .detect-info h3 { margin: 0 0 4px; font-size: var(--text-xl); font-weight: 600; color: var(--brand-900); }
+ .detect-info p { margin: 0; font-size: var(--text-sm); color: var(--fg-muted); }
+ .detect-card-actions { padding: 0 28px 28px; display: flex; gap: 8px; }
+ .detect-card-actions .btn-primary { flex: 1; justify-content: center; }
+
+ /* ── Platform grid ── */
+ .dl-grid {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ gap: 12px;
+ margin-top: 32px;
+ }
+ .dl-card {
+ background: var(--gray-0);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-lg);
+ padding: 20px;
+ display: flex; flex-direction: column;
+ transition: border-color var(--duration-base) var(--ease-standard),
+ box-shadow var(--duration-base) var(--ease-standard);
+ }
+ .dl-card:hover { border-color: var(--brand-300); box-shadow: var(--shadow-sm); }
+ .dl-card.detected { border-color: var(--brand-400); box-shadow: var(--shadow-md); }
+ .dl-card.coming-soon { opacity: 0.65; }
+ .dl-card-icon {
+ width: 48px; height: 48px;
+ background: var(--brand-50); border-radius: var(--radius-md);
+ display: grid; place-items: center; color: var(--brand-500);
+ margin-bottom: 12px;
+ }
+ .dl-card-icon svg { width: 24px; height: 24px; }
+ .dl-card-name { font-size: var(--text-md); font-weight: 600; color: var(--brand-900); margin: 0 0 4px; }
+ .dl-card-desc { font-size: var(--text-xs); color: var(--fg-muted); margin: 0 0 14px; line-height: 1.5; flex: 1; }
+ .dl-status {
+ display: inline-flex; align-items: center; gap: 4px;
+ font-size: 10px; font-weight: 600; letter-spacing: 0.04em;
+ padding: 3px 8px; border-radius: var(--radius-pill); margin-bottom: 12px;
+ }
+ .dl-status.available { background: var(--success-50); color: var(--success-700); }
+ .dl-status.soon { background: var(--gray-100); color: var(--fg-muted); }
+ .dl-card-btn {
+ display: flex; align-items: center; justify-content: center; gap: 6px;
+ height: 34px; padding: 0 14px;
+ border-radius: var(--radius-md);
+ font-size: var(--text-sm); font-weight: 500;
+ border: 1px solid transparent;
+ cursor: pointer; width: 100%;
+ transition: background var(--duration-fast) var(--ease-standard);
+ text-decoration: none;
+ }
+ .dl-card-btn.primary { background: var(--brand-500); color: #fff; }
+ .dl-card-btn.primary:hover { background: var(--brand-600); }
+ .dl-card-btn.disabled {
+ background: var(--gray-100); color: var(--fg-muted);
+ cursor: default; pointer-events: none;
+ border-color: var(--border-subtle);
+ }
+ .dl-card-btn svg { width: 14px; height: 14px; }
+
+ /* ── System requirements (rendered markdown) ── */
+ .sysreq-content h2 {
+ font-size: var(--text-xl); font-weight: 600;
+ color: var(--brand-900); margin: 28px 0 12px;
+ letter-spacing: var(--tracking-cn-display);
+ padding-bottom: 8px;
+ border-bottom: 1px solid var(--border-subtle);
+ }
+ .sysreq-content h2:first-child { margin-top: 0; }
+ .sysreq-content table {
+ width: 100%; border-collapse: collapse;
+ font-size: var(--text-sm); color: var(--gray-800);
+ margin-bottom: 8px;
+ }
+ .sysreq-content th {
+ text-align: left; font-size: 11px; font-weight: 600;
+ letter-spacing: 0.04em; text-transform: uppercase;
+ color: var(--fg-muted); padding: 8px 12px;
+ background: var(--gray-50);
+ border: 1px solid var(--border-subtle);
+ }
+ .sysreq-content td {
+ padding: 10px 12px;
+ border: 1px solid var(--border-subtle);
+ vertical-align: top;
+ }
+ .sysreq-content tr:hover td { background: var(--gray-25); }
+ .sysreq-content p { font-size: var(--text-sm); color: var(--fg-muted); margin: 8px 0 0; }
+
+ /* ── Changelog timeline ── */
+ .changelog {
+ display: grid;
+ grid-template-columns: 180px 1fr;
+ gap: 0;
+ margin-top: 40px;
+ border-left: 1px solid var(--border-subtle);
+ }
+ .changelog-entry { display: contents; }
+ .changelog-meta {
+ padding: 28px 24px 28px 32px;
+ position: relative;
+ border-bottom: 1px solid var(--border-subtle);
+ }
+ .changelog-meta::before {
+ content: '';
+ position: absolute; left: -7px; top: 36px;
+ width: 13px; height: 13px; border-radius: 50%;
+ background: var(--gray-0); border: 3px solid var(--gray-300);
+ }
+ .changelog-entry.current .changelog-meta::before {
+ background: var(--brand-500); border-color: var(--brand-100);
+ box-shadow: 0 0 0 4px var(--brand-50);
+ }
+ .changelog-version {
+ font-family: var(--font-mono); font-size: var(--text-md); font-weight: 600;
+ color: var(--brand-900); margin-bottom: 4px;
+ }
+ .changelog-date { font-size: var(--text-xs); color: var(--fg-muted); }
+ .changelog-tag {
+ display: inline-block; font-size: 10px;
+ background: var(--success-50); color: var(--success-700);
+ padding: 2px 8px; border-radius: var(--radius-pill);
+ font-weight: 500; margin-top: 8px;
+ }
+ .changelog-body {
+ padding: 28px 0 28px 32px;
+ border-bottom: 1px solid var(--border-subtle);
+ border-left: 1px solid var(--border-subtle);
+ margin-left: -1px;
+ }
+ .changelog-entry:last-child .changelog-meta,
+ .changelog-entry:last-child .changelog-body { border-bottom: none; }
+ .changelog-intro {
+ font-size: var(--text-sm); color: var(--gray-700);
+ line-height: 1.6; margin: 0 0 16px;
+ }
+ .changelog-cat { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
+ .changelog-cat-label {
+ font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
+ color: var(--fg-muted); text-transform: uppercase;
+ display: flex; align-items: center; gap: 6px; margin-bottom: 2px;
+ }
+ .changelog-cat-label .dot { width: 6px; height: 6px; border-radius: 50%; }
+ .dot-feature { background: var(--brand-500); }
+ .dot-improve { background: var(--success-500); }
+ .dot-fix { background: var(--warning-500); }
+ .changelog-cat ul {
+ margin: 0; padding: 0; list-style: none;
+ font-size: var(--text-sm); color: var(--gray-700); line-height: 1.6;
+ }
+ .changelog-cat ul li {
+ padding: 3px 0 3px 16px; position: relative;
+ }
+ .changelog-cat ul li::before {
+ content: ''; position: absolute; left: 0; top: 11px;
+ width: 6px; height: 1px; background: var(--gray-400);
+ }
+
+ /* ── Responsive ── */
+ @media (max-width: 1024px) {
+ .ph-inner { grid-template-columns: 1fr; gap: 32px; }
+ .ph-title { font-size: 36px; }
+ .dl-grid { grid-template-columns: repeat(3, 1fr); }
+ .changelog { grid-template-columns: 120px 1fr; }
+ }
+ @media (max-width: 768px) {
+ .dl-grid { grid-template-columns: repeat(2, 1fr); }
+ .page-header { padding: 48px 0 40px; }
+ }
+---
+
+
+
+
+
+
+
+
支持的平台
+
Web 版现已可用,其余平台正在开发中。
+
+
+
+
+
+
+
+
+
系统要求
+
在以下环境中均经过测试与验证。
+
+ {{ sysreq | safe }}
+
+
+
+
+
+
+
+
版本更新日志
+
最近 {{ changelog | length }} 个版本。
+
+
+ {% for entry in changelog %}
+
+
+
+ {% if entry.intro %}
+
{{ entry.intro }}
+ {% endif %}
+ {% for section in entry.sections %}
+
+
+ {% if section.type == "新功能" %}
+ 新功能
+ {% elif section.type == "改进" %}
+ 改进
+ {% elif section.type == "修复" %}
+ 问题修复
+ {% else %}
+ {{ section.type }}
+ {% endif %}
+
+
+ {% for item in section.items %}
+ - {{ item }}
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+
+
+
diff --git a/web/index.html b/web/index.html
deleted file mode 100644
index d6e9b51..0000000
--- a/web/index.html
+++ /dev/null
@@ -1,1860 +0,0 @@
-
-
-
-
-
-
-岩美酒库管理系统 — 为酒行与酒店设计的库存管理平台
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- v1.6
- 新增多仓库联动盘点 ·
- 查看更新
-
-
从入库到出库,
一套系统管到底。
-
- 岩美酒库管理系统,为酒行与酒店设计的库存、审核、财务一体化平台。审核驱动业务流,库存与账款自动同步,五端无缝接入。
-
-
-
-
无需安装
-
30 天免费
-
支持私有部署
-
-
-
-
-
-
-
-
yanmei.app/inventory
-
-
-
-
-
-
-
-
-
库存总量
-
2,816 瓶
-
↑ 4.2% 较上月
-
-
-
库存金额
-
¥486,290
-
↑ 2.8% 较上月
-
-
-
本月入库
-
128 单
-
↑ 12 单
-
-
-
-
-
-
-
-
WT-501-006
-
茅台飞天 53° · 500ml×6
-
A 仓
-
148
-
¥298,400
-
充足
-
-
-
XJ-468-001
-
五粮液第八代 52° · 500ml
-
A 仓
-
92
-
¥92,920
-
充足
-
-
-
XJ-330-024
-
剑南春水晶剑 52° · 500ml×6
-
B 仓
-
12
-
¥4,560
-
偏低
-
-
-
PJ-750-012
-
拉菲传奇波尔多 · 750ml
-
A 仓
-
64
-
¥18,560
-
充足
-
-
-
PJ-700-008
-
轩尼诗 VSOP · 700ml
-
B 仓
-
38
-
¥22,420
-
入库中
-
-
-
-
-
-
-
-
-
-
-
-
入库单已审批
-
RK20260523000007 库存 +24 瓶
生成应付 ¥48,400
-
-
-
-
-
-
-
-
-
-
-
服务各类酒水经营场所
-
-
-
-
-
5端
-
Web / iOS / Android / Win / Mac
-
-
-
-
-
-
-
-
-
核心模块
-
七大模块,覆盖酒水经营全流程
-
- 从商品建档到入库出库、从财务结算到数据导入,岩美一站式承载日常运营。
-
-
-
-
-
-
入库管理
-
审核驱动的入库流程。草稿、提交、审批、库存更新、应付账款生成 — 一气呵成。
-
- - 多商品行明细录入,自动算金额
- - 审批通过即同步库存与应付账款
- - 支持单据打印、商品标签打印
- - 批次号追踪,生产日期可追溯
-
-
-
-
-
-
出库管理
-
出库前自动校验库存,审批通过即扣减库存并生成应收。库存不足,单据无法通过。
-
-
-
-
-
库存管理
-
实时查询每个 SKU 的库存数量、所在仓库、批次。支持全仓盘点与库存流水。
-
-
-
-
-
财务管理
-
审批同步生成应付应收,月度汇总。结清一键完成,可按往来单位筛选导出。
-
-
-
-
-
往来单位
-
供应商与客户统一档案管理。卡号、初始余额、联系信息集中维护。
-
-
-
-
-
基础数据
-
商品名称、系列、规格三级字典,单品数量配置。先建字典,后录单据。
-
-
-
-
-
系统设置
-
用户与权限、多仓库、编号规则、参数与数据导入 — 自助配置,无需开发。
-
-
-
-
-
-
-
-
-
业务流程
-
审核驱动业务流,每一笔交易都可追溯
-
- 从单据录入到库存变动、账款生成,每一步都有清晰状态与经办人记录。
-
-
-
-
-
一张入库单的完整生命周期
-
-
-
1
-
-
录入草稿
-
选择仓库、供应商、入库日期,逐行录入商品明细。系统自动算金额,可随时保存草稿。
-
-
-
-
2
-
-
提交审核
-
确认无误后提交。单据进入「待审核」,此时不可再编辑,保证数据完整。
-
-
-
-
3
-
-
审批通过
-
操作员及以上权限审批。通过后库存自动 +N,同时生成一笔应付账款,账款挂在对应供应商名下。
-
-
-
-
4
-
-
结清账款
-
财务结算时一键「结清」,财务记录由「未结清」变为「已结清」。账目清晰,按月汇总。
-
-
-
-
-
-
-
-
-
RK20260523000007
-
已审批
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
数据洞察
-
把每一瓶酒的进出,转成可分析的数据
-
- 报表自动生成,可按日、按月、按往来单位维度切换。导出 Excel 一键完成。
-
-
-
-
-
-
-
本月财务流水
-
2026 年 5 月 · 应付与应收对比
-
-
-
-
-
-
-
- 应付账款
- 应收账款
-
-
-
-
-
-
-
-
-
-
-
财务汇总自动生成
-
每月应付应收按往来单位、按时间维度自动汇总。无需手工统计,月底一键导出。
-
-
-
-
-
-
损耗趋势可见
-
每次盘点的账实差异自动累计为损耗数据,结合周转率帮你发现异常 SKU。
-
-
-
-
-
-
Excel 进出自由
-
历史数据可批量导入,月度报表可一键导出。与会计、税务系统无缝衔接。
-
-
-
-
-
-
库存预警实时提醒
-
SKU 库存低于阈值,系统在 Web 与移动端同步推送。永远不会错过补货时机。
-
-
-
-
-
-
-
-
-
-
-
安全与权限
-
企业级权限控制,操作可追溯
-
- 四级角色细分权限,每一次单据操作都有经办人记录。数据备份与审批留痕,按合规要求设计。
-
-
-
-
-
-
四级角色
-
超级管理员、管理员、操作员、只读。按岗位分配,最小权限原则。
-
-
-
-
操作审计
-
谁、什么时候、做了什么 — 每一笔单据都有经办人与时间戳。
-
-
-
-
审批留痕
-
审批不可撤销,单据从草稿到结清的每一步状态完整保留。
-
-
-
-
每日备份
-
云端每日自动备份,支持私有部署。数据始终在你的控制下。
-
-
-
-
-
-
角色
-
说明
-
查看
-
录入
-
审批
-
设置
-
-
-
超级管理员
-
系统最高权限,含数据清空
-
-
-
-
-
-
-
管理员
-
门店管理人员,含用户与门店设置
-
-
-
-
-
-
-
操作员
-
日常录入与审核单据
-
-
-
-
-
-
-
只读
-
仅查看,不可修改任何数据
-
-
-
-
-
-
-
-
-
-
-
-
-
价格
-
按门店付费,明码标价
-
- 所有方案均含全功能、五端同步、无限单据、技术支持。仅在用户数、门店数、部署方式上区分。
-
-
-
-
-
入门方案
-
试用版
-
- ¥
- 0
- / 30 天
-
-
体验完整功能,无需绑卡
-
- - 单门店 · 最多 3 用户
- - 全部模块开放
- - Web 端 + 移动端
- - 邮件技术支持
-
-
免费开通
-
-
-
-
标准方案
-
单店版
-
- ¥
- 299
- / 月
-
-
年付折扣 ¥2,988 / 年(约省 ¥600)
-
- - 单门店 · 最多 10 用户
- - 全部模块 + 五端同步
- - 无限单据、无限商品
- - 云端每日备份
- - 工作日 9-18 点支持
-
-
购买
-
-
-
-
企业方案
-
连锁版
-
- 定制
-
-
多门店连锁,含私有部署
-
- - 多门店 · 总部数据汇总
- - 不限用户数
- - 支持私有部署 / 内网
- - SSO 单点登录
- - 7×24 专属客户经理
-
-
联系销售
-
-
-
-
-
-
-
-
-
常见问题
-
购买前常见的问题
-
-
-
-
- 支持哪些操作系统和设备?
-
-
-
- 系统支持 Windows、macOS 桌面客户端,iOS 与 Android 移动 App,以及主流浏览器的 Web 版本。同一账号可在五端同步使用,数据实时更新。
-
-
-
-
-
- 没有网络时还能操作吗?
-
-
-
- 网络中断时,系统会自动切换到离线模式,展示上次加载的缓存数据。库存查询与单据录入可继续,恢复网络后自动同步至云端。审批与生成账款类操作需要网络。
-
-
-
-
-
- 能否从原有 Excel / 旧系统迁移数据?
-
-
-
- 可以。「系统设置 → 数据导入」支持往来单位、商品名称/系列/规格、库存等数据的批量 Excel 导入,按提供的模板填写即可。导入过程中会显示成功条数与失败原因。
-
-
-
-
-
- 审批通过后发现错误,怎么办?
-
-
-
- 审批通过后操作不可撤销。如发现错误,可由具备权限的用户新建反向调整单据(红冲入库 / 红冲出库)来修正库存与账款。这样可以保留完整的审计链。
-
-
-
-
-
- 数据安全如何保障?
-
-
-
- 云端版采用每日自动备份策略,数据传输全程 HTTPS 加密。企业版支持私有部署,数据存放在你自己的服务器,岩美不接触任何业务数据。
-
-
-
-
-
- 可以试用多长时间?
-
-
-
- 标准版提供 30 天免费试用,无需绑定支付方式。试用期可使用全部功能、五端访问。30 天后可继续按月或按年付费,已录入的数据完整保留。
-
-
-
-
-
- 只读账号能做什么?
-
-
-
- 只读账号可查看全部数据,包括单据、库存、财务、报表,并可导出 Excel。但不能新建、修改、审批、删除任何数据。适合财务、税务、审计岗位的查阅需求。
-
-
-
-
-
-
-
-
-
-
-
-
用一杯咖啡的时间,
看看你的酒库到底有多少瓶。
-
30 天免费试用,无需绑卡。任何时间可取消,已录入数据保留 90 天。
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/web/index.njk b/web/index.njk
new file mode 100644
index 0000000..f3183c7
--- /dev/null
+++ b/web/index.njk
@@ -0,0 +1,627 @@
+---
+layout: base.njk
+title: 为酒行与酒店设计的库存管理平台
+description: 岩美酒库管理系统,审核驱动业务流,库存与账款自动同步,五端无缝接入。
+---
+
+
+
+
+
+
+
+ v1.6
+ 新增多仓库联动盘点 ·
+ 查看更新
+
+
从入库到出库,
一套系统管到底。
+
岩美酒库管理系统,为酒行与酒店设计的库存、审核、财务一体化平台。审核驱动业务流,库存与账款自动同步,五端无缝接入。
+
+
+
无需安装
+
30 天免费
+
支持私有部署
+
+
+
+
+
+
+
+
yanmei.app/inventory
+
+
+
+
+
+
+
+
库存总量
+
2,816 瓶
+
↑ 4.2% 较上月
+
+
+
库存金额
+
¥486,290
+
↑ 2.8% 较上月
+
+
+
本月入库
+
128 单
+
↑ 12 单
+
+
+
+
+
+
WT-501-006
茅台飞天 53° · 500ml×6
A 仓
148
¥298,400
充足
+
XJ-468-001
五粮液第八代 52° · 500ml
A 仓
92
¥92,920
充足
+
XJ-330-024
剑南春水晶剑 52° · 500ml×6
B 仓
12
¥4,560
偏低
+
PJ-750-012
拉菲传奇波尔多 · 750ml
A 仓
64
¥18,560
充足
+
PJ-700-008
轩尼诗 VSOP · 700ml
B 仓
38
¥22,420
入库中
+
+
+
+
+
+
+
+
入库单已审批
+
RK20260523000007 库存 +24 瓶
生成应付 ¥48,400
+
+
+
+
+
+
+
+
+
+
+
服务各类酒水经营场所
+
+
+
+
5端
Web / iOS / Android / Win / Mac
+
+
+
+
+
+
+
+
核心模块
+
七大模块,覆盖酒水经营全流程
+
从商品建档到入库出库、从财务结算到数据导入,岩美一站式承载日常运营。
+
+
+
+
入库管理
+
审核驱动的入库流程。草稿、提交、审批、库存更新、应付账款生成 — 一气呵成。
+
+ - 多商品行明细录入,自动算金额
+ - 审批通过即同步库存与应付账款
+ - 支持单据打印、商品标签打印
+ - 批次号追踪,生产日期可追溯
+
+
+
+
+
出库管理
+
出库前自动校验库存,审批通过即扣减库存并生成应收。库存不足,单据无法通过。
+
+
+
+
库存管理
+
实时查询每个 SKU 的库存数量、所在仓库、批次。支持全仓盘点与库存流水。
+
+
+
+
财务管理
+
审批同步生成应付应收,月度汇总。结清一键完成,可按往来单位筛选导出。
+
+
+
+
往来单位
+
供应商与客户统一档案管理。卡号、初始余额、联系信息集中维护。
+
+
+
+
基础数据
+
商品名称、系列、规格三级字典,单品数量配置。先建字典,后录单据。
+
+
+
+
系统设置
+
用户与权限、多仓库、编号规则、参数与数据导入 — 自助配置,无需开发。
+
+
+
+
+
+
+
+
+
业务流程
+
审核驱动业务流,每一笔交易都可追溯
+
从单据录入到库存变动、账款生成,每一步都有清晰状态与经办人记录。
+
+
+
一张入库单的完整生命周期
+
+
1
录入草稿
选择仓库、供应商、入库日期,逐行录入商品明细。系统自动算金额,可随时保存草稿。
+
2
提交审核
确认无误后提交。单据进入「待审核」,此时不可再编辑,保证数据完整。
+
3
审批通过
操作员及以上权限审批。通过后库存自动 +N,同时生成一笔应付账款,账款挂在对应供应商名下。
+
4
结清账款
财务结算时一键「结清」,财务记录由「未结清」变为「已结清」。账目清晰,按月汇总。
+
+
+
+
+
+
RK20260523000007
+
已审批
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
数据洞察
+
把每一瓶酒的进出,转成可分析的数据
+
报表自动生成,可按日、按月、按往来单位维度切换。导出 Excel 一键完成。
+
+
+
+
本月财务流水
2026 年 5 月 · 应付与应收对比
+
+
+
+
+
+ 应付账款
+ 应收账款
+
+
+
+
+
+
+
+
财务汇总自动生成
每月应付应收按往来单位、按时间维度自动汇总。无需手工统计,月底一键导出。
+
+
+
+
损耗趋势可见
每次盘点的账实差异自动累计为损耗数据,结合周转率帮你发现异常 SKU。
+
+
+
+
Excel 进出自由
历史数据可批量导入,月度报表可一键导出。与会计、税务系统无缝衔接。
+
+
+
+
库存预警实时提醒
SKU 库存低于阈值,系统在 Web 与移动端同步推送。永远不会错过补货时机。
+
+
+
+
+
+
+
+
+
+
安全与权限
+
企业级权限控制,操作可追溯
+
四级角色细分权限,每一次单据操作都有经办人记录。数据备份与审批留痕,按合规要求设计。
+
+
四级角色
超级管理员、管理员、操作员、只读。按岗位分配,最小权限原则。
+
操作审计
谁、什么时候、做了什么 — 每一笔单据都有经办人与时间戳。
+
审批留痕
审批不可撤销,单据从草稿到结清的每一步状态完整保留。
+
每日备份
云端每日自动备份,支持私有部署。数据始终在你的控制下。
+
+
+
+
+
+
+
+
+
价格
+
按门店付费,明码标价
+
所有方案均含全功能、五端同步、无限单据、技术支持。仅在用户数、门店数、部署方式上区分。
+
+
+
入门方案
+
试用版
+
¥0/ 30 天
+
体验完整功能,无需绑卡
+
+ - 单门店 · 最多 3 用户
+ - 全部模块开放
+ - Web 端 + 移动端
+ - 邮件技术支持
+
+
免费开通
+
+
+
标准方案
+
单店版
+
¥299/ 月
+
年付折扣 ¥2,988 / 年(约省 ¥600)
+
+ - 单门店 · 最多 10 用户
+ - 全部模块 + 五端同步
+ - 无限单据、无限商品
+ - 云端每日备份
+ - 工作日 9-18 点支持
+
+
购买
+
+
+
企业方案
+
连锁版
+
定制
+
多门店连锁,含私有部署
+
+ - 多门店 · 总部数据汇总
+ - 不限用户数
+ - 支持私有部署 / 内网
+ - SSO 单点登录
+ - 7×24 专属客户经理
+
+
联系销售
+
+
+
+
+
+
+
+
+
常见问题
+
购买前常见的问题
+
+
+ 支持哪些操作系统和设备?
+ 系统支持 Windows、macOS 桌面客户端,iOS 与 Android 移动 App,以及主流浏览器的 Web 版本。同一账号可在五端同步使用,数据实时更新。
+
+
+ 没有网络时还能操作吗?
+ 网络中断时,系统会自动切换到离线模式,展示上次加载的缓存数据。库存查询与单据录入可继续,恢复网络后自动同步至云端。审批与生成账款类操作需要网络。
+
+
+ 能否从原有 Excel / 旧系统迁移数据?
+ 可以。「系统设置 → 数据导入」支持往来单位、商品名称/系列/规格、库存等数据的批量 Excel 导入,按提供的模板填写即可。导入过程中会显示成功条数与失败原因。
+
+
+ 审批通过后发现错误,怎么办?
+ 审批通过后操作不可撤销。如发现错误,可由具备权限的用户新建反向调整单据(红冲入库 / 红冲出库)来修正库存与账款。这样可以保留完整的审计链。
+
+
+ 数据安全如何保障?
+ 云端版采用每日自动备份策略,数据传输全程 HTTPS 加密。企业版支持私有部署,数据存放在你自己的服务器,岩美不接触任何业务数据。
+
+
+ 可以试用多长时间?
+ 标准版提供 30 天免费试用,无需绑定支付方式。试用期可使用全部功能、五端访问。30 天后可继续按月或按年付费,已录入的数据完整保留。
+
+
+ 只读账号能做什么?
+ 只读账号可查看全部数据,包括单据、库存、财务、报表,并可导出 Excel。但不能新建、修改、审批、删除任何数据。适合财务、税务、审计岗位的查阅需求。
+
+
+
+
+
+
+
+
+
+
+
用一杯咖啡的时间,
看看你的酒库到底有多少瓶。
+
30 天免费试用,无需绑卡。任何时间可取消,已录入数据保留 90 天。
+
+
+
+
+
diff --git a/web/package-lock.json b/web/package-lock.json
new file mode 100644
index 0000000..ccb2463
--- /dev/null
+++ b/web/package-lock.json
@@ -0,0 +1,1671 @@
+{
+ "name": "jiu-marketing",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "jiu-marketing",
+ "devDependencies": {
+ "@11ty/eleventy": "^3.0.0",
+ "markdown-it": "^14.2.0"
+ }
+ },
+ "node_modules/@11ty/dependency-tree": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@11ty/dependency-tree/-/dependency-tree-4.0.2.tgz",
+ "integrity": "sha512-RTF6VTZHatYf7fSZBUN3RKwiUeJh5dhWV61gDPrHhQF2/gzruAkYz8yXuvGLx3w3ZBKreGrR+MfYpSVkdbdbLA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@11ty/eleventy-utils": "^2.0.1"
+ }
+ },
+ "node_modules/@11ty/dependency-tree-esm": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@11ty/dependency-tree-esm/-/dependency-tree-esm-2.0.4.tgz",
+ "integrity": "sha512-MYKC0Ac77ILr1HnRJalzKDlb9Z8To3kXQCltx299pUXXUFtJ1RIONtULlknknqW8cLe19DLVgmxVCtjEFm7h0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@11ty/eleventy-utils": "^2.0.7",
+ "acorn": "^8.15.0",
+ "dependency-graph": "^1.0.0",
+ "normalize-path": "^3.0.0"
+ }
+ },
+ "node_modules/@11ty/eleventy": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/@11ty/eleventy/-/eleventy-3.1.5.tgz",
+ "integrity": "sha512-hZ0g6MwZyRxCqXsPm82gIM304LraKbUz3ZmezOSjsqxttZG6cHTib3Qq8QkESJoKwnr+yX1eyfOkPC5/mEgZnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@11ty/dependency-tree": "^4.0.2",
+ "@11ty/dependency-tree-esm": "^2.0.4",
+ "@11ty/eleventy-dev-server": "^2.0.8",
+ "@11ty/eleventy-plugin-bundle": "^3.0.7",
+ "@11ty/eleventy-utils": "^2.0.7",
+ "@11ty/lodash-custom": "^4.17.21",
+ "@11ty/posthtml-urls": "^1.0.2",
+ "@11ty/recursive-copy": "^4.0.4",
+ "@sindresorhus/slugify": "^2.2.1",
+ "bcp-47-normalize": "^2.3.0",
+ "chokidar": "^3.6.0",
+ "debug": "^4.4.3",
+ "dependency-graph": "^1.0.0",
+ "entities": "^6.0.1",
+ "filesize": "^10.1.6",
+ "gray-matter": "^4.0.3",
+ "iso-639-1": "^3.1.5",
+ "js-yaml": "^4.1.1",
+ "kleur": "^4.1.5",
+ "liquidjs": "^10.25.0",
+ "luxon": "^3.7.2",
+ "markdown-it": "^14.1.1",
+ "minimist": "^1.2.8",
+ "moo": "0.5.2",
+ "node-retrieve-globals": "^6.0.1",
+ "nunjucks": "^3.2.4",
+ "picomatch": "^4.0.3",
+ "please-upgrade-node": "^3.2.0",
+ "posthtml": "^0.16.7",
+ "posthtml-match-helper": "^2.0.3",
+ "semver": "^7.7.4",
+ "slugify": "^1.6.8",
+ "tinyglobby": "^0.2.15"
+ },
+ "bin": {
+ "eleventy": "cmd.cjs"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/11ty"
+ }
+ },
+ "node_modules/@11ty/eleventy-dev-server": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/@11ty/eleventy-dev-server/-/eleventy-dev-server-2.0.8.tgz",
+ "integrity": "sha512-15oC5M1DQlCaOMUq4limKRYmWiGecDaGwryr7fTE/oM9Ix8siqMvWi+I8VjsfrGr+iViDvWcH/TVI6D12d93mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@11ty/eleventy-utils": "^2.0.1",
+ "chokidar": "^3.6.0",
+ "debug": "^4.4.0",
+ "finalhandler": "^1.3.1",
+ "mime": "^3.0.0",
+ "minimist": "^1.2.8",
+ "morphdom": "^2.7.4",
+ "please-upgrade-node": "^3.2.0",
+ "send": "^1.1.0",
+ "ssri": "^11.0.0",
+ "urlpattern-polyfill": "^10.0.0",
+ "ws": "^8.18.1"
+ },
+ "bin": {
+ "eleventy-dev-server": "cmd.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/11ty"
+ }
+ },
+ "node_modules/@11ty/eleventy-plugin-bundle": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-bundle/-/eleventy-plugin-bundle-3.0.7.tgz",
+ "integrity": "sha512-QK1tRFBhQdZASnYU8GMzpTdsMMFLVAkuU0gVVILqNyp09xJJZb81kAS3AFrNrwBCsgLxTdWHJ8N64+OTTsoKkA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@11ty/eleventy-utils": "^2.0.2",
+ "debug": "^4.4.0",
+ "posthtml-match-helper": "^2.0.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/11ty"
+ }
+ },
+ "node_modules/@11ty/eleventy-utils": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@11ty/eleventy-utils/-/eleventy-utils-2.0.7.tgz",
+ "integrity": "sha512-6QE+duqSQ0GY9rENXYb4iPR4AYGdrFpqnmi59tFp9VrleOl0QSh8VlBr2yd6dlhkdtj7904poZW5PvGr9cMiJQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/11ty"
+ }
+ },
+ "node_modules/@11ty/lodash-custom": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/@11ty/lodash-custom/-/lodash-custom-4.17.21.tgz",
+ "integrity": "sha512-Mqt6im1xpb1Ykn3nbcCovWXK3ggywRJa+IXIdoz4wIIK+cvozADH63lexcuPpGS/gJ6/m2JxyyXDyupkMr5DHw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/11ty"
+ }
+ },
+ "node_modules/@11ty/posthtml-urls": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@11ty/posthtml-urls/-/posthtml-urls-1.0.3.tgz",
+ "integrity": "sha512-1YvhnkaNlFnnJic1rBMWmTC2adbuy+JQiBfl1Hecr1Wjjik1pQZmGyk/eC9zKX/FQv52s2Nht1Gi/UwhYqrBeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "evaluate-value": "^2.0.0",
+ "http-equiv-refresh": "^2.0.1",
+ "list-to-array": "^1.1.0",
+ "parse-srcset": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@11ty/recursive-copy": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@11ty/recursive-copy/-/recursive-copy-4.0.4.tgz",
+ "integrity": "sha512-oI7m8pa7/IAU/3lqRU9vjBbs20iKFo7x+1K9kT3aVira6scc1X9MjBdgLCHzLJeJ7iB6wydioA+kr9/qPnvmlQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "errno": "^1.0.0",
+ "junk": "^3.1.0",
+ "minimatch": "^3.1.5",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sindresorhus/slugify": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz",
+ "integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/transliterate": "^1.0.0",
+ "escape-string-regexp": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@sindresorhus/transliterate": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz",
+ "integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/a-sync-waterfall": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
+ "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.5",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
+ "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.11.0"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/anymatch/node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/bcp-47": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-2.1.0.tgz",
+ "integrity": "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-alphabetical": "^2.0.0",
+ "is-alphanumerical": "^2.0.0",
+ "is-decimal": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/bcp-47-match": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz",
+ "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/bcp-47-normalize": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/bcp-47-normalize/-/bcp-47-normalize-2.3.0.tgz",
+ "integrity": "sha512-8I/wfzqQvttUFz7HVJgIZ7+dj3vUaIyIxYXaTRP1YWoSDfzt6TUmxaKZeuXR62qBmYr+nvuWINFRl6pZ5DlN4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bcp-47": "^2.0.0",
+ "bcp-47-match": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
+ "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/commander": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+ "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/dependency-graph": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz",
+ "integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+ "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.0",
+ "entities": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/dom-serializer/node_modules/entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+ "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.2.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+ "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^1.0.1",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/errno": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-1.0.0.tgz",
+ "integrity": "sha512-3zV5mFS1E8/1bPxt/B0xxzI1snsg3uSCIh6Zo1qKg6iMw93hzPANk9oBFzSFBFrwuVoQuE3rLoouAUfwOAj1wQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prr": "~1.0.1"
+ },
+ "bin": {
+ "errno": "cli.js"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/esm-import-transformer": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/esm-import-transformer/-/esm-import-transformer-3.0.5.tgz",
+ "integrity": "sha512-1GKLvfuMnnpI75l8c6sHoz0L3Z872xL5akGuBudgqTDPv4Vy6f2Ec7jEMKTxlqWl/3kSvNbHELeimJtnqgYniw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.15.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/evaluate-value": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/evaluate-value/-/evaluate-value-2.0.0.tgz",
+ "integrity": "sha512-VonfiuDJc0z4sOO7W0Pd130VLsXN6vmBWZlrog1mCb/o7o/Nl5Lr25+Kj/nkCCAhG+zqeeGjxhkK9oHpkgTHhQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/filesize": {
+ "version": "10.1.6",
+ "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz",
+ "integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 10.4.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
+ "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "~2.0.2",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/finalhandler/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gray-matter": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
+ "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "js-yaml": "^3.13.1",
+ "kind-of": "^6.0.2",
+ "section-matter": "^1.0.0",
+ "strip-bom-string": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/gray-matter/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/gray-matter/node_modules/js-yaml": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
+ "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
+ "dev": true,
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.2",
+ "domutils": "^2.8.0",
+ "entities": "^3.0.1"
+ }
+ },
+ "node_modules/htmlparser2/node_modules/entities": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/http-equiv-refresh": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-equiv-refresh/-/http-equiv-refresh-2.0.1.tgz",
+ "integrity": "sha512-XJpDL/MLkV3dKwLzHwr2dY05dYNfBNlyPu4STQ8WvKCFdc6vC5tPXuq28of663+gHVg03C+16pHHs/+FmmDjcw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/is-alphabetical": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
+ "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-alphanumerical": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
+ "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-alphabetical": "^2.0.0",
+ "is-decimal": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-decimal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
+ "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-json": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz",
+ "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/iso-639-1": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/iso-639-1/-/iso-639-1-3.1.5.tgz",
+ "integrity": "sha512-gXkz5+KN7HrG0Q5UGqSMO2qB9AsbEeyLP54kF1YrMsIxmu+g4BdB7rflReZTSTZGpfj8wywu6pfPBCylPIzGQA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/junk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
+ "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/linkify-it": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz",
+ "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/markdown-it"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "uc.micro": "^2.0.0"
+ }
+ },
+ "node_modules/liquidjs": {
+ "version": "10.27.0",
+ "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.27.0.tgz",
+ "integrity": "sha512-tw/OA59K7aIBlMKIrKlumr37fiZUheShVHXY8cVctWisgY1p9mc5hreOvlreoS0wTiwlWk14Ya7305c2a/Cg5w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^10.0.0"
+ },
+ "bin": {
+ "liquid": "bin/liquid.js",
+ "liquidjs": "bin/liquid.js"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/liquidjs"
+ }
+ },
+ "node_modules/list-to-array": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/list-to-array/-/list-to-array-1.1.0.tgz",
+ "integrity": "sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/luxon": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz",
+ "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/markdown-it": {
+ "version": "14.2.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz",
+ "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/markdown-it"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "^4.4.0",
+ "linkify-it": "^5.0.1",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.1.0"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.mjs"
+ }
+ },
+ "node_modules/markdown-it/node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/mime": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
+ "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
+ "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/moo": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
+ "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/morphdom": {
+ "version": "2.7.8",
+ "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.8.tgz",
+ "integrity": "sha512-D/fR4xgGUyVRbdMGU6Nejea1RFzYxYtyurG4Fbv2Fi/daKlWKuXGLOdXtl+3eIwL110cI2hz1ZojGICjjFLgTg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-retrieve-globals": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/node-retrieve-globals/-/node-retrieve-globals-6.0.1.tgz",
+ "integrity": "sha512-j0DeFuZ/Wg3VlklfbxUgZF/mdHMTEiEipBb3q0SpMMbHaV3AVfoUQF8UGxh1s/yjqO0TgRZd4Pi/x2yRqoQ4Eg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.14.1",
+ "acorn-walk": "^8.3.4",
+ "esm-import-transformer": "^3.0.3"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nunjucks": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz",
+ "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "a-sync-waterfall": "^1.0.0",
+ "asap": "^2.0.3",
+ "commander": "^5.1.0"
+ },
+ "bin": {
+ "nunjucks-precompile": "bin/precompile"
+ },
+ "engines": {
+ "node": ">= 6.9.0"
+ },
+ "peerDependencies": {
+ "chokidar": "^3.3.0"
+ },
+ "peerDependenciesMeta": {
+ "chokidar": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/nunjucks/node_modules/commander": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
+ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/parse-srcset": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
+ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/please-upgrade-node": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+ "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver-compare": "^1.0.0"
+ }
+ },
+ "node_modules/posthtml": {
+ "version": "0.16.7",
+ "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.7.tgz",
+ "integrity": "sha512-7Hc+IvlQ7hlaIfQFZnxlRl0jnpWq2qwibORBhQYIb0QbNtuicc5ZxvKkVT71HJ4Py1wSZ/3VR1r8LfkCtoCzhw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "posthtml-parser": "^0.11.0",
+ "posthtml-render": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/posthtml-match-helper": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/posthtml-match-helper/-/posthtml-match-helper-2.0.3.tgz",
+ "integrity": "sha512-p9oJgTdMF2dyd7WE54QI1LvpBIkNkbSiiECKezNnDVYhGhD1AaOnAkw0Uh0y5TW+OHO8iBdSqnd8Wkpb6iUqmw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "posthtml": "^0.16.6"
+ }
+ },
+ "node_modules/posthtml-parser": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz",
+ "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "htmlparser2": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/posthtml-render": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz",
+ "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-json": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/section-matter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
+ "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
+ "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/semver-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.3",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.1",
+ "mime-types": "^3.0.2",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slugify": {
+ "version": "1.6.9",
+ "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.9.tgz",
+ "integrity": "sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/ssri": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-11.0.0.tgz",
+ "integrity": "sha512-aZpUoMN/Jj2MqA4vMCeiKGnc/8SuSyHbGSBdgFbZxP8OJGF/lFkIuElzPxsN0q8TQQ+prw3P4EDfB3TBHHgfXw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.3"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/strip-bom-string": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
+ "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/uc.micro": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/urlpattern-polyfill": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz",
+ "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ws": {
+ "version": "8.21.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
+ "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/web/package.json b/web/package.json
new file mode 100644
index 0000000..b13449d
--- /dev/null
+++ b/web/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "jiu-marketing",
+ "private": true,
+ "scripts": {
+ "build": "eleventy",
+ "dev": "eleventy --serve --port=3000"
+ },
+ "devDependencies": {
+ "@11ty/eleventy": "^3.0.0",
+ "markdown-it": "^14.2.0"
+ }
+}