diff --git a/docs/superpowers/plans/2026-06-24-tag-add-button-simplify.md b/docs/superpowers/plans/2026-06-24-tag-add-button-simplify.md
new file mode 100644
index 0000000..2bdd492
--- /dev/null
+++ b/docs/superpowers/plans/2026-06-24-tag-add-button-simplify.md
@@ -0,0 +1,679 @@
+# 小程序添加标签按钮简化与自定义弹窗 实现计划
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** 简化编辑资料页"添加"按钮文字、收紧字数限制到 4 字、标签不换行省略号截断、用自定义深色太空主题弹窗组件替换 `uni.showModal`。
+
+**Architecture:** 新建 `TagDialog.vue` 组件支持 input / confirm 双模式,样式与小程序深色太空主题一致;编辑资料页和管理页分别引入该组件,重构 `addCustomTag` 和 `confirmDelete` 从 `uni.showModal` 切换到自定义弹窗;标签样式增加 `white-space: nowrap` 三件套防止换行。
+
+**Tech Stack:** UniApp 3 + Vue 3 Composition API (`
+
+
+```
+
+### Step 2: 提交
+
+```bash
+git add mini-program/src/components/TagDialog.vue
+git commit -m "feat:新增 TagDialog 自定义弹窗组件,深色太空主题样式"
+```
+
+---
+
+## Task 2: 编辑资料页改动(index.vue)
+
+**目标:** 简化添加按钮文字、引入 TagDialog、重构 addCustomTag 用自定义弹窗、字数限制收紧到 4、标签不换行。
+
+**Files:**
+- Modify: `mini-program/src/pages/onboarding/index.vue`
+
+### Step 1: 模板 — 简化按钮文字
+
+修改 `mini-program/src/pages/onboarding/index.vue`。
+
+找到性格标签 panel 末尾占位(约第 146 行):
+
+```html
+ + 添加标签
+```
+
+改为:
+
+```html
+ + 添加
+```
+
+找到兴趣爱好 panel 末尾占位(约第 167 行):
+
+```html
+ + 添加兴趣
+```
+
+改为:
+
+```html
+ + 添加
+```
+
+### Step 2: 模板 — 挂载 TagDialog 组件
+
+找到 `` 和 `` 包裹的页面结构末尾(约第 185-186 行):
+
+```html
+
+
+
+```
+
+在 `` 之后、`` 之前插入 TagDialog 挂载:
+
+```html
+
+
+
+
+
+```
+
+### Step 3: script — 引入组件
+
+找到 import 区(约第 189-193 行):
+
+```javascript
+import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
+import { onShow } from '@dcloudio/uni-app'
+import { useAppStore } from '../../stores/app.js'
+import { useMenuButtonSafeArea } from '../../composables/useMenuButtonSafeArea.js'
+```
+
+在最后一行 import 之后追加:
+
+```javascript
+import TagDialog from '../../components/TagDialog.vue'
+```
+
+### Step 4: script — 新增弹窗响应式状态
+
+找到 `const saving = ref(false)` 这一行(约第 198 行附近,在 `const isEdit = ref(false)` 之后),在其下方追加:
+
+```javascript
+const dialogVisible = ref(false)
+const dialogMode = ref('input')
+const dialogTitle = ref('')
+const dialogPlaceholder = ref('')
+const dialogContent = ref('')
+const dialogInput = ref('')
+const dialogAction = ref(null)
+```
+
+### Step 5: script — 重构 addCustomTag 并新增 handleAddTag / onDialogConfirm / onDialogCancel
+
+找到现有的 `addCustomTag` 函数(约第 410-449 行,从 `/**` 注释到 `}` 结束):
+
+```javascript
+/**
+ * 新增自定义标签(性格标签 / 兴趣爱好通用)
+ * @param {string} type 'personality' 或 'hobby'
+ */
+const addCustomTag = (type) => {
+ const isPersonality = type === 'personality'
+ const library = isPersonality ? form.personalityTagLibrary : form.hobbyLibrary
+ const selected = isPersonality ? form.personalityTags : form.hobbies
+ const title = isPersonality ? '添加性格标签' : '添加兴趣爱好'
+
+ uni.showModal({
+ title,
+ editable: true,
+ placeholderText: '请输入标签(最多8个字符)',
+ success: (res) => {
+ const value = String(res.content || '').trim()
+ if (!res.confirm) return
+ if (!value) {
+ uni.showToast({ title: '请输入标签内容', icon: 'none' })
+ return
+ }
+ if (value.length > 8) {
+ uni.showToast({ title: '标签最多8个字符', icon: 'none' })
+ return
+ }
+ if (library.includes(value)) {
+ uni.showToast({ title: '标签已存在', icon: 'none' })
+ return
+ }
+ // 新标签插入到库数组最前面
+ library.unshift(value)
+ // 若已选未满 5 个,自动加入已选;否则仅提示
+ if (selected.length >= 5) {
+ uni.showToast({ title: '已达上限,仅加入标签库', icon: 'none' })
+ return
+ }
+ selected.push(value)
+ }
+ })
+}
+```
+
+完整替换为以下四个函数:
+
+```javascript
+/**
+ * 打开添加标签弹窗
+ * @param {string} type 'personality' 或 'hobby'
+ */
+const addCustomTag = (type) => {
+ const isPersonality = type === 'personality'
+ dialogMode.value = 'input'
+ dialogTitle.value = isPersonality ? '添加性格标签' : '添加兴趣爱好'
+ dialogPlaceholder.value = '请输入标签(最多4个字)'
+ dialogInput.value = ''
+ dialogAction.value = { kind: 'add', type }
+ dialogVisible.value = true
+}
+
+/**
+ * 处理添加标签的实际逻辑(字数限制 4 字)
+ */
+const handleAddTag = (type, rawValue) => {
+ const value = String(rawValue || '').trim()
+ const isPersonality = type === 'personality'
+ const library = isPersonality ? form.personalityTagLibrary : form.hobbyLibrary
+ const selected = isPersonality ? form.personalityTags : form.hobbies
+
+ if (!value) {
+ uni.showToast({ title: '请输入标签内容', icon: 'none' })
+ return
+ }
+ if (value.length > 4) {
+ uni.showToast({ title: '内容不能超过4个字', icon: 'none' })
+ return
+ }
+ if (library.includes(value)) {
+ uni.showToast({ title: '标签已存在', icon: 'none' })
+ return
+ }
+ // 新标签插入到库数组最前面
+ library.unshift(value)
+ // 若已选未满 5 个,自动加入已选;否则仅提示
+ if (selected.length >= 5) {
+ uni.showToast({ title: '已达上限,仅加入标签库', icon: 'none' })
+ return
+ }
+ selected.push(value)
+}
+
+/**
+ * 弹窗确认回调
+ */
+const onDialogConfirm = (value) => {
+ const action = dialogAction.value
+ if (!action) return
+ if (action.kind === 'add') {
+ handleAddTag(action.type, value)
+ }
+ dialogAction.value = null
+ dialogVisible.value = false
+}
+
+/**
+ * 弹窗取消回调
+ */
+const onDialogCancel = () => {
+ dialogAction.value = null
+ dialogVisible.value = false
+}
+```
+
+### Step 6: 样式 — .tag-choice 不换行
+
+找到 `.tag-choice` 样式(约第 1008-1011 行):
+
+```css
+.tag-choice {
+ height: 40rpx;
+ font-size: 21rpx;
+}
+```
+
+改为:
+
+```css
+.tag-choice {
+ height: 40rpx;
+ font-size: 21rpx;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+```
+
+### Step 7: 提交
+
+```bash
+git add mini-program/src/pages/onboarding/index.vue
+git commit -m "feat:编辑页添加按钮简化为添加,字数限制4字,标签不换行,接入自定义弹窗"
+```
+
+---
+
+## Task 3: 管理页改动(tag-manage.vue)
+
+**目标:** 引入 TagDialog、重构 confirmDelete 用自定义弹窗、标签文字不换行。
+
+**Files:**
+- Modify: `mini-program/src/pages/onboarding/tag-manage.vue`
+
+### Step 1: 模板 — 挂载 TagDialog 组件
+
+找到 `` 和 `` 包裹的页面结构末尾(约第 44-46 行):
+
+```html
+
+
+
+```
+
+在 `` 之后、`` 之前插入 TagDialog 挂载:
+
+```html
+
+
+
+
+
+```
+
+### Step 2: script — 引入组件
+
+找到 import 区(约第 48-51 行):
+
+```javascript
+import { computed, onMounted, reactive, ref } from 'vue'
+import { useAppStore } from '../../stores/app.js'
+import { useMenuButtonSafeArea } from '../../composables/useMenuButtonSafeArea.js'
+```
+
+在最后一行 import 之后追加:
+
+```javascript
+import TagDialog from '../../components/TagDialog.vue'
+```
+
+### Step 3: script — 新增弹窗响应式状态
+
+找到 `const type = ref('personality')` 这一行(约第 56 行),在其下方追加:
+
+```javascript
+const dialogVisible = ref(false)
+const dialogTitle = ref('确认删除')
+const dialogContent = ref('')
+const pendingTag = ref(null)
+```
+
+### Step 4: script — 重构 confirmDelete 并新增 onDialogConfirm / onDialogCancel
+
+找到现有的 `confirmDelete` 函数(约第 127-139 行):
+
+```javascript
+/**
+ * 删除确认
+ */
+const confirmDelete = (tag) => {
+ uni.showModal({
+ title: '确认删除',
+ content: `确定删除「${tag}」吗?删除后不可恢复`,
+ success: (res) => {
+ if (!res.confirm) return
+ deleteTag(tag)
+ }
+ })
+}
+```
+
+完整替换为以下三个函数:
+
+```javascript
+/**
+ * 打开删除确认弹窗
+ */
+const confirmDelete = (tag) => {
+ pendingTag.value = tag
+ dialogContent.value = `确定删除「${tag}」吗?删除后不可恢复`
+ dialogVisible.value = true
+}
+
+/**
+ * 弹窗确认回调
+ */
+const onDialogConfirm = () => {
+ if (pendingTag.value) {
+ deleteTag(pendingTag.value)
+ pendingTag.value = null
+ }
+ dialogVisible.value = false
+}
+
+/**
+ * 弹窗取消回调
+ */
+const onDialogCancel = () => {
+ pendingTag.value = null
+ dialogVisible.value = false
+}
+```
+
+### Step 5: 样式 — .tag-text 不换行
+
+找到 `.tag-text` 样式(约第 311-314 行):
+
+```css
+.tag-text {
+ color: rgba(255, 255, 255, 0.9);
+ font-size: 26rpx;
+}
+```
+
+改为:
+
+```css
+.tag-text {
+ color: rgba(255, 255, 255, 0.9);
+ font-size: 26rpx;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+```
+
+### Step 6: 提交
+
+```bash
+git add mini-program/src/pages/onboarding/tag-manage.vue
+git commit -m "feat:管理页删除确认接入自定义弹窗,标签文字不换行"
+```
+
+---
+
+## Task 4: H5 浏览器验证
+
+**目标:** 在 H5 模式下验证 spec 的 8 条验收标准。
+
+### Step 1: 确认 H5 dev server 运行
+
+```bash
+python dev-services.py status
+```
+
+确认 `Emotion-museum-uniapp 前端` 状态为 `运行中`(端口 5175)。若未运行:
+
+```bash
+cd mini-program
+npm run dev:h5
+```
+
+### Step 2: 逐条验证验收标准
+
+在浏览器中打开 `http://localhost:5175`,登录后进入编辑资料页(`?edit=1`):
+
+| # | 验收标准 | 验证方法 |
+|---|---|---|
+| 1 | 添加按钮只显示"+ 添加" | 观察性格标签、兴趣爱好 panel 末尾占位文字 |
+| 2 | 点击"+ 添加"弹出深色太空主题弹窗 | 点击按钮,验证弹窗为毛玻璃卡片 + 紫色渐变按钮 + 金色 ✦,非白底蓝按钮 |
+| 3 | 输入 5 字 toast 提示"内容不能超过4个字" | 输入 5 个字点确定,验证 toast 文案 |
+| 4 | 输入 4 字以内新标签,确认后出现在最前 | 输入"测试"点确定,验证标签出现在列表第一位 |
+| 5 | 标签过长时省略号截断不换行 | 输入 4 字标签,观察窄屏下是否单行省略号 |
+| 6 | 管理页删除弹窗为深色主题 | 点"管理"进入管理页,点 × 或左滑,验证弹窗样式与文案 |
+| 7 | 取消按钮和遮罩层点击都能关闭弹窗 | 分别测试取消按钮、点击遮罩层,验证弹窗关闭且不触发动作 |
+| 8 | 弹窗 H5 下样式与深色主题一致 | 整体视觉检查 |
+
+### Step 3: 验收通过后报告
+
+所有 8 条通过后,确认工作区干净:
+
+```bash
+git status
+```
+
+---
+
+## 执行顺序建议
+
+1. Task 1(新建组件)→ Task 2(编辑页接入)→ Task 3(管理页接入)→ Task 4(验证)
+2. Task 1 必须先完成,Task 2/3 依赖组件存在。
+3. Task 2/3 完成后,H5 dev server 热加载自动生效,可直接进入 Task 4 验证。