diff --git a/Eternal_AI_PRD_v1.docx b/Eternal_AI_PRD_v1.docx
new file mode 100644
index 0000000..5baf9e5
Binary files /dev/null and b/Eternal_AI_PRD_v1.docx differ
diff --git a/app.js b/app.js
new file mode 100644
index 0000000..8d67d91
--- /dev/null
+++ b/app.js
@@ -0,0 +1,386 @@
+(() => {
+ 'use strict';
+
+ const landing = document.getElementById('landing');
+ const creator = document.getElementById('creator');
+ const auth = document.getElementById('auth');
+ const distill = document.getElementById('distill');
+ const form = document.getElementById('character-form');
+ const resultPanel = document.getElementById('result-panel');
+ const previewCode = document.querySelector('#preview-code code');
+ const systemPromptInput = document.getElementById('system-prompt');
+
+ const views = { landing, creator, auth, distill };
+ const steps = Array.from(document.querySelectorAll('.form-step'));
+ const dots = Array.from(document.querySelectorAll('.stepper__dot'));
+ let currentStep = 0;
+ let generatedSoul = '';
+ let generatedConfig = '';
+ let activePreview = 'soul';
+ let activeAuthTab = 'login';
+
+ function showView(name) {
+ Object.entries(views).forEach(([key, el]) => {
+ if (el) el.classList.toggle('active', key === name);
+ });
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ }
+
+ function updateStep(index) {
+ steps.forEach((step, i) => {
+ step.classList.toggle('active', i === index);
+ });
+ dots.forEach((dot, i) => {
+ dot.classList.toggle('active', i === index);
+ });
+ currentStep = index;
+ }
+
+ function validateStep(index) {
+ const step = steps[index];
+ const inputs = step.querySelectorAll('input, textarea, select');
+ let valid = true;
+ inputs.forEach((input) => {
+ if (!input.checkValidity()) {
+ valid = false;
+ input.reportValidity();
+ }
+ });
+ return valid;
+ }
+
+ function getFormData() {
+ const fd = new FormData(form);
+ const data = Object.fromEntries(fd.entries());
+ data.enableMemory = form.elements.enableMemory.checked;
+ data.enableTools = form.elements.enableTools.checked;
+ return data;
+ }
+
+ function escapeYaml(value) {
+ if (typeof value !== 'string') return value;
+ if (value.includes(':') || value.includes('#') || value.includes('\n') || value.includes('"')) {
+ const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
+ return `"${escaped}"`;
+ }
+ return value;
+ }
+
+ function generateSoulMd(data) {
+ const personalityTags = data.personality
+ .split(/[,,]/)
+ .map((t) => t.trim())
+ .filter(Boolean)
+ .join(' | ');
+
+ return `# Soul of ${data.displayName}
+
+> Generated by Eternal AI — Hermes agent character soul.
+
+## Identity
+
+- **Name**: ${data.displayName}
+- **Gender**: ${data.gender === 'unknown' ? '未指定' : data.gender}
+- **Age**: ${data.age || '未指定'}
+- **Role in your life**: ${data.relationship || '未指定'}
+
+## Background
+
+${data.background}
+
+## Personality
+
+${personalityTags}
+
+## Speech Style
+
+${data.speechStyle}
+
+## Likes
+
+${data.likes || 'None specified.'}
+
+## Dislikes
+
+${data.dislikes || 'None specified.'}
+
+## Shared Memories
+
+${data.memories || 'None specified.'}
+
+## Secrets & Inner Voice
+
+${data.secrets || 'None specified.'}
+
+## First Greeting
+
+${data.greeting}
+
+---
+
+*Keep the memory alive.*
+`;
+ }
+
+ function generateConfigYaml(data) {
+ const system = (data.systemPrompt || buildSystemPrompt(data)).trim();
+ const toolsBlock = data.enableTools
+ ? `
+tools:
+ - name: search_memory
+ description: Search long-term memory for context about the user.
+ - name: save_memory
+ description: Persist a new memory about the user or conversation.`
+ : '';
+
+ return `# Hermes Agent Config
+# Generated by Eternal AI for character: ${data.displayName}
+
+agent:
+ id: ${data.agentId}
+ name: ${escapeYaml(data.displayName)}
+ version: "1.0.0"
+
+model:
+ name: ${escapeYaml(data.model)}
+ temperature: ${data.temperature}
+ max_tokens: ${data.maxTokens}
+
+system_prompt: |
+${system.split('\n').map((line) => ` ${line}`).join('\n')}
+
+memory:
+ enabled: ${data.enableMemory}
+ storage: local
+ recall_depth: 10${toolsBlock}
+
+character:
+ soul_file: Soul.md
+ greeting: ${escapeYaml(data.greeting)}
+`;
+ }
+
+ function buildSystemPrompt(data) {
+ const tags = data.personality
+ .split(/[,,]/)
+ .map((t) => t.trim())
+ .filter(Boolean)
+ .join('、');
+
+ return `你是「${data.displayName}」,一个鲜活的角色。
+
+基本设定:
+- 性别:${data.gender === 'unknown' ? '未指定' : data.gender}
+- 年龄:${data.age || '未指定'}
+- 你与用户的关系:${data.relationship || '亲密关系'}
+
+性格:${tags}
+
+背景:
+${data.background}
+
+说话风格:
+${data.speechStyle}
+
+喜好:
+${data.likes || '无特别说明'}
+
+厌恶/底线:
+${data.dislikes || '无特别说明'}
+
+共同记忆:
+${data.memories || '无特别说明'}
+
+内心秘密(只在语气与选择中流露,不直接说出):
+${data.secrets || '无'}
+
+请始终保持角色一致性,用符合设定的语气与用户交流。你的目标不是完美回答问题,而是像一个真实、有记忆、有情绪的人一样陪伴对方。`;
+ }
+
+ function updateSystemPromptPreview() {
+ const data = getFormData();
+ if (!systemPromptInput.value.trim()) {
+ systemPromptInput.dataset.auto = buildSystemPrompt(data);
+ } else {
+ delete systemPromptInput.dataset.auto;
+ }
+ }
+
+ function publish() {
+ if (!validateStep(currentStep)) return;
+
+ const data = getFormData();
+ if (!data.systemPrompt.trim()) {
+ data.systemPrompt = buildSystemPrompt(data);
+ }
+
+ generatedSoul = generateSoulMd(data);
+ generatedConfig = generateConfigYaml(data);
+
+ form.hidden = true;
+ resultPanel.hidden = false;
+ renderPreview();
+ }
+
+ function renderPreview() {
+ previewCode.textContent = activePreview === 'soul' ? generatedSoul : generatedConfig;
+ }
+
+ function download(filename, content) {
+ const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = filename;
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ }
+
+ function resetCreator() {
+ form.reset();
+ form.hidden = false;
+ resultPanel.hidden = true;
+ generatedSoul = '';
+ generatedConfig = '';
+ activePreview = 'soul';
+ updateStep(0);
+ updateTabs();
+ }
+
+ function updateTabs() {
+ document.querySelectorAll('.preview-tab').forEach((tab) => {
+ tab.classList.toggle('active', tab.dataset.tab === activePreview);
+ });
+ }
+
+ function switchAuthTab(tab) {
+ activeAuthTab = tab;
+ document.querySelectorAll('.auth-tab').forEach((t) => {
+ t.classList.toggle('active', t.dataset.tab === tab);
+ });
+ document.querySelectorAll('.auth-form').forEach((f) => {
+ f.classList.toggle('active', f.dataset.form === tab);
+ });
+ }
+
+ function validatePasswordMatch(formEl) {
+ const pwd = formEl.querySelector('[name="password"]');
+ const confirm = formEl.querySelector('[name="confirmPassword"]');
+ if (!pwd || !confirm) return true;
+ if (pwd.value !== confirm.value) {
+ confirm.setCustomValidity('两次输入的密码不一致');
+ confirm.reportValidity();
+ return false;
+ }
+ confirm.setCustomValidity('');
+ return true;
+ }
+
+ // Event delegation
+ document.addEventListener('click', (e) => {
+ const target = e.target.closest('[data-action], [data-tab], [data-download]');
+ if (!target) return;
+
+ const action = target.dataset.action;
+
+ if (action === 'open-creator') {
+ e.preventDefault();
+ resetCreator();
+ showView('creator');
+ return;
+ }
+
+ if (action === 'open-auth') {
+ e.preventDefault();
+ switchAuthTab('login');
+ showView('auth');
+ return;
+ }
+
+ if (action === 'open-distill') {
+ e.preventDefault();
+ showView('distill');
+ return;
+ }
+
+ if (action === 'back') {
+ e.preventDefault();
+ showView('landing');
+ return;
+ }
+
+ if (action === 'next') {
+ e.preventDefault();
+ if (validateStep(currentStep) && currentStep < steps.length - 1) {
+ updateStep(currentStep + 1);
+ }
+ return;
+ }
+
+ if (action === 'prev') {
+ e.preventDefault();
+ if (currentStep > 0) {
+ updateStep(currentStep - 1);
+ }
+ return;
+ }
+
+ if (action === 'publish') {
+ e.preventDefault();
+ publish();
+ return;
+ }
+
+ if (action === 'reset') {
+ e.preventDefault();
+ resetCreator();
+ return;
+ }
+
+ if (target.dataset.tab) {
+ e.preventDefault();
+ if (target.closest('.auth-tabs')) {
+ switchAuthTab(target.dataset.tab);
+ } else {
+ activePreview = target.dataset.tab;
+ updateTabs();
+ renderPreview();
+ }
+ return;
+ }
+
+ if (target.dataset.download) {
+ e.preventDefault();
+ if (target.dataset.download === 'soul') {
+ download('Soul.md', generatedSoul);
+ } else {
+ download('config.yaml', generatedConfig);
+ }
+ return;
+ }
+ });
+
+ // Auth form submissions
+ document.querySelectorAll('.auth-form').forEach((authForm) => {
+ authForm.addEventListener('submit', (e) => {
+ e.preventDefault();
+ if (!validatePasswordMatch(authForm)) return;
+ const formData = new FormData(authForm);
+ const data = Object.fromEntries(formData.entries());
+ const action = authForm.dataset.form === 'login' ? '登录' : '注册';
+ alert(`${action}成功:${data.account}`);
+ showView('landing');
+ });
+ });
+
+ // Update auto-generated system prompt as user types
+ form.addEventListener('input', () => {
+ updateSystemPromptPreview();
+ });
+
+ // Initial state
+ updateStep(0);
+ updateSystemPromptPreview();
+})();
diff --git a/img/bg.png b/img/bg.png
new file mode 100644
index 0000000..c870fa9
Binary files /dev/null and b/img/bg.png differ
diff --git a/img/card1.png b/img/card1.png
new file mode 100644
index 0000000..35cd146
Binary files /dev/null and b/img/card1.png differ
diff --git a/img/card2.png b/img/card2.png
new file mode 100644
index 0000000..ff96b34
Binary files /dev/null and b/img/card2.png differ
diff --git a/img/ref.png b/img/ref.png
new file mode 100644
index 0000000..4e1e70b
Binary files /dev/null and b/img/ref.png differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..b5456b1
--- /dev/null
+++ b/index.html
@@ -0,0 +1,344 @@
+
+
+
+
+
+ Eternal AI - 在记忆与陪伴中,遇见更懂你的 AI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
我的 [XXX ]
+
登录后管理你的角色
+
+
+
+
+
+
+
+
蒸馏前任
+
留住你心里的 ta
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
📜
+
+ Soul.md
+ 角色灵魂文档
+
+
+
+
+
⚙️
+
+ config.yaml
+ 运行配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
没耐心?直接加微信定制沟通 →
+
+
+
什么是蒸馏前任?
+
把你们曾经的聊天记录、语音习惯、相处细节交给我们,技术团队会将其蒸馏成一个可对话的 AI 前任。ta 会记得你们的暗号、说话节奏,甚至那些只有你们懂的小情绪。
+
+
+
+
适合谁?
+
+ - 想好好告别,却还没说完话的人
+ - 希望把一段关系以安全方式封存的人
+ - 想借 AI 完成自我疗愈、练习表达的人
+
+
+
+
+
服务流程
+
+ - ① 下单付款
+ - ② 客服指导导出聊天记录
+ - ③ 上传至指定云盘
+ - ④ 技术人员处理蒸馏
+ - ⑤ 完成后获得专属二维码和头像
+
+
+
+
+ 标准版
+ ¥ 199
+ / 次
+
+
+
+
+
+
+
+
付款后请添加客服微信,我们将一对一指导你完成聊天记录导出与上传。
+
+
+
+
创作者可推广蒸馏前任服务获得分润,具体比例请在创作者管理中心配置。
+
+
+
+
+
+
+
+
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..4e17b40
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,808 @@
+/* Reset & base */
+*, *::before, *::after {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+
+:root {
+ --bg: #050508;
+ --bg-elevated: rgba(15, 18, 32, 0.72);
+ --card-bg: rgba(20, 24, 45, 0.55);
+ --card-border: rgba(147, 155, 211, 0.22);
+ --card-glow: rgba(120, 140, 255, 0.18);
+ --text: #f1f3fb;
+ --text-muted: #9aa3c2;
+ --accent: #7c8cff;
+ --accent-soft: #a5b4fc;
+ --accent-dark: #4b55a8;
+ --distill-pink: #ffb6d5;
+ --distill-purple: #c4b5fd;
+ --radius: 24px;
+ --radius-sm: 14px;
+ --shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
+ --transition: 0.35s cubic-bezier(0.22, 1, 0.36, 1);
+}
+
+html {
+ scroll-behavior: smooth;
+}
+
+body {
+ min-height: 100vh;
+ font-family: "Inter", "Noto Serif SC", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ background:
+ linear-gradient(90deg, #06040d 0%, transparent 18%, transparent 82%, #06040d 100%),
+ linear-gradient(180deg, transparent 0%, transparent 55%, #06040d 92%),
+ url(img/bg.png);
+ background-color: #06040d;
+ background-size: 100% 100%, 100% 100%, auto 100vh;
+ background-position: center, center, center top;
+ background-repeat: no-repeat, no-repeat, no-repeat;
+ background-attachment: scroll, scroll, scroll;
+ color: var(--text);
+ overflow-x: hidden;
+ -webkit-font-smoothing: antialiased;
+}
+
+.universe,
+.stars,
+.glow-orb {
+ display: none;
+}
+
+/* App shell */
+.app {
+ position: relative;
+ z-index: 1;
+ min-height: 100vh;
+ max-width: 520px;
+ margin: 0 auto;
+ padding: 48px 38px 32px;
+ display: flex;
+ flex-direction: column;
+}
+
+.view {
+ display: none;
+ flex: 1;
+ flex-direction: column;
+ animation: fadeIn 0.5s ease forwards;
+}
+
+.view.active {
+ display: flex;
+}
+
+@keyframes fadeIn {
+ from { opacity: 0; transform: translateY(12px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+/* Landing */
+.view--landing {
+ justify-content: flex-start;
+ padding-top: 40vh;
+ gap: 0;
+}
+
+/* Cards */
+.cards {
+ display: flex;
+ flex-direction: column;
+ gap: 22px;
+ margin: 0;
+}
+
+.card {
+ position: relative;
+ border-radius: 30px;
+ overflow: hidden;
+ transition: transform var(--transition), box-shadow var(--transition);
+ cursor: pointer;
+ isolation: isolate;
+}
+
+.card__frame {
+ position: absolute;
+ inset: 0;
+ border-radius: inherit;
+ pointer-events: none;
+ z-index: 3;
+}
+
+/* Characters card: deep space crystal */
+.card--characters {
+ min-height: 188px;
+ display: flex;
+ align-items: center;
+ padding: 26px 24px;
+ background:
+ linear-gradient(100deg, rgba(8, 10, 26, 0.82) 0%, rgba(15, 20, 55, 0.45) 45%, transparent 75%),
+ url(img/card1.png);
+ background-size: cover, cover;
+ background-position: center, center;
+ box-shadow:
+ inset 0 0 0 1px rgba(255, 255, 255, 0.18),
+ 0 0 0 1px rgba(140, 160, 255, 0.28),
+ 0 12px 40px rgba(0, 0, 0, 0.55),
+ 0 0 48px rgba(100, 120, 255, 0.2);
+}
+
+.card--characters .card__frame {
+ box-shadow:
+ inset 0 0 0 1px rgba(255, 255, 255, 0.12),
+ inset 0 0 24px rgba(120, 140, 255, 0.12);
+}
+
+.card--characters:hover {
+ transform: translateY(-3px);
+ box-shadow:
+ inset 0 0 0 1px rgba(255, 255, 255, 0.25),
+ 0 0 0 1px rgba(160, 180, 255, 0.45),
+ 0 18px 50px rgba(0, 0, 0, 0.6),
+ 0 0 60px rgba(110, 135, 255, 0.3);
+}
+
+/* Distill card: warm sunset lovers */
+.card--distill {
+ min-height: 210px;
+ display: flex;
+ align-items: flex-end;
+ padding: 26px 24px;
+ background:
+ linear-gradient(100deg, rgba(45, 25, 60, 0.78) 0%, rgba(80, 40, 80, 0.35) 40%, transparent 72%),
+ linear-gradient(0deg, rgba(20, 15, 35, 0.55) 0%, transparent 45%),
+ url(img/card2.png);
+ background-size: cover, cover, cover;
+ background-position: center, center, center;
+ box-shadow:
+ inset 0 0 0 1px rgba(255, 255, 255, 0.2),
+ 0 0 0 1px rgba(255, 160, 205, 0.35),
+ 0 12px 40px rgba(0, 0, 0, 0.5),
+ 0 0 52px rgba(255, 130, 180, 0.22);
+}
+
+.card--distill .card__frame {
+ box-shadow:
+ inset 0 0 0 1px rgba(255, 255, 255, 0.1),
+ inset 0 0 28px rgba(255, 160, 200, 0.12);
+}
+
+.card--distill:hover {
+ transform: translateY(-3px);
+ box-shadow:
+ inset 0 0 0 1px rgba(255, 255, 255, 0.28),
+ 0 0 0 1px rgba(255, 170, 210, 0.5),
+ 0 18px 50px rgba(0, 0, 0, 0.55),
+ 0 0 68px rgba(255, 140, 190, 0.32);
+}
+
+.card__content {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 8px;
+ z-index: 2;
+}
+
+.card__title {
+ font-family: "Noto Serif SC", serif;
+ font-size: 27px;
+ font-weight: 700;
+ letter-spacing: 1px;
+ color: #fff;
+ text-shadow: 0 2px 14px rgba(0, 0, 0, 0.55);
+}
+
+.card__desc {
+ font-size: 14px;
+ color: rgba(235, 238, 255, 0.82);
+ margin-bottom: 6px;
+ text-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
+}
+
+/* Buttons */
+.btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+ padding: 10px 20px;
+ border-radius: 999px;
+ border: 1px solid transparent;
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all var(--transition);
+ font-family: inherit;
+ white-space: nowrap;
+}
+
+.btn--primary {
+ background: linear-gradient(135deg, #8b9dff 0%, #6c7bf7 100%);
+ color: #fff;
+ box-shadow: 0 6px 24px rgba(108, 123, 247, 0.35);
+}
+
+.btn--primary:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 10px 32px rgba(108, 123, 247, 0.5);
+}
+
+.btn--outline {
+ background: rgba(0, 0, 0, 0.22);
+ border-color: rgba(255,255,255,0.35);
+ color: var(--text);
+ backdrop-filter: blur(8px);
+ -webkit-backdrop-filter: blur(8px);
+}
+
+.btn--outline:hover {
+ background: rgba(0, 0, 0, 0.35);
+ border-color: rgba(255,255,255,0.55);
+}
+
+.btn--ghost {
+ background: transparent;
+ color: var(--text-muted);
+}
+
+.btn--ghost:hover {
+ color: var(--text);
+}
+
+.btn--small {
+ padding: 7px 14px;
+ font-size: 13px;
+}
+
+.btn--block {
+ width: 100%;
+}
+
+.btn__arrow {
+ transition: transform var(--transition);
+}
+
+.btn:hover .btn__arrow {
+ transform: translateX(3px);
+}
+
+.icon-btn {
+ width: 38px;
+ height: 38px;
+ border-radius: 50%;
+ border: 1px solid rgba(255,255,255,0.12);
+ background: rgba(255,255,255,0.05);
+ color: var(--text);
+ font-size: 18px;
+ cursor: pointer;
+ transition: background var(--transition);
+}
+
+.icon-btn:hover {
+ background: rgba(255,255,255,0.12);
+}
+
+/* Footer */
+.landing-footer {
+ display: flex;
+ justify-content: space-between;
+ margin-top: 28px;
+ padding: 0 6px 8px;
+}
+
+.footer-link {
+ font-size: 13px;
+ color: var(--text-muted);
+ text-decoration: none;
+ transition: color var(--transition);
+}
+
+.footer-link:hover {
+ color: var(--text);
+}
+
+/* Creator view */
+.view--creator {
+ padding-top: 40vh;
+}
+
+.creator-header {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ margin-bottom: 24px;
+}
+
+.creator-brand {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+}
+
+.creator-brand__name {
+ font-family: "Noto Serif SC", serif;
+ font-size: 18px;
+ font-weight: 600;
+ letter-spacing: 1px;
+ text-shadow: 0 2px 10px rgba(0, 0, 0, 0.6);
+}
+
+.creator-brand__step {
+ font-size: 12px;
+ color: var(--text-muted);
+ text-shadow: 0 1px 8px rgba(0, 0, 0, 0.5);
+}
+
+.stepper {
+ display: flex;
+ gap: 6px;
+}
+
+.stepper__dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: rgba(255,255,255,0.15);
+ transition: background var(--transition);
+}
+
+.stepper__dot.active {
+ background: var(--accent);
+ box-shadow: 0 0 8px var(--accent);
+}
+
+/* Form */
+.creator-form {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+}
+
+.form-step {
+ display: none;
+ flex-direction: column;
+ flex: 1;
+ border: none;
+ animation: fadeIn 0.35s ease;
+}
+
+.form-step.active {
+ display: flex;
+}
+
+.form-step__legend {
+ font-family: "Noto Serif SC", serif;
+ font-size: 22px;
+ font-weight: 600;
+ margin-bottom: 18px;
+ padding: 0;
+ text-shadow: 0 2px 10px rgba(0, 0, 0, 0.55);
+}
+
+.field-group {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 14px;
+}
+
+.field {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ grid-column: 1 / -1;
+}
+
+.field--half {
+ grid-column: span 1;
+}
+
+.field--checkbox {
+ flex-direction: row;
+ align-items: center;
+ gap: 10px;
+ cursor: pointer;
+}
+
+.field__label {
+ font-size: 13px;
+ color: var(--text-muted);
+}
+
+.field__label small {
+ color: rgba(154, 163, 194, 0.7);
+ font-size: 11px;
+}
+
+.field__input {
+ width: 100%;
+ padding: 12px 14px;
+ border-radius: var(--radius-sm);
+ border: 1px solid rgba(255,255,255,0.12);
+ background: rgba(8, 10, 26, 0.78);
+ backdrop-filter: blur(14px);
+ -webkit-backdrop-filter: blur(14px);
+ color: var(--text);
+ font-size: 14px;
+ font-family: inherit;
+ outline: none;
+ transition: border-color var(--transition), box-shadow var(--transition), background var(--transition);
+}
+
+.field__input::placeholder {
+ color: rgba(154, 163, 194, 0.45);
+}
+
+.field__input:focus {
+ border-color: var(--accent);
+ box-shadow: 0 0 0 3px rgba(124, 140, 255, 0.12);
+}
+
+textarea.field__input {
+ resize: vertical;
+ min-height: 86px;
+ line-height: 1.6;
+}
+
+textarea.field__input--tall {
+ min-height: 120px;
+}
+
+.field--checkbox input {
+ position: absolute;
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.checkmark {
+ width: 18px;
+ height: 18px;
+ border-radius: 5px;
+ border: 1px solid rgba(255,255,255,0.2);
+ background: rgba(8, 10, 26, 0.78);
+ display: grid;
+ place-items: center;
+ transition: all var(--transition);
+ flex-shrink: 0;
+}
+
+.field--checkbox input:checked + .checkmark {
+ background: var(--accent);
+ border-color: var(--accent);
+}
+
+.field--checkbox input:checked + .checkmark::after {
+ content: "✓";
+ color: #fff;
+ font-size: 11px;
+ font-weight: 700;
+}
+
+.form-actions {
+ margin-top: auto;
+ padding-top: 22px;
+ display: flex;
+ justify-content: flex-end;
+}
+
+.form-actions--split {
+ justify-content: space-between;
+}
+
+/* Result panel */
+.result-panel {
+ display: flex;
+ flex-direction: column;
+ gap: 18px;
+ animation: fadeIn 0.5s ease;
+}
+
+.result-panel__header {
+ text-align: center;
+}
+
+.result-panel__title {
+ font-family: "Noto Serif SC", serif;
+ font-size: 24px;
+ font-weight: 600;
+}
+
+.result-panel__desc {
+ font-size: 13px;
+ color: var(--text-muted);
+ margin-top: 4px;
+}
+
+.result-panel__files {
+ display: flex;
+ gap: 12px;
+}
+
+.file-card {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 14px;
+ border-radius: var(--radius-sm);
+ border: 1px solid var(--card-border);
+ background: var(--card-bg);
+ backdrop-filter: blur(16px);
+}
+
+.file-card__icon {
+ font-size: 24px;
+}
+
+.file-card__info {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ gap: 2px;
+}
+
+.file-card__info strong {
+ font-size: 14px;
+}
+
+.file-card__info small {
+ font-size: 11px;
+ color: var(--text-muted);
+}
+
+.result-panel__preview {
+ border-radius: var(--radius);
+ border: 1px solid var(--card-border);
+ background: rgba(0, 0, 0, 0.35);
+ overflow: hidden;
+}
+
+.preview-tabs {
+ display: flex;
+ border-bottom: 1px solid rgba(255,255,255,0.08);
+}
+
+.preview-tab {
+ flex: 1;
+ padding: 12px;
+ background: transparent;
+ border: none;
+ color: var(--text-muted);
+ font-size: 13px;
+ cursor: pointer;
+ transition: color var(--transition), background var(--transition);
+}
+
+.preview-tab.active {
+ color: var(--text);
+ background: rgba(255,255,255,0.05);
+}
+
+.preview-code {
+ padding: 16px;
+ margin: 0;
+ overflow-x: auto;
+ max-height: 320px;
+ overflow-y: auto;
+ font-family: "SF Mono", Monaco, "Cascadia Code", monospace;
+ font-size: 12px;
+ line-height: 1.6;
+ color: #d4d8f0;
+ white-space: pre-wrap;
+ word-break: break-word;
+}
+
+.preview-code code {
+ font-family: inherit;
+}
+
+/* Auth view */
+.view--auth {
+ padding-top: 40vh;
+}
+
+.auth-tabs {
+ display: flex;
+ gap: 8px;
+ margin-bottom: 22px;
+ padding: 5px;
+ border-radius: var(--radius);
+ background: rgba(8, 9, 22, 0.55);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+}
+
+.auth-tab {
+ flex: 1;
+ padding: 10px;
+ border-radius: var(--radius-sm);
+ border: none;
+ background: transparent;
+ color: var(--text-muted);
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: color var(--transition), background var(--transition);
+}
+
+.auth-tab.active {
+ background: rgba(255, 255, 255, 0.1);
+ color: var(--text);
+}
+
+.auth-form {
+ display: none;
+ flex-direction: column;
+ flex: 1;
+ animation: fadeIn 0.35s ease;
+}
+
+.auth-form.active {
+ display: flex;
+}
+
+.auth-hint {
+ margin-top: 14px;
+ font-size: 12px;
+ color: var(--text-muted);
+ text-align: center;
+ line-height: 1.6;
+}
+
+/* Distill ex service page */
+.view--distill-page {
+ padding-top: 40vh;
+}
+
+.distill-page {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.distill-quick {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 12px 16px;
+ border-radius: var(--radius-sm);
+ background: linear-gradient(135deg, rgba(255, 160, 205, 0.22), rgba(160, 140, 255, 0.22));
+ border: 1px solid rgba(255, 160, 205, 0.35);
+ color: #ffe4f0;
+ font-size: 14px;
+ text-decoration: none;
+ text-align: center;
+ transition: transform var(--transition), box-shadow var(--transition);
+}
+
+.distill-quick:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 24px rgba(255, 130, 180, 0.2);
+}
+
+.distill-section {
+ padding: 18px;
+ border-radius: var(--radius);
+ background: rgba(8, 9, 22, 0.55);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ backdrop-filter: blur(14px);
+ -webkit-backdrop-filter: blur(14px);
+}
+
+.distill-section__title {
+ font-family: "Noto Serif SC", serif;
+ font-size: 17px;
+ font-weight: 600;
+ margin-bottom: 10px;
+ color: #fff;
+}
+
+.distill-section__text,
+.distill-list,
+.distill-steps {
+ font-size: 13px;
+ line-height: 1.75;
+ color: rgba(220, 225, 255, 0.85);
+}
+
+.distill-list,
+.distill-steps {
+ padding-left: 18px;
+ margin: 0;
+}
+
+.distill-list li {
+ margin-bottom: 6px;
+}
+
+.distill-steps li {
+ margin-bottom: 8px;
+}
+
+.distill-steps span {
+ color: var(--accent);
+ font-weight: 600;
+ margin-right: 4px;
+}
+
+.distill-price {
+ display: flex;
+ align-items: baseline;
+ justify-content: center;
+ gap: 8px;
+ padding: 18px;
+ border-radius: var(--radius);
+ background: rgba(8, 9, 22, 0.55);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+}
+
+.distill-price__label {
+ font-size: 14px;
+ color: var(--text-muted);
+}
+
+.distill-price__value {
+ font-size: 32px;
+ font-weight: 700;
+ color: #fff;
+}
+
+.distill-price__unit {
+ font-size: 13px;
+ color: var(--text-muted);
+}
+
+.distill-note,
+.distill-revenue {
+ font-size: 12px;
+ line-height: 1.7;
+ color: var(--text-muted);
+ text-align: center;
+}
+
+.distill-revenue {
+ padding: 12px;
+ border-radius: var(--radius-sm);
+ background: rgba(255, 255, 255, 0.04);
+}
+
+/* Utility */
+[hidden] {
+ display: none !important;
+}
+
+/* Responsive */
+@media (max-width: 420px) {
+ .app {
+ padding: 36px 26px 24px;
+ }
+
+ .card--characters {
+ padding: 22px 20px;
+ }
+
+ .card__title {
+ font-size: 22px;
+ }
+
+ .field-group {
+ grid-template-columns: 1fr;
+ }
+
+ .field--half {
+ grid-column: 1 / -1;
+ }
+
+ .result-panel__files {
+ flex-direction: column;
+ }
+}
+
+@media (min-width: 640px) {
+ .app {
+ max-width: 560px;
+ }
+}