麦肯锡咨询顾问的真实世界:从项目实战到行业未来

谈笑风生 312 views 2 replies
#2 ·

麦肯锡咨询顾问的真实世界:从项目实战到行业未来

——基于麦肯锡大中华区顾问 Maggie 的深度访谈整理


一、从贝莱德到麦肯锡:一次蓄谋已久的转型

Maggie 的本科经历本身就带有强烈的"全球流动"色彩。她就读于 World Bachelor in Business(全球商业学士)项目,由南加州大学、港科大和意大利博科尼大学三校合办,大一在美国,大二在香港,大三在意大利,毕业时持有三所学校的学位。

高三时她便对咨询行业产生了兴趣——"可以让你感受到很多不同的行业,经常出差,住五星级酒店。这些都是真的,但没有人告诉我会这么累。"本科期间她曾申请咨询实习,因疫情导致名额紧缩未能如愿,最终拿到贝莱德(BlackRock)的 return offer,在香港的可持续投资团队开始了职业生涯。

贝莱德的那一年,团队氛围极为宽松:早上八点半到岗,傍晚六点准时下班,白天甚至需要在日历上给自己"填格子",好让日程看起来不那么空旷。然而正是这种低强度,让她在两到三个月内就确认了一件事:学习曲线不够陡峭,她真正想要的还是咨询。

"你一直很想要一个东西,然后去做了一些跟想象中不太一样的事情,某种程度上反而更加确信了。"2022 年,她社招进入麦肯锡大中华区深圳办公室,专注于消费行业与奢侈酒店领域的人员、组织架构及企业文化方向。贝莱德那一年的经历虽未被计入麦肯锡的 tenure,却赋予了她一种更清醒的自我意识——不再执着于跟同届比绩效、比升职速度,而是更清楚地知道自己要什么。


二、咨询牛马的真实一天

典型的项目日节奏

以"第二天要跟 CEO 开会"为例,一个典型的工作日大致如下:

  • 9:30 团队晨会(team check-in),项目经理与团队对齐当天核心任务。
  • 10:00–12:00 铺开内容:与客户对接,或开始撰写次日汇报的 5 至 10 页 PPT。
  • 12:00–13:30 午餐时间不固定,常被用来跟领导做内部讨论。
  • 14:00–18:00 下午是较完整的产出时间。先与 CEO 的幕僚长或业务负责人做内容对齐("拉通会"),根据反馈修改,再进行麦肯锡内部的 problem solving session(简称 PS,已动词化,"我们 P 一下这个事"即讨论之意)。
  • 18:00–19:00 理想情况下,项目经理将定稿发出,当晚相对轻松。
  • 更常见的情况:领导反馈"故事线差挺多"或"CEO 中午说还想看另外几个点",团队继续修改至晚上八九点。
  • 19:00 团队 check-out——不是下班,而是对齐晚间任务:客户已离场,团队进入相对安静的专注时段,用来前置(frontload)次日工作。
  • 凌晨 12:00–1:00 是项目期间的平均收工时间;遇到极端情况,三四点也并不罕见。

工作时长与节奏

每周工作时长约 80 至 90 小时。与投行不同的是,咨询的周末相对受到保护——周一到周五极度密集,周五傍晚大家各自飞回常驻城市后,基本不再有工作。

出差

出差比例高度取决于个人 base 和客户分布。Maggie 常驻深圳,但 80% 的时间在香港做项目,因此"百分之百在出差"。不过对她而言,朋友和社交圈都在香港,反而不构成负担。她会有意识地优先选择香港项目,待久了再穿插上海、北京、厦门等地的项目,保持新鲜感。


三、组织咨询(P&O):战略落地的"最后一公里"

与战略咨询的关系

在麦肯锡的框架中,组织咨询(People, Organization & Performance)是战略咨询的自然延伸。一个典型的战略项目周期为 6 至 12 周:先做内部诊断(业绩、产品、运营),再做外部对标,最终输出"房子图"式的战略蓝图——顶层是愿景,中间是三到四个业务支柱,底层永远是人员架构、能力建设和数字化基础。

近年来各大咨询公司的趋势是"不再交完 PPT 就走人",而是围绕战略中定义的核心板块,继续做六个月到两三年的转型陪跑。组织架构调整、流程梳理、薪资体系设计、人员培训赋能,都是这一阶段的典型工作。

为什么"人"比"战略"更重要

Maggie 服务过一家体育组织,其新任商业化负责人在规划团队架构时,用了一个足球场的比喻:每个直接下属都是一名明星球员,各守其位,共同目标是把球送进球门。

"每一个新 CEO 上任,永远先要清理的是他底下是一些什么样的兵,能够让他排兵布阵。"战略可以随时调整,但人的流失和能力断层对组织的伤害是长期且不可逆的。这也是 Maggie 选择深耕组织方向的核心原因——能看到实实在在的、落在具体个人身上的变化。


四、真实项目案例

案例一:全球奢华酒店集团的开业流程优化

Maggie 两年前参与了一个为国际顶级酒店集团梳理"从 0 到 1"开业全流程的项目。客户的核心痛点是:每年全球新开数家酒店,却频繁遭遇预算超支、工期延误(9 至 10 个月的 delayed opening 极为常见,甚至烂尾)、以及品质不达标等问题。

她将酒店从无到有的生命周期拆解为五个核心阶段:

  1. Development(开发谈判):多数奢华酒店并不自持物业,而是与业主签署 hotel management agreement,负责经营管理。前期需谈妥选址、条款与管理模式。
  2. Feasibility(可行性测算):确定酒店规模、房间配比、餐厅数量,形成初步蓝图。
  3. Architecture & Construction(设计与施工):这是最"雷"的阶段。工期短则两三年、长则八到十年,需要建立追踪机制,确保与施工方的沟通透明,防止偷工减料。Maggie 在此阶段闹过一个笑话——看到文件里写"hand over your drawings",以为是"把挂在墙上的画移交",查了才知道 drawings 指的是建筑图纸。
  4. Pre-opening(开业筹备):通常半年到一年。人员招聘呈阶梯式:总经理可能提前一两年就位,餐饮和楼面负责人提前半年,而一线服务员和客房清洁人员往往开业前一个半月才到岗——来得越早,人力成本越高,因此最后阶段的培训强度极大。
  5. Open & Ramp-up(正式开业与爬坡):关注开业后的业绩健康爬升,以及早期问题的快速响应机制。

项目的另一条线是人员成本优化:同一城市、同一集团旗下的多家酒店(例如中环与尖沙嘴),哪些部门的人可以合并共享?前台、客房部、餐饮负责人必须驻店,但财务、HR 等中后台岗位存在合并空间。不过,由于酒店是高度依赖人的服务行业,实际节省幅度有限——裁掉一个初级员工,往往要给接管两家酒店的上级加薪,省下的钱很多时候变成了加薪支出。

案例二:国内高端女装品牌的战略重塑

一条裙子卖三五千块、对标奢牌入门价格的国内女装品牌。项目覆盖从品牌定位、产品线设计、渠道策略到营销打法的完整链条。

产品端看得极深:一年分几季,每季分波段上新(线下门店每两到四周换一个波段),不同条线(通勤、晚宴、休闲)的 SKU 占比、上新节奏都需精确规划。Maggie 甚至参与了新一季的审款会,走进设计总监的工作室,看布料、看白模人台上的成衣,看设计师如何从哥特式建筑的镂空结构中汲取面料灵感。

但最出乎意料的发现不在产品端,而在一线执行层。Maggie 和同事做了 mystery shopping(神秘顾客暗访),走进一家商场门店,导购开口的第一句话不是介绍面料或设计理念,而是:"小姐你有会员吗?没有的话我帮你开一个,买一千减五百。"

这完全违背了品牌总部想要传递的高端调性——真正的奢牌店,导购会讲 Loro Piana 的面料、当季的设计灵感、穿上这件衣服会带来的气场。而这位导购为了冲业绩,私自用各种方式打折,甚至扫别的条码、开不同的会员账号来充自己的提成。

"这是上面的战略方向跟底下执行的断层。"品牌要做价值拉升,才能配得上五千到八千的定价,但一线人员的意识和能力如果跟不上,一切品牌叙事都是空谈。


五、咨询顾问的核心价值:不是找答案,而是理清路径

面对"为什么客户愿意花几百万请刚毕业没几年的人来教在行业里摸爬滚打了几十年的高管"这个经典质疑,Maggie 的回答很明确:

"咨询顾问的价值不是帮客户找到正确答案,因为客户永远都知道正确答案。"

客户真正缺的是:不知道怎么走到那里(how to get there),做这件事要付出什么代价,以什么节奏推进,需要花多少钱,意味着什么。公司里没有人能中立地、结构化地把这些事想清楚并铺排出来。

咨询顾问做的几件事:

  • 帮客户摸排清楚所有需要做的决策及其含义;
  • 提供结构化的思考框架(structured thinking);
  • 做行业研究和信息整合;
  • 作为客观中立的第三方,帮客户把模糊的直觉变成可执行的方案。

一位前同事的总结让 Maggie 印象深刻:"咨询顾问就是 10 到 15 年前的 AI。我想了解一个行业,就请一个咨询顾问帮我把这个行业摸透,告诉我市场规模多大,在这里开店还是在那里开店。"

但 AI 无法替代的部分在于:信任关系、情绪价值、担责(accountability),以及帮客户"骑着单车"走过转型期——先一起骑,再在后面扶着后座,最后客户自己骑。


六、AI 时代的咨询行业

工作内容的转变

Maggie 确认,AI 不会消灭咨询顾问这个角色,但会深刻改变日常工作。麦肯锡内部已全面配备 ChatGPT、Cursor 等工具的 license,每人有一定的 token 额度。公司内部还建有基于过往项目知识库的内部 AI 系统(含 MCP 接口),可以检索十年前的行业案例。

效率层面的变化是显著的:research 时间大幅缩短,PPT 制作时间减少(有些客户已接受 HTML 或 dashboard 形式的交付),公司甚至已将"麦肯锡语气写邮件""用七步法拆解问题"等流程做了 AI 征流。

但随之而来的是对人际能力的更高要求。当基础的信息搜集和文档制作被压缩后,咨询顾问的核心价值更加集中在:与客户深度对话、提供判断和视角、驱动客户行动、承担决策责任。

对应届生的能力要求

Maggie 认为 AI 时代做咨询,招聘方会更看重三点:

  1. 学习能力:新技术、新行业、新工具变化极快,持续学习是基本功。
  2. 创新的动手能力:例如用 Cursor 快速搭建一个 HTML 交互界面,让客户在组织架构图上实时拖拽人员、查看薪资变化,而不是对着静态的"box and lines"PPT 干瞪眼。新人在这方面反而有优势。
  3. 赋能客户、驱动客户做事的能力:长期转型项目要求团队真正"铺到客户那边",带着客户的同事一起干活。麦肯锡内部有张照片常被用来培训:十个人站在一起,让人猜哪五个是麦肯锡的、哪五个是客户——理想状态是"分不清"。

麦肯锡内部的 AI 生态

  • 所有主流 AI 工具均有公司 license;
  • 内部知识库接入 MCP,可对话式检索历史项目;
  • 员工可自建 AI 技能(如 HTML 转 PPT、麦肯锡 tone of voice 模板)并上传至公司共享库;
  • 每周都有 AI 相关培训,包括午餐分享会(lunch and learn)和专项深度课程。

七、薪酬与晋升体系

薪酬结构

大中华区的起薪无法对标全球(尤其美国)。分析师(BA)第一年的薪资与国内大厂管培生处于类似区间,约为全球水平的不到 50%。但升到第二级(Associate/Consultant)时,会大幅向全球水平靠拢(达到 80%–90%),第一级与第二级之间的涨幅可达 2 至 3 倍。此后的涨幅回归阶梯式,直到资深合伙人阶段才会有另一个显著跳跃。

晋升路径与时间线

阶段 典型时长
BA → Associate 2.5–3 年
Associate → 项目经理(EM) 1.5–3 年(内部培养上来的更快)
项目经理 → 副合伙人(AP) 2–3 年
副合伙人 → 合伙人(Partner) 2–4 年
合伙人 → 资深合伙人(SP) 极长,有人从 BA 到 Partner 的时间等于从 Partner 到 SP 的时间

Up or Out

这个机制真实存在,但并非网传的那么"恐怖"。每半年做一次绩效评估,表现不佳者会收到口头警告(concerning),但仍有半年时间证明自己可以扭转(turn around)。真正的淘汰更多发生在两到三年的节点上,而非每半年就面临生死。

晋升的关键因素

麦肯锡的评估机制高度依赖 reputation。每半年,一位与你从未合作过的"评估负责人"会逐一电话联系你过去六个月合作过的 6 至 8 位领导,收集反馈,汇总后提交委员会。因此,你的 key sponsors(关键推荐人)是谁、他们在公司的分量如何,直接影响晋升结果。

在同一个客户上待较长时间(8 至 12 个月甚至更久)是加速晋升的有效路径之一——客户对你知根知底,你也对业务了如指掌,领导更愿意让熟悉项目的人承担更大责任。


八、Staffing:一场持续的"内部招聘会"

麦肯锡的项目分配机制被 Maggie 形容为"拿到了一个招聘会的入场券"。每周公司内部会发布未来一到四周新开的项目清单,列明行业、内容、时长、项目经理和领导。顾问需要主动 reach out——给项目领导发邮件、跟自己的 PD(Professional Development Manager,相当于"班主任")表达意愿。

项目最终由项目方决定人选,PD 做系统确认。项目经理在 staff 人之前,会打电话给你之前合作过的同事做"尽职调查";你也可以反向打听这位项目经理的风格。整个机制高度透明。

如何拒绝不想上的项目

麦肯锡的培训甚至会专门教这个问题。核心方法是"yes, no, yes":先感谢机会,再说明客观限制,最后给出替代方案(推荐其他人选、或表示自己项目结束后可以支援)。

更深层的策略是从两个维度表达:

  • Development needs:我过去三个项目都在搭模型,接下来想练客户沟通和概念性思考,所以纯建模的项目不太适合我现阶段。
  • Passion:坦诚地说自己对另一个行业更有热情,并解释为什么。

"你不可能 staff 一个心根本不在项目上、而且非常讨厌这个话题的人。用这个方法基本能解决 80% 的问题。"


九、MBB 三家的风格差异

维度 麦肯锡 BCG 贝恩
气质 最精英、最传统,"领导力工厂" 偏学术,注重话题深度和领域钻研 小而美,时尚精致
强势领域 综合管理、领导力培养 知识创新、行业研究 尽职调查、PE、消费品与奢侈品
文化关键词 Partner potential、成熟度 智识探索 "One Bainie always helps another",互助、校委会式氛围
面试特点 看重人格魅力和领导潜质,case 算错数不一定致命 — 据说 case 算错数直接 hard pass

十、谁不适合做咨询

Maggie 给出了三类画像:

  1. 喜欢稳定性的人:无论是稳定在某座城市还是某家公司,咨询的项目制节奏和频繁出差与此天然冲突。
  2. 只想深钻单一领域的专家型人格:咨询本质上是 generalist(通才)的游戏,需要成为"六边形战士"。虽然麦肯锡有 expert track,但 PhD 式的纵深钻研或二级市场某几家公司的极致跟踪,与咨询的工作方式并不匹配。
  3. 非常不喜欢与人打交道的人:咨询的核心工作就是说话——讨论、说服、与客户高频互动。公司里当然有内向的同事,但工作性质决定了大量 interaction 不可避免。

十一、福利与假期

  • 年假:前两年 15 天,第三年起 20 天,另有病假和每年 5 至 10 天的培训假。
  • 项目间隙的灵活性:没有固定的直线领导(line manager),项目之间的休假非常灵活,休两到三周甚至一个月完全可行。
  • Take Time 政策:每半年可申请额外 15 天无薪假(对应减少那部分工资)。
  • 差旅积分:酒店集团最高会员等级、航空公司里程,是咨询顾问最大的"隐形福利"之一。"出去旅行基本不用现金订酒店,能用积分就用积分。"
  • 企业协议价:公司与酒店和航空公司有商务合约,员工私人出行也可享受折扣。
  • McKinsey Perks:入职第一天就能在公司内网看到的福利专区,涵盖苹果产品折扣、行李箱优惠、健身房等。

十二、反馈文化与职场成长

麦肯锡的反馈机制非常结构化:每个项目结束时有 dedicated 的 one-on-one feedback,也可以每两周主动约团队成员做 one-on-one。

Maggie 分享了两个令她印象深刻的反馈:

第一个来自一位在公司四十年的资深合伙人。开会时年轻顾问们噼里啪啦地用电脑记笔记,这位老人说了一句:"You are here not to take notes."——你来这里不是为了记笔记的。很多这样的小细节,决定了你在董事会会议室里能否赢得话语权。类似的还有:做汇报时站起来讲而不是坐着讲,身体的 presence 会完全不同。

第二个关于晋升节奏。Maggie 想冲更快的升职,收到的反馈是"there is no rush"。她最初理解为"你做得还不够好",后来另一位合伙人帮她重新解读:"你其实走在一条非常好的轨道上(you are on a very promising track),所以不需要急。时间到了,这些事情自然会发生。"在这个公司,是马拉松,不是短跑。很多优秀的分析师升到项目经理会很痛苦,项目经理做得如鱼得水的人再往上又未必适应。


十三、职业出路(Exit Opportunity)

Maggie 观察到,同届入职的同事中已有一半离开,有些升职前走,有些升职后走,并非都是被"up or out",很多人是主动选择。

常见的出路包括:

  • 大厂战略岗:业务战略或战略部门,是最主流的方向。
  • Chief of Staff(幕僚长):适合 junior 一点离开的人,去创业公司或大厂某部门负责人身边,做团队架构规划、战略思考、代为出席部分会议。
  • 海外业务:近年来不少人去了大厂在东南亚、南美等地的海外部门。
  • 甲方高管:更资深级别的去向。
  • PE/投后管理:与咨询的工作性质相似,但换了一个行业和视角。

麦肯锡的校友网络在商业世界中的影响力不容低估。"你去看整个 500 强里有多少 CEO 是麦肯锡的,再看他们底下的减一、减二、减三,可能一条线下来都是麦肯锡的。"一位大学教授曾对 Maggie 说:麦肯锡最大的资源不是你在职时的学习,而是你离开后的影响力。


十四、个人规划:在确定性中保持开放

Maggie 由麦肯锡 sponsor 读 MBA,毕业后将回到公司。但她坦承自己并没有一个清晰的"一定要在某个时间点离开"的计划。

"在麦肯锡,好像每个人都比谁的 exit 更酷。说'我想继续干'好像不是一个特别酷的答案,但我又没觉得它是一个差的路径。"

她更在意的是几个底层维度:工作中保持 mobility(最好能全球出差)、与人深度相关、做赋能和组织领导力方向的事情。至于具体的行业和角色,她选择在哈佛的两年里保持开放。

"之前总觉得一定要进咨询、一定要去 HBS,这些都是我努力规划并且做到了的。但现在有了 safety net,可以更开放地去做探索。"


十五、给年轻人的建议:Passion Mapping 与 Values Mapping

Passion Mapping(热情梳理)

Maggie 在大学时做过一次,申请 MBA 时又做了一次,答案高度一致。方法很简单:

  1. 写下你平时爱做的五件事(喝咖啡、旅行、跑步……)。
  2. 为每件事写出五到八个你喜欢它的原因。
  3. 将大约四十张小卡片做排列组合,找到跨事件的共同驱动力。

例如,喜欢手冲咖啡(探索不同产区的豆子、感受不同风味)和喜欢旅行(感受不同国家的文化、看没看过的风景),背后的 driver 其实是同一个:探索世界和不同文化。用一到一个半小时,可以提炼出三到五条最核心的个人驱动力。

Values Mapping(价值观梳理)

麦肯锡在第一年分析师培训中就会做这个练习:50 张写有 Family、Friendship、Integrity、Money、Achievement、Excellence 等词的卡牌,先筛掉没感觉的(50→25),再筛(25→10),最后排序,选出前 5。

Maggie 的核心排序是:Family、Achievement、Excellence。作为家中长姐,她的 achievement 和 excellence 在某种程度上是服务于家庭的——给两个妹妹做榜样、铺路。初中时的手写笔记留给妹妹参考,妹妹的大学申请表里可以写"姐姐是哈佛毕业的",这些瞬间构成了她"往前走又铺路"的人生叙事。

"很多时候你的所有 action 可能是 fear based 的——小时候成绩不好会被骂,所以要一直考好、找好工作、进好学校。但最终你需要探索的是 value based 的路径。"

关于弱点

"你的弱点也是你保护自己的 self-defense mechanism,有可能是双面性的。核心不是攻克每一个弱点,而是知道自己的 strength 和 weakness 是什么。"

关于冒险

Maggie 坦言自己不是一个天生的 risk taker,过去五到八年基本沿着既定路线执行。如果回到大学,她会更早地尝试创业或不同行业的实习。"国内大家的误区是,如果没做一个'正经的'实习而去做了创业,会不会对长期轨迹有负面影响。但至少从顶尖商学院看中的特质来看,花时间去探索看起来有风险的道路,并不会真的有负面影响。你的每一段经历都是算数的。"

但她同时承认,一个人是否愿意 take risk,很大程度上是性格决定的,而性格受基因和早期家庭环境影响。后天可以训练(比如创业失败一次后,再做一次的勇气会增加),但底色是既定的。


十六、平行宇宙里的另一种人生

如果不做咨询,Maggie 想过两个角色:

  1. Leadership Coach / 企业培训引导师:给不同企业的领导人做领导力培训,或者给高中生大学生做职业探索。
  2. 全职妈妈:长期陪伴教育过程,参与学校家委会或公益机构的管理。

两者并不冲突,核心都是"通过人与人之间的链接和影响,帮助不同的人释放最大的价值"。

回顾从贝莱德到麦肯锡的四五年,她的感受是"非常 fulfilled"——完成了自己给自己定的目标,也在过程中收获了那些"如果你不来做这些项目,根本不会发现的身边的特点"。


本文基于播客节目《100 种职业实验》第 6 期两集内容整理,嘉宾 Maggie(贝莱德→麦肯锡大中华区→哈佛 MBA),主持人黄教练(Brian)。

我虽然行过死荫的幽谷,也不怕遭害,因为你与我同在。
诗篇 23:4

#3 ·
Z
Zethes
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Values Mapping|价值观卡牌漏斗</title>
<style>
  :root{
    --ink:#102638; --muted:#65727d; --paper:#f5f2eb; --card:#fffdf8;
    --line:#d9d5cc; --blue:#163f5f; --blue2:#0f5f78; --accent:#c45b39;
    --good:#2d6f5d; --warn:#986b12; --soft:#e8eef2; --shadow:0 10px 28px rgba(16,38,56,.08);
  }
  *{box-sizing:border-box}
  html{scroll-behavior:smooth}
  body{margin:0;font-family:Inter,"PingFang SC","Microsoft YaHei",system-ui,-apple-system,sans-serif;background:var(--paper);color:var(--ink);line-height:1.55}
  a{color:var(--blue2);text-decoration-thickness:1px;text-underline-offset:3px}
  button,input,textarea{font:inherit}
  .wrap{max-width:1180px;margin:0 auto;padding:28px 22px 70px}
  .hero{background:linear-gradient(130deg,#102f48 0%,#0b2133 68%,#133f52 100%);color:#fff;border-radius:28px;padding:38px;box-shadow:var(--shadow);position:relative;overflow:hidden}
  .hero:after{content:"";position:absolute;right:-90px;top:-90px;width:310px;height:310px;border:1px solid rgba(255,255,255,.14);border-radius:50%;box-shadow:0 0 0 48px rgba(255,255,255,.035),0 0 0 98px rgba(255,255,255,.022)}
  .eyebrow{font-size:12px;letter-spacing:.14em;text-transform:uppercase;font-weight:750;opacity:.78}
  h1{font-size:clamp(34px,5vw,66px);line-height:1.04;margin:10px 0 14px;letter-spacing:-.045em;max-width:850px}
  .lead{font-size:18px;max-width:800px;color:#d7e2ea;margin:0 0 24px}
  .badges{display:flex;flex-wrap:wrap;gap:9px;position:relative;z-index:2}
  .badge{border:1px solid rgba(255,255,255,.25);background:rgba(255,255,255,.08);border-radius:999px;padding:7px 11px;font-size:12px;color:#eef6fb}
  .badge strong{color:#fff}
  .funnel{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:22px;position:relative;z-index:2}
  .funnel .node{border:1px solid rgba(255,255,255,.18);background:rgba(255,255,255,.075);padding:17px;border-radius:16px;min-height:100px}
  .node .n{font-size:34px;font-weight:850;line-height:1}.node b{display:block;margin-top:8px}.node span{font-size:12px;color:#c9d7e0}
  .section{margin-top:24px;background:rgba(255,255,255,.64);border:1px solid var(--line);border-radius:24px;padding:28px;box-shadow:0 8px 24px rgba(16,38,56,.035)}
  .section h2{font-size:24px;margin:0 0 6px;letter-spacing:-.02em}.section p.top{margin:0;color:var(--muted)}
  .research-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:18px}
  .evidence{padding:18px;border-radius:16px;background:var(--card);border:1px solid var(--line)}
  .evidence h3{margin:0 0 8px;font-size:15px}.evidence ul{margin:8px 0 0;padding-left:19px;color:#3d4b56}.evidence li{margin:6px 0}
  .tag{display:inline-block;border-radius:999px;padding:3px 8px;font-size:11px;font-weight:750;margin-right:6px}
  .tag.ok{background:#dfeee8;color:#1f604e}.tag.mid{background:#f2ead5;color:#7c5d12}.tag.no{background:#f1e3de;color:#914528}
  .workspace-head{display:flex;gap:14px;align-items:flex-start;justify-content:space-between;margin-bottom:16px}
  .counter{font-variant-numeric:tabular-nums;background:var(--ink);color:#fff;border-radius:999px;padding:8px 12px;font-weight:750;font-size:13px;white-space:nowrap}
  .instruction{border-left:4px solid var(--accent);padding:10px 14px;background:#fff7f0;border-radius:0 12px 12px 0;color:#5a4037;margin:12px 0 18px}
  .cards{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px}
  .value-card{border:1px solid var(--line);border-radius:15px;background:var(--card);padding:13px;cursor:pointer;min-height:105px;transition:.15s ease;box-shadow:0 2px 8px rgba(16,38,56,.025);text-align:left;color:var(--ink)}
  .value-card:hover{transform:translateY(-1px);border-color:#9aa9b3}
  .value-card.selected{background:#153d5a;color:#fff;border-color:#153d5a;box-shadow:0 8px 18px rgba(21,61,90,.18)}
  .value-card.disabled{opacity:.42;cursor:not-allowed;transform:none}
  .value-card .en{font-weight:800;font-size:14px}.value-card .zh{font-size:13px;margin-top:2px}.value-card .desc{font-size:11px;color:#73808a;margin-top:8px;line-height:1.35}.value-card.selected .desc{color:#cad8e1}
  .actions{display:flex;flex-wrap:wrap;gap:9px;margin-top:18px;align-items:center}
  .btn{border:0;border-radius:12px;padding:10px 15px;font-weight:750;cursor:pointer;background:var(--blue);color:#fff}
  .btn:hover{filter:brightness(1.06)}.btn:disabled{opacity:.35;cursor:not-allowed;filter:none}
  .btn.secondary{background:#e7edf1;color:#17364c}.btn.ghost{background:transparent;border:1px solid var(--line);color:#304550}.btn.danger{background:#803f31}
  .status{font-size:13px;color:var(--muted)}
  .rank-list{display:grid;gap:10px;margin-top:14px}
  .rank-item{display:grid;grid-template-columns:42px 1fr auto;gap:12px;align-items:center;padding:13px 14px;border:1px solid var(--line);background:var(--card);border-radius:14px}
  .rank-num{width:34px;height:34px;border-radius:50%;background:var(--ink);color:#fff;display:grid;place-items:center;font-weight:850}
  .rank-main b{display:block}.rank-main small{color:var(--muted)}
  .rank-controls{display:flex;gap:6px}.iconbtn{border:1px solid var(--line);background:#fff;border-radius:9px;padding:6px 9px;cursor:pointer}.iconbtn:disabled{opacity:.3}
  .reflection{display:grid;gap:12px;margin-top:16px}.reflection-card{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:16px}
  .reflection-card h4{margin:0 0 11px}.form-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px}.field label{display:block;font-size:11px;font-weight:750;color:#60717e;margin-bottom:5px}.field input,.field textarea{width:100%;border:1px solid #cfd5d8;background:#fff;border-radius:10px;padding:10px;color:var(--ink)}.field textarea{min-height:78px;resize:vertical}
  .meta-grid{display:grid;grid-template-columns:1fr 2fr;gap:10px;margin-top:14px}
  .result-box{margin-top:16px;background:#102f48;color:#fff;border-radius:18px;padding:18px}.result-box h3{margin:0 0 10px}.result-top5{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}.result-v{border:1px solid rgba(255,255,255,.18);border-radius:12px;padding:11px;background:rgba(255,255,255,.06)}.result-v b{font-size:13px}.result-v small{display:block;color:#bed0db;margin-top:4px}
  .history{margin-top:16px;overflow:auto}.history table{width:100%;border-collapse:collapse;font-size:13px;background:#fff}.history th,.history td{padding:10px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}.history th{background:#edf2f5;color:#425564}
  .compare{margin-top:14px;padding:15px;border:1px solid #bfd8cf;background:#eef7f3;border-radius:14px;color:#275447}
  .source-list{display:grid;gap:9px;margin-top:15px}.source{padding:13px 14px;border:1px solid var(--line);background:var(--card);border-radius:13px;font-size:13px}.source b{display:block}.source span{color:var(--muted)}
  .fine{font-size:12px;color:var(--muted);margin-top:12px}
  .hidden{display:none!important}
  .toast{position:fixed;right:18px;bottom:18px;background:#0d2d43;color:white;border-radius:12px;padding:11px 14px;box-shadow:var(--shadow);opacity:0;transform:translateY(8px);pointer-events:none;transition:.2s}.toast.show{opacity:1;transform:translateY(0)}
  @media(max-width:960px){.cards{grid-template-columns:repeat(3,1fr)}.research-grid{grid-template-columns:1fr}.form-grid{grid-template-columns:1fr}.result-top5{grid-template-columns:1fr 1fr}.funnel{grid-template-columns:1fr 1fr}}
  @media(max-width:620px){.wrap{padding:14px 12px 50px}.hero,.section{border-radius:19px;padding:20px}.cards{grid-template-columns:1fr 1fr}.meta-grid{grid-template-columns:1fr}.workspace-head{display:block}.counter{display:inline-block;margin-top:10px}.rank-item{grid-template-columns:38px 1fr}.rank-controls{grid-column:2}.result-top5{grid-template-columns:1fr}.funnel{grid-template-columns:1fr 1fr}.node .n{font-size:28px}}
  @media print{body{background:white}.actions,.toast,#practice .cards{display:none!important}.hero,.section{box-shadow:none}.wrap{max-width:none}.hero{background:#fff;color:#111;border:1px solid #bbb}.lead,.node span{color:#555}.funnel .node{border-color:#bbb;background:#fff}.badge{color:#111;border-color:#bbb;background:#fff}}
</style>
</head>
<body>
<div class="wrap">
  <header class="hero">
    <div class="eyebrow">VALUES MAPPING</div>
    <h1>50张价值观卡牌 → Top 5</h1>
    <p class="lead">50 → 25 → 10 → 5</p>
  </header>

  <section class="section" id="practice">
    <div class="workspace-head">
      <div>
        <h2>实操区</h2>
        <p class="top" id="phaseTitle">Step 1|初筛:50 → 25</p>
      </div>
      <div class="counter" id="counter">已选 0 / 25</div>
    </div>
    <div class="instruction" id="instruction">问题:<strong>这个词现在会不会让我有明显的“是,这对我重要”反应?</strong> 不用深入思考。</div>
    <div class="cards" id="cards"></div>
    <div id="ranking" class="hidden"></div>
    <div id="reflection" class="hidden"></div>
    <div class="actions" id="actions"></div>
  </section>

  <section class="section" id="historySection">
    <h2>归档与复测</h2>
    <div class="compare hidden" id="compareBox"></div>
    <div class="history" id="history"></div>
    <div class="actions">
      <button class="btn ghost" id="exportAllBtn">导出全部历史 JSON</button>
      <button class="btn ghost" id="clearHistoryBtn">清空本机历史</button>
    </div>
    <div class="fine">记录仅保存在当前浏览器。</div>
  </section>

</div>
<div class="toast" id="toast"></div>
<script>
const VALUES = [
  {en:'Family',zh:'家庭',desc:'把家人关系、照顾与共同生活放在重要位置'},
  {en:'Friendship',zh:'友情',desc:'维持真诚、可靠、彼此支持的朋友关系'},
  {en:'Love',zh:'爱',desc:'给予并接受深厚的亲密、关怀与情感连接'},
  {en:'Belonging',zh:'归属',desc:'感到被接纳,并与重要的人群真正连结'},
  {en:'Compassion',zh:'慈悲 / 关怀',desc:'理解他人的痛苦,并愿意给予支持'},
  {en:'Service',zh:'服务',desc:'主动帮助他人,解决真实需要'},
  {en:'Generosity',zh:'慷慨',desc:'愿意分享时间、资源、机会与善意'},
  {en:'Trust',zh:'信任',desc:'建立可以坦诚、托付并相互依赖的关系'},
  {en:'Loyalty',zh:'忠诚',desc:'对重要的人、关系或承诺保持坚定'},
  {en:'Respect',zh:'尊重',desc:'认真对待自己与他人的边界、尊严和选择'},
  {en:'Integrity',zh:'正直',desc:'即使有代价,也让行为符合自己的原则'},
  {en:'Authenticity',zh:'真实',desc:'不靠迎合维持形象,按真实自我表达和行动'},
  {en:'Responsibility',zh:'责任',desc:'对承诺、选择、影响与后果负责'},
  {en:'Justice',zh:'公正',desc:'重视权利、机会与规则层面的公平对待'},
  {en:'Humility',zh:'谦逊',desc:'不过度抬高自己,愿意承认局限并向他人学习'},
  {en:'Gratitude',zh:'感恩',desc:'持续看见并珍惜已经拥有的人与事'},
  {en:'Forgiveness',zh:'宽恕',desc:'愿意放下长期怨恨,为关系或自己腾出空间'},
  {en:'Courage',zh:'勇气',desc:'面对风险、冲突或不确定仍选择行动'},
  {en:'Discipline',zh:'自律',desc:'为了长期重要的事持续执行必要行动'},
  {en:'Patience',zh:'耐心',desc:'允许成长和结果需要时间,不被即时回报牵引'},
  {en:'Freedom',zh:'自由',desc:'拥有选择生活方向、表达与行动方式的空间'},
  {en:'Curiosity',zh:'好奇',desc:'主动提问、探索未知并理解不同观点'},
  {en:'Learning',zh:'学习',desc:'持续获得新的知识、技能与理解'},
  {en:'Growth',zh:'成长',desc:'不断拓展自己的能力、成熟度与可能性'},
  {en:'Creativity',zh:'创造',desc:'产生原创想法,并把新的可能变成现实'},
  {en:'Adventure',zh:'冒险',desc:'主动接触新鲜、未知、刺激或有挑战的体验'},
  {en:'Nature',zh:'自然',desc:'珍视与自然环境、生命和生态世界的连接'},
  {en:'Achievement',zh:'成就',desc:'完成有挑战的目标,并取得清晰可见的成果'},
  {en:'Excellence',zh:'卓越',desc:'追求高标准和高质量,而非只求完成'},
  {en:'Mastery',zh:'精通',desc:'在重要领域形成深度能力与专业水准'},
  {en:'Ambition',zh:'进取 / 雄心',desc:'主动争取更大的目标、舞台和发展空间'},
  {en:'Leadership',zh:'领导',desc:'承担方向与责任,组织并带动他人前进'},
  {en:'Influence',zh:'影响力',desc:'能够改变他人的理解、选择或行动'},
  {en:'Recognition',zh:'认可',desc:'希望重要的贡献与能力被看见和肯定'},
  {en:'Money',zh:'财富 / 金钱',desc:'拥有充足的经济资源、购买力与财务选择权'},
  {en:'Security',zh:'安全',desc:'拥有稳定、受保护、可预期的生活基础'},
  {en:'Health',zh:'健康',desc:'维护身体、睡眠、精力与长期生命状态'},
  {en:'Balance',zh:'平衡',desc:'让工作、关系、休息与个人空间保持可持续节奏'},
  {en:'Inner Peace',zh:'内在平静',desc:'保持稳定、清醒、少内耗的内在状态'},
  {en:'Happiness',zh:'幸福',desc:'追求整体上的满足、愉悦与生活满意感'},
  {en:'Fun',zh:'乐趣',desc:'让玩乐、轻松和即时的享受成为生活的一部分'},
  {en:'Beauty',zh:'美',desc:'欣赏或创造审美、和谐、设计与美感'},
  {en:'Faith',zh:'信仰',desc:'相信并遵循超越即时利益的信念或宗教信仰'},
  {en:'Purpose',zh:'意义 / 使命',desc:'让人生有值得投入的方向、理由与意义'},
  {en:'Wisdom',zh:'智慧',desc:'追求成熟判断、洞察与对复杂性的理解'},
  {en:'Tradition',zh:'传统',desc:'珍视文化、家庭或仪式中值得延续的部分'},
  {en:'Order',zh:'秩序',desc:'偏好清晰、结构、规则和井然有序'},
  {en:'Simplicity',zh:'简约',desc:'减少不必要的复杂、占有与干扰'},
  {en:'Hope',zh:'希望',desc:'相信未来存在改善的可能,并愿意继续投入'},
  {en:'Legacy',zh:'传承',desc:'希望留下能在自己之后继续产生作用的影响'}
];

const app = {
  phase:1,
  s1:new Set(), s2:new Set(), s3:new Set(), ranking:[],
  savedCurrent:null, draftNotes:{}, draftDate:'', draftLifeStage:''
};

const $ = s => document.querySelector(s);
const cardsEl = $('#cards'), counterEl=$('#counter'), titleEl=$('#phaseTitle'), instEl=$('#instruction'), actionsEl=$('#actions');
const rankEl=$('#ranking'), reflEl=$('#reflection'), toastEl=$('#toast');

function toast(msg){ toastEl.textContent=msg; toastEl.classList.add('show'); setTimeout(()=>toastEl.classList.remove('show'),1500); }
function target(){ return app.phase===1?25:app.phase===2?10:app.phase===3?5:5; }
function sourceValues(){
  if(app.phase===1) return VALUES;
  const set = app.phase===2?app.s1:app.s2;
  return VALUES.filter(v=>set.has(v.en));
}
function selectedSet(){ return app.phase===1?app.s1:app.phase===2?app.s2:app.s3; }

function renderCards(){
  rankEl.classList.add('hidden'); reflEl.classList.add('hidden'); cardsEl.classList.remove('hidden');
  const src=sourceValues(), sel=selectedSet(), max=target();
  cardsEl.innerHTML='';
  src.forEach(v=>{
    const b=document.createElement('button'); b.type='button'; b.className='value-card'+(sel.has(v.en)?' selected':'')+(sel.size>=max&&!sel.has(v.en)?' disabled':'');
    b.innerHTML=`<div class="en">${v.en}</div><div class="zh">${v.zh}</div><div class="desc">${v.desc}</div>`;
    b.addEventListener('click',()=>{
      if(sel.has(v.en)) sel.delete(v.en); else if(sel.size<max) sel.add(v.en); else return toast(`本轮只能保留 ${max} 张`);
      if(app.phase===1){app.s2.clear();app.s3.clear();app.ranking=[];}
      if(app.phase===2){app.s3.clear();app.ranking=[];}
      render();
    });
    cardsEl.appendChild(b);
  });
}

function renderActions(){
  actionsEl.innerHTML='';
  if(app.phase<=3){
    if(app.phase>1){ const back=btn('返回上一步','secondary',()=>{ app.phase--; render(); }); actionsEl.appendChild(back); }
    const sel=selectedSet(); const n=target();
    const next=btn(app.phase===3?'进入 Top 5 排序':'进入下一轮','',()=>{ app.phase++; if(app.phase===4) app.ranking=VALUES.filter(v=>app.s3.has(v.en)).map(v=>v.en); render(); });
    next.disabled=sel.size!==n; actionsEl.appendChild(next);
    const reset=btn('清空本轮','ghost',()=>{sel.clear();render();}); actionsEl.appendChild(reset);
    const s=document.createElement('span'); s.className='status'; s.textContent=sel.size===n?'已达到本轮目标,可以继续。':`还需选择 ${n-sel.size} 张。`; actionsEl.appendChild(s);
  } else if(app.phase===4){
    actionsEl.appendChild(btn('返回 Top 5 选择','secondary',()=>{app.phase=3;render();}));
    actionsEl.appendChild(btn('确认排序,进入反思','',()=>{app.phase=5;render();}));
  } else if(app.phase===5){
    actionsEl.appendChild(btn('返回排序','secondary',()=>{captureDraft();app.phase=4;render();}));
    actionsEl.appendChild(btn('保存本次 Mapping','',saveSession));
    actionsEl.appendChild(btn('下载本次 JSON','ghost',exportCurrent));
    actionsEl.appendChild(btn('复制 Markdown 摘要','ghost',copySummary));
    actionsEl.appendChild(btn('重新开始','danger',resetAll));
  }
}
function btn(label,kind,fn){const b=document.createElement('button');b.type='button';b.className='btn '+(kind||'');b.textContent=label;b.addEventListener('click',fn);return b;}

function renderRanking(){
  cardsEl.classList.add('hidden'); reflEl.classList.add('hidden'); rankEl.classList.remove('hidden');
  rankEl.innerHTML='<div class="instruction">排序规则:<strong>不允许并列。</strong>如果只能保留其中一个,你会留下谁?用上下箭头完成强制排序。</div><div class="rank-list" id="rankList"></div>';
  const list=rankEl.querySelector('#rankList');
  app.ranking.forEach((en,i)=>{
    const v=VALUES.find(x=>x.en===en); const row=document.createElement('div'); row.className='rank-item';
    row.innerHTML=`<div class="rank-num">${i+1}</div><div class="rank-main"><b>${v.en} · ${v.zh}</b><small>${v.desc}</small></div><div class="rank-controls"><button class="iconbtn up" ${i===0?'disabled':''}>↑</button><button class="iconbtn down" ${i===app.ranking.length-1?'disabled':''}>↓</button></div>`;
    row.querySelector('.up').addEventListener('click',()=>moveRank(i,-1)); row.querySelector('.down').addEventListener('click',()=>moveRank(i,1)); list.appendChild(row);
  });
}
function moveRank(i,d){const j=i+d;if(j<0||j>=app.ranking.length)return;[app.ranking[i],app.ranking[j]]=[app.ranking[j],app.ranking[i]];render();}

function captureDraft(){
  document.querySelectorAll('[data-note]').forEach(el=>app.draftNotes[el.dataset.note]=el.value);
  if($('#recordDate')) app.draftDate=$('#recordDate').value;
  if($('#lifeStage')) app.draftLifeStage=$('#lifeStage').value;
}
function renderReflection(){
  cardsEl.classList.add('hidden'); rankEl.classList.add('hidden'); reflEl.classList.remove('hidden');
  const old={...app.draftNotes}; document.querySelectorAll('[data-note]').forEach(el=>old[el.dataset.note]=el.value);
  reflEl.innerHTML=`<div class="instruction"><strong>把价值观变成行为。</strong>对每个 Top 5 写三项:为什么重要、最近一次行为证据、未来 30 天一个可观察承诺。</div>
    <div class="meta-grid"><div class="field"><label>记录日期</label><input id="recordDate" type="date"></div><div class="field"><label>现阶段 / 人生情境(可选)</label><input id="lifeStage" placeholder="例如:刚换工作 / 新婚 / 创业第2年 / 研究生阶段"></div></div>
    <div class="reflection" id="reflectionCards"></div><div class="result-box"><h3>你的当前 Top 5</h3><div class="result-top5">${app.ranking.map((en,i)=>{const v=VALUES.find(x=>x.en===en);return `<div class="result-v"><b>#${i+1} ${v.en}</b><small>${v.zh}</small></div>`}).join('')}</div></div>`;
  const rc=$('#reflectionCards');
  app.ranking.forEach((en,i)=>{const v=VALUES.find(x=>x.en===en);const box=document.createElement('div');box.className='reflection-card';box.innerHTML=`<h4>#${i+1} ${v.en} · ${v.zh}</h4><div class="form-grid"><div class="field"><label>为什么现在重要?</label><textarea data-note="${en}|why" placeholder="用你自己的定义写,不要写标准答案"></textarea></div><div class="field"><label>最近一次行为证据</label><textarea data-note="${en}|evidence" placeholder="最近30天,哪件事说明你真的重视它?"></textarea></div><div class="field"><label>未来30天承诺</label><textarea data-note="${en}|commitment" placeholder="一个可观察、可完成的行动"></textarea></div></div>`;rc.appendChild(box);});
  $('#recordDate').value=app.draftDate||(app.savedCurrent&&app.savedCurrent.date)||new Date().toISOString().slice(0,10);
  $('#lifeStage').value=app.draftLifeStage||(app.savedCurrent&&app.savedCurrent.lifeStage)||'';
  document.querySelectorAll('[data-note]').forEach(el=>{if(old[el.dataset.note]!=null)el.value=old[el.dataset.note]; else if(app.savedCurrent?.notes?.[el.dataset.note])el.value=app.savedCurrent.notes[el.dataset.note];});
}

function render(){
  if(app.phase===1){titleEl.textContent='Step 1|初筛:50 → 25';instEl.innerHTML='问题:<strong>这个词现在会不会让我有明显的“是,这对我重要”反应?</strong> 不用深入思考。';}
  if(app.phase===2){titleEl.textContent='Step 2|复筛:25 → 10';instEl.innerHTML='取舍:<strong>如果只能保留其中一部分,哪些是“没有它就不像我”的?</strong> 选满 10 张。';}
  if(app.phase===3){titleEl.textContent='Step 3A|决赛圈:10 → 5';instEl.innerHTML='从 10 张里只留 5 张。<strong>选你真实愿意付出代价去维护的。</strong>';}
  if(app.phase===4){titleEl.textContent='Step 3B|Top 5 强制排序';instEl.innerHTML='';}
  if(app.phase===5){titleEl.textContent='Step 4|定义、证据与承诺';instEl.innerHTML='';}
  counterEl.textContent=app.phase<=3?`已选 ${selectedSet().size} / ${target()}`:app.phase===4?'Top 5 排序中':'Top 5 已形成';
  if(app.phase<=3) renderCards(); else if(app.phase===4) renderRanking(); else renderReflection();
  renderActions(); renderHistory();
}

function collectCurrent(){
  const notes={}; document.querySelectorAll('[data-note]').forEach(el=>notes[el.dataset.note]=el.value.trim());
  return {id:'vm_'+Date.now(),createdAt:new Date().toISOString(),date:$('#recordDate')?.value||new Date().toISOString().slice(0,10),lifeStage:$('#lifeStage')?.value.trim()||'',method:'50-25-10-5 Values Mapping',top5:[...app.ranking],notes};
}
function getHistory(){try{return JSON.parse(localStorage.getItem('valuesMappingSessions')||'[]')}catch(e){return []}}
function setHistory(x){localStorage.setItem('valuesMappingSessions',JSON.stringify(x));}
function saveSession(){
  captureDraft(); const s=collectCurrent(), h=getHistory(); h.push(s); setHistory(h); app.savedCurrent=s; toast('已保存在本机浏览器'); renderHistory();
}
function resetAll(){app.phase=1;app.s1.clear();app.s2.clear();app.s3.clear();app.ranking=[];app.savedCurrent=null;app.draftNotes={};app.draftDate='';app.draftLifeStage='';render();window.scrollTo({top:document.querySelector('#practice').offsetTop-12,behavior:'smooth'});}
function download(obj,name){const blob=new Blob([JSON.stringify(obj,null,2)],{type:'application/json'});const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=name;document.body.appendChild(a);a.click();setTimeout(()=>{URL.revokeObjectURL(a.href);a.remove()},0)}
function exportCurrent(){captureDraft();const s=collectCurrent();download(s,`values-mapping-${s.date}.json`);}
function summaryText(s){return `# Values Mapping — ${s.date}\n${s.lifeStage?`情境:${s.lifeStage}\n`:''}\n${s.top5.map((en,i)=>{const v=VALUES.find(x=>x.en===en);return `${i+1}. ${v.en} / ${v.zh}\n   - Why: ${s.notes[en+'|why']||''}\n   - Evidence: ${s.notes[en+'|evidence']||''}\n   - 30-day commitment: ${s.notes[en+'|commitment']||''}`}).join('\n')}`}
async function copySummary(){captureDraft();const s=collectCurrent();try{await navigator.clipboard.writeText(summaryText(s));toast('Markdown 摘要已复制');}catch(e){toast('浏览器未允许剪贴板权限');}}

function compareSessions(a,b){
  if(!a||!b)return''; const A=new Set(a.top5),B=new Set(b.top5),common=b.top5.filter(x=>A.has(x)),added=b.top5.filter(x=>!A.has(x)),dropped=a.top5.filter(x=>!B.has(x));
  const moves=common.map(x=>{const d=(a.top5.indexOf(x)+1)-(b.top5.indexOf(x)+1);return d===0?`${x} 不变`:d>0?`${x} ↑${d}`:`${x} ↓${Math.abs(d)}`});
  return `<strong>与上一份记录相比:</strong> Top 5 成员重合 ${common.length}/5。${added.length?`新增:${added.join('、')}。`:''}${dropped.length?`退出:${dropped.join('、')}。`:''}<br>顺序变化:${moves.join(';')||'无可比成员'}。`;
}
function renderHistory(){
  const h=getHistory(), box=$('#history'), cb=$('#compareBox');
  if(!h.length){box.innerHTML='<p class="fine">还没有本机历史记录。完成本次 Top 5 后点击“保存本次 Mapping”。</p>';cb.classList.add('hidden');return;}
  const rows=[...h].reverse().map(s=>`<tr><td>${s.date}</td><td>${s.lifeStage||'—'}</td><td>${s.top5.map((x,i)=>`${i+1}.${x}`).join(' · ')}</td></tr>`).join('');
  box.innerHTML=`<table><thead><tr><th>日期</th><th>人生情境</th><th>Top 5(有序)</th></tr></thead><tbody>${rows}</tbody></table>`;
  if(h.length>=2){cb.innerHTML=compareSessions(h[h.length-2],h[h.length-1]);cb.classList.remove('hidden');}else cb.classList.add('hidden');
}
$('#exportAllBtn').addEventListener('click',()=>{const h=getHistory();if(!h.length)return toast('暂无历史可导出');download(h,'values-mapping-history.json');});
$('#clearHistoryBtn').addEventListener('click',()=>{if(confirm('仅清空此浏览器中的 Values Mapping 历史。确定?')){localStorage.removeItem('valuesMappingSessions');renderHistory();toast('本机历史已清空');}});

render();
</script>
</body>
</html>

我虽然行过死荫的幽谷,也不怕遭害,因为你与我同在。
诗篇 23:4