commit c4477bee103e1bf2594934f99c3cb4e2fe0537bc
Author: root <root@hub.scroll.pub>
Date: 2024-12-30 13:36:40 +0000
Subject: Initial commit
diff --git a/body.html b/body.html
new file mode 100644
index 0000000..0c302f3
--- /dev/null
+++ b/body.html
@@ -0,0 +1,67 @@
+<header>
+ <nav>
+ <div class="logo">WorkLog</div>
+ <div class="theme-toggle">
+ <button id="themeToggle" aria-label="Toggle dark mode">🌓</button>
+ </div>
+ </nav>
+</header>
+
+<main>
+ <section class="log-entry">
+ <h2>Quick Log</h2>
+ <div class="editor-container">
+ <div class="toolbar">
+ <button data-command="bold" aria-label="Bold">B</button>
+ <button data-command="italic" aria-label="Italic">I</button>
+ <button data-command="insertUnorderedList" aria-label="Bullet list">•</button>
+ </div>
+ <div id="editor" contenteditable="true" aria-label="Log entry editor"></div>
+ </div>
+ <div class="entry-meta">
+ <input type="text" id="tags" placeholder="Add tags..." aria-label="Add tags">
+ <select id="category" aria-label="Select category">
+ <option value="work">Work</option>
+ <option value="study">Study</option>
+ <option value="project">Project</option>
+ </select>
+ </div>
+ <button id="saveLog" class="primary-button">Save Log</button>
+ </section>
+
+ <section class="logs-view">
+ <h2>Recent Logs</h2>
+ <div class="filters">
+ <input type="text" id="search" placeholder="Search logs..." aria-label="Search logs">
+ <input type="date" id="dateFilter" aria-label="Filter by date">
+ </div>
+ <div id="logsList" class="logs-list"></div>
+ </section>
+
+ <section class="statistics">
+ <h2>Statistics</h2>
+ <div class="stats-grid">
+ <div class="stat-card">
+ <span class="stat-number" id="totalLogs">0</span>
+ <span class="stat-label">Total Logs</span>
+ </div>
+ <div class="stat-card">
+ <span class="stat-number" id="weeklyLogs">0</span>
+ <span class="stat-label">This Week</span>
+ </div>
+ <div class="stat-card">
+ <span class="stat-number" id="streak">0</span>
+ <span class="stat-label">Day Streak</span>
+ </div>
+ </div>
+ </section>
+</main>
+
+<footer>
+ <p>WorkLog - Smart Browser-Based Work Journal</p>
+ <nav>
+ <a href="/privacy">Privacy</a>
+ <a href="/terms">Terms</a>
+ <a href="/help">Help</a>
+ </nav>
+</footer>
\ No newline at end of file
diff --git a/index.scroll b/index.scroll
new file mode 100644
index 0000000..0afedbc
--- /dev/null
+++ b/index.scroll
@@ -0,0 +1,8 @@
+buildHtml
+baseUrl https://worklog.scroll.pub
+metaTags
+editButton /edit.html
+title WorkLog - Smart Browser-Based Work Journal
+style.css
+body.html
+script.js
\ No newline at end of file
diff --git a/prompt.json b/prompt.json
new file mode 100644
index 0000000..ffeaf30
--- /dev/null
+++ b/prompt.json
@@ -0,0 +1,20 @@
+{
+ "id": "msg_016yApr9vuTGpBhL3YrQhpMR",
+ "type": "message",
+ "role": "assistant",
+ "model": "claude-3-5-sonnet-20241022",
+ "content": [
+ {
+ "type": "text",
+ "text": "I'll create a website for this Chrome logging/journaling extension.\n\nSuggested domain: worklog.scroll.pub (simple, memorable, represents the core logging functionality)\n\n---domain---\nworklog.scroll.pub\n---index.scroll---\nbuildHtml\nbaseUrl https://worklog.scroll.pub\nmetaTags\neditButton /edit.html\ntitle WorkLog - Smart Browser-Based Work Journal\nstyle.css\nbody.html\nscript.js\n---body.html---\n<header>\n <nav>\n <div class=\"logo\">WorkLog</div>\n <div class=\"theme-toggle\">\n <button id=\"themeToggle\" aria-label=\"Toggle dark mode\">🌓</button>\n </div>\n </nav>\n</header>\n\n<main>\n <section class=\"log-entry\">\n <h2>Quick Log</h2>\n <div class=\"editor-container\">\n <div class=\"toolbar\">\n <button data-command=\"bold\" aria-label=\"Bold\">B</button>\n <button data-command=\"italic\" aria-label=\"Italic\">I</button>\n <button data-command=\"insertUnorderedList\" aria-label=\"Bullet list\">•</button>\n </div>\n <div id=\"editor\" contenteditable=\"true\" aria-label=\"Log entry editor\"></div>\n </div>\n <div class=\"entry-meta\">\n <input type=\"text\" id=\"tags\" placeholder=\"Add tags...\" aria-label=\"Add tags\">\n <select id=\"category\" aria-label=\"Select category\">\n <option value=\"work\">Work</option>\n <option value=\"study\">Study</option>\n <option value=\"project\">Project</option>\n </select>\n </div>\n <button id=\"saveLog\" class=\"primary-button\">Save Log</button>\n </section>\n\n <section class=\"logs-view\">\n <h2>Recent Logs</h2>\n <div class=\"filters\">\n <input type=\"text\" id=\"search\" placeholder=\"Search logs...\" aria-label=\"Search logs\">\n <input type=\"date\" id=\"dateFilter\" aria-label=\"Filter by date\">\n </div>\n <div id=\"logsList\" class=\"logs-list\"></div>\n </section>\n\n <section class=\"statistics\">\n <h2>Statistics</h2>\n <div class=\"stats-grid\">\n <div class=\"stat-card\">\n <span class=\"stat-number\" id=\"totalLogs\">0</span>\n <span class=\"stat-label\">Total Logs</span>\n </div>\n <div class=\"stat-card\">\n <span class=\"stat-number\" id=\"weeklyLogs\">0</span>\n <span class=\"stat-label\">This Week</span>\n </div>\n <div class=\"stat-card\">\n <span class=\"stat-number\" id=\"streak\">0</span>\n <span class=\"stat-label\">Day Streak</span>\n </div>\n </div>\n </section>\n</main>\n\n<footer>\n <p>WorkLog - Smart Browser-Based Work Journal</p>\n <nav>\n <a href=\"/privacy\">Privacy</a>\n <a href=\"/terms\">Terms</a>\n <a href=\"/help\">Help</a>\n </nav>\n</footer>\n---style.css---\n:root {\n --primary: #2563eb;\n --primary-dark: #1d4ed8;\n --bg: #ffffff;\n --text: #1f2937;\n --border: #e5e7eb;\n --card-bg: #f9fafb;\n --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n --radius: 8px;\n}\n\n[data-theme=\"dark\"] {\n --primary: #3b82f6;\n --primary-dark: #2563eb;\n --bg: #111827;\n --text: #f9fafb;\n --border: #374151;\n --card-bg: #1f2937;\n --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);\n}\n\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: system-ui, -apple-system, sans-serif;\n background: var(--bg);\n color: var(--text);\n line-height: 1.5;\n transition: background-color 0.3s, color 0.3s;\n}\n\nheader {\n padding: 1rem;\n border-bottom: 1px solid var(--border);\n background: var(--card-bg);\n}\n\nnav {\n max-width: 1200px;\n margin: 0 auto;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.logo {\n font-size: 1.5rem;\n font-weight: bold;\n background: linear-gradient(45deg, var(--primary), var(--primary-dark));\n -webkit-background-clip: text;\n color: transparent;\n}\n\nmain {\n max-width: 1200px;\n margin: 2rem auto;\n padding: 0 1rem;\n}\n\nsection {\n margin-bottom: 2rem;\n}\n\n.editor-container {\n border: 1px solid var(--border);\n border-radius: var(--radius);\n overflow: hidden;\n}\n\n.toolbar {\n padding: 0.5rem;\n border-bottom: 1px solid var(--border);\n background: var(--card-bg);\n}\n\n.toolbar button {\n padding: 0.25rem 0.5rem;\n margin-right: 0.5rem;\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: var(--bg);\n color: var(--text);\n cursor: pointer;\n}\n\n#editor {\n min-height: 200px;\n padding: 1rem;\n outline: none;\n}\n\n.entry-meta {\n display: flex;\n gap: 1rem;\n margin: 1rem 0;\n}\n\ninput, select {\n padding: 0.5rem;\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: var(--bg);\n color: var(--text);\n}\n\n.primary-button {\n padding: 0.75rem 1.5rem;\n background: var(--primary);\n color: white;\n border: none;\n border-radius: var(--radius);\n cursor: pointer;\n transition: background-color 0.3s;\n}\n\n.primary-button:hover {\n background: var(--primary-dark);\n}\n\n.stats-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 1rem;\n}\n\n.stat-card {\n padding: 1.5rem;\n background: var(--card-bg);\n border-radius: var(--radius);\n box-shadow: var(--shadow);\n text-align: center;\n}\n\n.stat-number {\n font-size: 2rem;\n font-weight: bold;\n color: var(--primary);\n}\n\n.stat-label {\n display: block;\n margin-top: 0.5rem;\n font-size: 0.875rem;\n}\n\nfooter {\n padding: 2rem 1rem;\n background: var(--card-bg);\n text-align: center;\n}\n\nfooter nav {\n margin-top: 1rem;\n justify-content: center;\n gap: 2rem;\n}\n\nfooter a {\n color: var(--text);\n text-decoration: none;\n}\n\n@media (max-width: 768px) {\n .entry-meta {\n flex-direction: column;\n }\n \n .stats-grid {\n grid-template-columns: 1fr;\n }\n}\n---script.js---\ndocument.addEventListener('DOMContentLoaded', () => {\n // Theme Toggle\n const themeToggle = document.getElementById('themeToggle');\n const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');\n \n function setTheme(isDark) {\n document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');\n localStorage.setItem('theme', isDark ? 'dark' : 'light');\n }\n\n themeToggle.addEventListener('click', () => {\n const isDark = document.documentElement.getAttribute('data-theme') === 'dark';\n setTheme(!isDark);\n });\n\n // Rich Text Editor\n const toolbar = document.querySelector('.toolbar');\n toolbar.addEventListener('click', (e) => {\n if (e.target.matches('button[data-command]')) {\n const command = e.target.getAttribute('data-command');\n document.execCommand(command, false, null);\n }\n });\n\n // Save Log\n const saveLog = document.getElementById('saveLog');\n saveLog.addEventListener('click', () => {\n const content = document.getElementById('editor').innerHTML;\n const tags = document.getElementById('tags').value;\n const category = document.getElementById('category').value;\n const timestamp = new Date().toISOString();\n\n const log = {\n content,\n tags: tags.split(',').map(tag => tag.trim()),\n category,\n timestamp\n };\n\n // Store in localStorage for demo\n const logs = JSON.parse(localStorage.getItem('logs') || '[]');\n logs.unshift(log);\n localStorage.setItem('logs', JSON.stringify(logs));\n\n updateLogsList();\n updateStats();\n clearEditor();\n });\n\n function clearEditor() {\n document.getElementById('editor').innerHTML = '';\n document.getElementById('tags').value = '';\n document.getElementById('category').selectedIndex = 0;\n }\n\n function updateLogsList() {\n const logsList = document.getElementById('logsList');\n const logs = JSON.parse(localStorage.getItem('logs') || '[]');\n \n logsList.innerHTML = logs.map(log => `\n <div class=\"log-item\">\n <div class=\"log-content\">${log.content}</div>\n <div class=\"log-meta\">\n <span>${new Date(log.timestamp).toLocaleDateString()}</span>\n <span>${log.category}</span>\n <span>${log.tags.join(', ')}</span>\n </div>\n </div>\n `).join('');\n }\n\n function updateStats() {\n const logs = JSON.parse(localStorage.getItem('logs') || '[]');\n \n document.getElementById('totalLogs').textContent = logs.length;\n \n const weekAgo = new Date();\n weekAgo.setDate(weekAgo.getDate() - 7);\n const weeklyLogs = logs.filter(log => \n new Date(log.timestamp) > weekAgo\n ).length;\n document.getElementById('weeklyLogs').textContent = weeklyLogs;\n \n // Calculate streak\n let streak = 0;\n let currentDate = new Date();\n while (true) {\n const hasLog = logs.some(log => \n new Date(log.timestamp).toDateString() === currentDate.toDateString()\n );\n if (!hasLog) break;\n streak++;\n currentDate.setDate(currentDate.getDate() - 1);\n }\n document.getElementById('streak').textContent = streak;\n }\n\n // Initial load\n updateLogsList();\n updateStats();\n});\n---end---"
+ }
+ ],
+ "stop_reason": "end_turn",
+ "stop_sequence": null,
+ "usage": {
+ "input_tokens": 1918,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0,
+ "output_tokens": 2978
+ }
+}
\ No newline at end of file
diff --git a/readme.scroll b/readme.scroll
new file mode 100644
index 0000000..a68b491
--- /dev/null
+++ b/readme.scroll
@@ -0,0 +1,2 @@
+# worklog3.scroll.pub
+Website generated by Claude from prompt: Google Chrome 插件需求文档 目标用户 职场人士 需要记录日常工作内容、任务进展和总结。 学生/研究人员 需要记录学习笔记、研究进展和灵感。 自由职业者 需要跟踪项目进展、任务完成情况和时间管理。 核心需求 便捷记录:用户可以快速记录工作内容,无需离开浏览器。 分类整理:支持对日志进行分类、标签化管理,便于后续查找和总结。 数据持久化:日志数据需要安全存储,支持本地存储或云端同步。 总结与回顾:提供总结功能,帮助用户回顾工作进展和成果。 提醒与习惯养成:支持定时提醒用户记录日志,帮助形成习惯。 功能需求 日志记录功能 功能点 快速输入 实现简单输入框,支持快速记录工作内容。 自动保存内容到本地。 富文本支持 使用富文本编辑器,支持加粗、斜体、列表等基本格式化功能。 日期与时间 自动记录日志创建时间,允许用户手动调整。 附件支持 上传图片或文件作为附件,文件大小限制 5MB。 技术实现 <textarea id="log-input" placeholder="输入日志内容..."></textarea> <button id="save-log">保存</button> document.getElementById("save-log").addEventListener("click", () => { const log = document.getElementById("log-input").value; const timestamp = new Date().toISOString(); chrome.storage.local.set({ [timestamp]: log }); }); 分类与标签功能 功能点 分类管理 用户可创建、编辑和删除分类。 提供默认分类(如“未分类”)。 标签管理 支持为每条日志添加多个标签。 技术实现 分类存储: { "categories": ["日常工作", "学习笔记", "项目进展"] } 标签输入库:Tagify 搜索与过滤功能 功能点 关键词搜索 支持通过关键词搜索日志内容。 日期过滤 按日期范围过滤日志。 分类/标签过滤 按分类或标签筛选��志。 技术实现 const logs = await chrome.storage.local.get(null); const filteredLogs = Object.values(logs).filter(log => log.category === selectedCategory); 数据导出功能 功能点 支持导出格式:文本、Markdown 和 Excel。 批量导出:选择多条日志导出。 导出范围:支持按日期范围、分类或标签导出。 技术实现 const exportData = JSON.stringify(logs, null, 2); // 结构化数据 const blob = new Blob([exportData], { type: "application/json" }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = "logs.json"; link.click(); 提醒功能 功能点 定时提醒 提供每日、每周和每月提醒功能。 提醒内容 支持自定义提醒文本。 技术实现 chrome.alarms.create("dailyReminder", { when: Date.now() + 1000 * 60 * 60 * 24 }); chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === "dailyReminder") { chrome.notifications.create("reminder", { title: "日志提醒", message: "请记录今天的工作日志!", type: "basic", iconUrl: "icon.png", }); } }); 数据同步功能 功能点 本地存储 使用 chrome.storage.local 存储日志数据。 云端同步 支持与 Google Drive 或 OneDrive 同步。 技术实现 function uploadToGoogleDrive(file) { fetch("https://www.googleapis.com/upload/drive/v3/files?uploadType=media", { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, }, body: file, }); } 统计与总结功能 功能点 日志统计 统计总日志数量、每日平均日志数量等。 分类统计 按分类统计日志数量。 总结报告 生成每周/每月总结报告,支持导出 PDF。 技术实现 const summaryHtml = ` <h1>本周总结</h1> <p>总日志数量:${totalLogs}</p> <p>最常用分类:${topCategory}</p> `; const blob = new Blob([summaryHtml], { type: "application/pdf" }); const url = URL.createObjectURL(blob); 用户界面设计 功能点 简洁易用 使用直观的界面布局,便于用户快速上手。 主题切换 提供浅色和深色主题切换功能。 技术实现 :root { --background-color: white; } [data-theme="dark"] { --background-color: black; } 技术实现建议 前端技术 使用 HTML/CSS/JavaScript 构建插件界面。 引入 React 或 Vue.js 提高开发效率。 数据存储 使用 chrome.storage.local 存储本地数据。 云同步时,通过 Google Drive 或 OneDrive API 上传文件。 插件开发 定义 manifest.json 文件以描述插件。 使用 background.js 实现后台逻辑。 如需与网页内容交互,使用 content.js。 安全性 加密存储敏感数据。 仅请求必要的权限,保护用户隐私。
\ No newline at end of file
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..1311818
--- /dev/null
+++ b/script.js
@@ -0,0 +1,101 @@
+document.addEventListener('DOMContentLoaded', () => {
+ // Theme Toggle
+ const themeToggle = document.getElementById('themeToggle');
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
+
+ function setTheme(isDark) {
+ document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
+ localStorage.setItem('theme', isDark ? 'dark' : 'light');
+ }
+
+ themeToggle.addEventListener('click', () => {
+ const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
+ setTheme(!isDark);
+ });
+
+ // Rich Text Editor
+ const toolbar = document.querySelector('.toolbar');
+ toolbar.addEventListener('click', (e) => {
+ if (e.target.matches('button[data-command]')) {
+ const command = e.target.getAttribute('data-command');
+ document.execCommand(command, false, null);
+ }
+ });
+
+ // Save Log
+ const saveLog = document.getElementById('saveLog');
+ saveLog.addEventListener('click', () => {
+ const content = document.getElementById('editor').innerHTML;
+ const tags = document.getElementById('tags').value;
+ const category = document.getElementById('category').value;
+ const timestamp = new Date().toISOString();
+
+ const log = {
+ content,
+ tags: tags.split(',').map(tag => tag.trim()),
+ category,
+ timestamp
+ };
+
+ // Store in localStorage for demo
+ const logs = JSON.parse(localStorage.getItem('logs') || '[]');
+ logs.unshift(log);
+ localStorage.setItem('logs', JSON.stringify(logs));
+
+ updateLogsList();
+ updateStats();
+ clearEditor();
+ });
+
+ function clearEditor() {
+ document.getElementById('editor').innerHTML = '';
+ document.getElementById('tags').value = '';
+ document.getElementById('category').selectedIndex = 0;
+ }
+
+ function updateLogsList() {
+ const logsList = document.getElementById('logsList');
+ const logs = JSON.parse(localStorage.getItem('logs') || '[]');
+
+ logsList.innerHTML = logs.map(log => `
+ <div class="log-item">
+ <div class="log-content">${log.content}</div>
+ <div class="log-meta">
+ <span>${new Date(log.timestamp).toLocaleDateString()}</span>
+ <span>${log.category}</span>
+ <span>${log.tags.join(', ')}</span>
+ </div>
+ </div>
+ `).join('');
+ }
+
+ function updateStats() {
+ const logs = JSON.parse(localStorage.getItem('logs') || '[]');
+
+ document.getElementById('totalLogs').textContent = logs.length;
+
+ const weekAgo = new Date();
+ weekAgo.setDate(weekAgo.getDate() - 7);
+ const weeklyLogs = logs.filter(log =>
+ new Date(log.timestamp) > weekAgo
+ ).length;
+ document.getElementById('weeklyLogs').textContent = weeklyLogs;
+
+ // Calculate streak
+ let streak = 0;
+ let currentDate = new Date();
+ while (true) {
+ const hasLog = logs.some(log =>
+ new Date(log.timestamp).toDateString() === currentDate.toDateString()
+ );
+ if (!hasLog) break;
+ streak++;
+ currentDate.setDate(currentDate.getDate() - 1);
+ }
+ document.getElementById('streak').textContent = streak;
+ }
+
+ // Initial load
+ updateLogsList();
+ updateStats();
+});
\ No newline at end of file
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..75c8e81
--- /dev/null
+++ b/style.css
@@ -0,0 +1,175 @@
+:root {
+ --primary: #2563eb;
+ --primary-dark: #1d4ed8;
+ --bg: #ffffff;
+ --text: #1f2937;
+ --border: #e5e7eb;
+ --card-bg: #f9fafb;
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
+ --radius: 8px;
+}
+
+[data-theme="dark"] {
+ --primary: #3b82f6;
+ --primary-dark: #2563eb;
+ --bg: #111827;
+ --text: #f9fafb;
+ --border: #374151;
+ --card-bg: #1f2937;
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: system-ui, -apple-system, sans-serif;
+ background: var(--bg);
+ color: var(--text);
+ line-height: 1.5;
+ transition: background-color 0.3s, color 0.3s;
+}
+
+header {
+ padding: 1rem;
+ border-bottom: 1px solid var(--border);
+ background: var(--card-bg);
+}
+
+nav {
+ max-width: 1200px;
+ margin: 0 auto;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.logo {
+ font-size: 1.5rem;
+ font-weight: bold;
+ background: linear-gradient(45deg, var(--primary), var(--primary-dark));
+ -webkit-background-clip: text;
+ color: transparent;
+}
+
+main {
+ max-width: 1200px;
+ margin: 2rem auto;
+ padding: 0 1rem;
+}
+
+section {
+ margin-bottom: 2rem;
+}
+
+.editor-container {
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ overflow: hidden;
+}
+
+.toolbar {
+ padding: 0.5rem;
+ border-bottom: 1px solid var(--border);
+ background: var(--card-bg);
+}
+
+.toolbar button {
+ padding: 0.25rem 0.5rem;
+ margin-right: 0.5rem;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ background: var(--bg);
+ color: var(--text);
+ cursor: pointer;
+}
+
+#editor {
+ min-height: 200px;
+ padding: 1rem;
+ outline: none;
+}
+
+.entry-meta {
+ display: flex;
+ gap: 1rem;
+ margin: 1rem 0;
+}
+
+input, select {
+ padding: 0.5rem;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ background: var(--bg);
+ color: var(--text);
+}
+
+.primary-button {
+ padding: 0.75rem 1.5rem;
+ background: var(--primary);
+ color: white;
+ border: none;
+ border-radius: var(--radius);
+ cursor: pointer;
+ transition: background-color 0.3s;
+}
+
+.primary-button:hover {
+ background: var(--primary-dark);
+}
+
+.stats-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 1rem;
+}
+
+.stat-card {
+ padding: 1.5rem;
+ background: var(--card-bg);
+ border-radius: var(--radius);
+ box-shadow: var(--shadow);
+ text-align: center;
+}
+
+.stat-number {
+ font-size: 2rem;
+ font-weight: bold;
+ color: var(--primary);
+}
+
+.stat-label {
+ display: block;
+ margin-top: 0.5rem;
+ font-size: 0.875rem;
+}
+
+footer {
+ padding: 2rem 1rem;
+ background: var(--card-bg);
+ text-align: center;
+}
+
+footer nav {
+ margin-top: 1rem;
+ justify-content: center;
+ gap: 2rem;
+}
+
+footer a {
+ color: var(--text);
+ text-decoration: none;
+}
+
+@media (max-width: 768px) {
+ .entry-meta {
+ flex-direction: column;
+ }
+
+ .stats-grid {
+ grid-template-columns: 1fr;
+ }
+}
\ No newline at end of file