/* 2026-09-18：原来这里 @import 了思源宋体（notoserifsc/serif.css）。全站统一成
   无衬线之后没有任何一条规则再用 "Source Han Serif SC"，留着只是白挂一个请求，
   已去掉。文件还在 assets/fonts/notoserifsc/，要用回衬线体把这行加回来即可
   —— ⚠️ @import 必须待在文件最前面，放到下面那堆 @font-face 后面会被整条忽略。 */

/* 骨架阶段的功能性样式，不是最终视觉稿——精细排版/留白比例等定稿前的细节以
   wander-hours-visual skill 为准，这里只保证交互逻辑能被看清楚、能测试。 */

/* ⚠️⚠️ 下面这几条 @font-face 里的 font-family 是**字体的名字**，不是字体栈。
   2026-09-18 全站统一字体时用 sed 全局替换 `font-family: "Freud";` 之类，
   把这几条也一起改成了 `"Freud", "Source Han Sans CN", sans-serif`——@font-face
   的 font-family 只能是单个名字，写成列表整条规则直接作废，于是 **v458/v459
   全程没有加载过 Freud 和思源黑体，所有字都在用系统兜底字**（等待动画那些
   描边字母最先露馅）。以后再批量改字体栈，先把 @font-face 这一段排除掉。

   2026-08-21 字体已接入——源文件从 /Volumes/设计部/2023品牌设计系统/.../品牌标准字体/
   直接转的 woff2（这台机器上那个卷是挂载着的，不需要用户另外打包发文件），
   转换步骤见 assets/fonts/README.md。 */
@font-face { font-family: "Freud"; src: url("../assets/fonts/Freud-Regular.woff2") format("woff2"); font-weight: 400; }
@font-face { font-family: "Freud"; src: url("../assets/fonts/Freud-Bold.woff2") format("woff2"); font-weight: 700; }
@font-face { font-family: "Source Han Sans CN"; src: url("../assets/fonts/SourceHanSansCN-Regular.woff2") format("woff2"); font-weight: 400; }
@font-face { font-family: "Source Han Sans CN"; src: url("../assets/fonts/SourceHanSansCN-Bold.woff2") format("woff2"); font-weight: 700; }
/* 地点海报用的三款字（2026-09-07）。全部下到本地——装置离线跑，Google Fonts 连不上。
   Long Cang 是中文手写体，Google 把它切成 92 个 unicode 子集，见 longcang.css。 */
/* 明信片用（2026-09-07）：Parisienne 是 Snell Roundhand 的网页回退，
   Cormorant Garamond 印落款 wander hours。 */
/* 2026-09-08 老板定死字体清单：思源宋体 / 思源黑体 / Snell Roundhand /
   Times New Roman / Freud，五款全部打包进项目，Windows 上才和 macOS 一致。
   Snell Roundhand 从 macOS 的 SnellRoundhand.ttc 取 Regular 转的 woff2；
   Times New Roman 同理。两者都是系统字体，仅限本装置内部使用，不要外发。 */
@font-face { font-family: "Snell Roundhand"; src: url("../assets/fonts/SnellRoundhand.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Times New Roman"; src: url("../assets/fonts/TimesNewRoman.woff2") format("woff2"); font-weight: 400; font-display: swap; }

/* 2026-09-02 更新：②→⑦ 的底色现在统一是 --scent-wash（= --scent-tone 兑
   --tone-wash 到 --paper），--scent-tone 取的永远是那一对设计色里**浅的**那个，
   所以四款底色落在同一个明度带里，不再出现阳台的夜兑成一片中性灰、
   对比度比别人低一截那种情况（旧写法是 --scent-primary 18%，阳台的夜 primary
   是近黑的 #080C0D，.scent-tag 实测只有 3.98，其余三款 4.6+）。
   即便如此，**跟着底色走的文字校验时仍然要四款都量**——四款底色同带但不同色相，
   兑出来的对比度不会完全一样。 */
/* 2026-09-01【可读性下限】用户反馈"字不太看得清"。实测（把前景色按不透明度
   合成到实际背景上再算 WCAG 对比度）发现全站的"次要文字"普遍用 opacity
   0.4~0.55，落在 2.5~3.7 的对比度上，远低于正文该有的 4.5——最严重的是③打字机
   纸上正在打的固定句（2.50）和完成态档案纸上的固定句（2.76），那恰恰是用户
   要读的正文。
   这不是审美问题：这台装置是**站着远看的公共屏**，比手边的显示器更需要余量。
   已把这类文字统一抬到 opacity ≥0.62（对比度 ≈4.8+），小号字段名同时从
   0.58rem 加大到 0.66rem。
   **"固定句比自选句淡"这条设计规则没有取消**，只是淡的那一档有了下限——层次
   靠"斜体 + 更小字号 + 0.62 透明度"表达，对比 1.0 的加粗大字仍然分得很开。
   以后再调这些数值，先用对比度实测，别只凭屏幕上看着顺眼。 */
:root {
  --ink: #1a1a1a;
  --paper: #f4f1ea;
  /* 2026-09-02 香型氛围底：②识别 → ⑦打印 这一整段旅程共用同一条配方，
     浓度只有这一个旋钮。--scent-tone 由 js/customize.js 的 applyScentTone
     挂在 #stage 上（值来自 data.js 的 toneBg，永远是那一对设计色里浅的
     那个），没刷卡时回落到 --paper，等于没有色调。 */
  --tone-wash: 30%;
  /* 实色填充块（选中的按钮、抽走的选项条这类"整块铺色 + 纸色字"的地方）专用。
     不能直接用 --scent-accent/--scent-ink：四款里深浅差太大，阳台的夜的强调色
     是浅蓝 #A2D7D9、月夜银桂是金黄 #F6AB00，铺上去再压 --paper 色的字就是
     白底白字（2026-09-02 截图确认，画布工具栏的"自由绘画/完成"选中态在这两款
     上基本看不见）。往墨色兑到底，四款都够深，但各自的色相还在。
     45% 这个比例是量出来的不是估的：--scent-ink 占比越高色相越足，但月夜银桂的
     ink 是金黄 #F6AB00，占 70% 时纸色字只有 3.10 的对比度，50% 才到 4.88，取 45%
     是留一档余量。实测四款（--paper 色的字压在这块实色上）：酒店房间 14.97 /
     午后客厅 11.87 / 阳台的夜 16.42 / 月夜银桂 5.50，全部过 4.5。 */
  --scent-solid: color-mix(in srgb, var(--scent-ink, var(--ink)) 45%, var(--ink));
  --scent-wash: color-mix(in srgb, var(--scent-tone, var(--paper)) var(--tone-wash), var(--paper));
  /* 2026-08-21 纸纹理——用 SVG feTurbulence 现生成的灰度噪点图，纯 CSS 内联，
     不需要额外的图片素材文件。跟 background-blend-mode:multiply 配合，把这层
     噪点"揉"进底色里，做出哑光纸张/卡纸那种不完全均匀的颗粒感，而不是电脑
     渲染出来的绝对纯色平涂——这是回应"不要科技感，要写实打印质感"这条反馈
     的关键一步。baseFrequency 0.9 出来的颗粒偏细密，适合卡纸/哑光涂料的
     质感；如果以后想要更粗糙的牛皮纸/木纹感，调低这个值就会颗粒更大。 */
  --paper-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch' result='t'/%3E%3CfeColorMatrix in='t' type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='0.12' intercept='0.88'/%3E%3CfeFuncG type='linear' slope='0.12' intercept='0.88'/%3E%3CfeFuncB type='linear' slope='0.12' intercept='0.88'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; }

/* 2026-09-02 用户："现在所有的字都太小了，看不清，可以大一点"。
   全站 45 处 font-size 里有 44 处是 rem（唯一的 px 是个 SVG 里的数字徽标），
   所以整体字号只有这一个旋钮：根字号 16 → 22（×1.375）。
   rem 是相对**根元素**算的，不受 #stage 那层 transform:scale() 影响，所以在
   1080×1920 的设计空间里放大的是实打实的设计像素，四种窗口尺寸下等比一致。
   要再调大/调小改这一个数就行，不要一处处去改 rem 值——那样下次又得全找一遍。 */
html { font-size: 28px; } /* 2026-09-02 用户测试后从 22 再加到 28：现场站着看还是嫌小，这是第二次提 */

html, body {
  margin: 0;
  height: 100%;
  background: var(--paper);
  color: var(--ink);
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  overflow: hidden;
  -webkit-user-select: none;
  user-select: none;
}

/* 固定 1080×1920 竖屏设计分辨率（2026-08-24 从横屏 1920×1080 改的，宽高
   对调，见 js/stage.js 的说明），整体用 transform 缩放+居中适配实际窗口。
   里面所有原来用 vw/vh 量视口的地方都已经换算成基于这个固定尺寸的 px，
   不再假设实际浏览器视口一定是标准比例。 */
#stage {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1080px;
  height: 1920px;
  transform-origin: center center;
  background: var(--paper);
}

.view { display: none; height: 100%; width: 100%; }
.view.active { display: flex; }

/* ---------- idle：开屏——燃烧的半截香 + 袅袅升起的引导文字 ----------
   2026-08-20 改过两版：第一版按品牌手册《宇宙的猜想 Cosmic Speculation Brand
   Book》"如意茶线香"（蜡烛产品线的实拍）改成了深酒红戏剧化布光，用户反馈
   "颜色有点诡异"，指出应该主要参照"漫游一刻"这款产品自己的企划书
   （`/Volumes/全员共享/2026市场共享/2026年方案类-市场共享/漫游一刻产品企划.pdf`），
   不是泛化整个品牌其他产品线（蜡烛）的调性。翻了这份企划书才发现：这条线香
   产品线自己的四款场景大片（酒店房间/午后客厅/阳台的夜/月夜银桂）用的是
   **柔光平拍摄影**——每款场景各自的柔和色调背景（不是统一深色）、暖白/浅灰
   树脂香托（企划书第11页写明材质是"树脂"）、真实的浅灰白色烟雾，跟蜡烛线的
   深色戏剧化布光是两回事。开屏是选香之前的中性场景，不对应任何一款具体
   场景色，所以背景仍用品牌自己的中性米白基调（跟企划书封面/项目信息页的
   背景色 #f5f2e7 几乎一致，也是本项目从一开始就在用的 --paper），香托颜色
   和形状按企划书里实拍香托精确取样重做。 */
#view-idle {
  position: relative;
  background: var(--paper);
}
.idle-scene {
  position: absolute;
  inset: 0;
}

/* 2026-08-24：原来这一整块是纯 CSS 画的"燃着的香"插画（盒身+翻盖+树脂
   香托+斜插的香梗+三缕小烟丝），用户反馈希望换成真实产品实拍——已经用
   真实拍摄的产品照片（.idle-photo-frame，见下面）取代。这里的说明和数值
   留给以后想回看当年怎么画这个插画时参考，不再生效：曾经用一张实拍参照图
   （2026-8-6-宇宙的猜想0598.tif，"阳台的夜"那款）画出"香托垫在打开的包装盒
   翻盖上，盒身贴着桌面斜放"这个构图，颜色直接取自阳台的夜的 colorPrimary/
   colorAccent；香托是暖灰白色树脂矮盘，从产品企划 PDF 里酒店房间款的实拍
   精确取样（亮部约#c9c2ba，暗部约#8f887c）。 */

/* 真实产品照片替代原来的 CSS 插画——每次回到待机画面，js/idle-scene.js 的
   IDLE_PRODUCT_PHOTOS 会随机选一张换上，"随机点燃一款线香"的感觉。
   2026-08-24 第一版给照片加了张"白卡纸相框"（留白边框+投影+轻微旋转），
   用户反馈"这样不行，一个框在这儿很奇怪"——实拍图本身是纯白影棚背景，
   套上我自己另加的白色卡纸边框之后，读起来是"背景上贴了一个边界分明的
   矩形色块"，不是"照片直接摆在桌面上"，两层白（图片自己的白底+边框的白）
   叠在一起反而更显生硬。改成不加任何边框/背景色，直接用
   mix-blend-mode:multiply 把图片和 #view-idle 的米白背景（--paper
   #f4f1ea，还叠了 --paper-grain 纹理）做正片叠底混合——纯白色乘以任何
   颜色等于那个颜色本身不变，所以实拍图的白色影棚背景会自然融进页面背景、
   看不出矩形边界，只有产品本身（比背景暗的像素）会保留下来叠在纸感背景
   上，效果类似把照片直接印在这张纸上，不是贴了一张独立的卡片上去。
   宽度固定、高度由 aspect-ratio 跟着每张照片自己的实际比例走（三款实拍
   构图裁得比例还不完全一样），JS 选中某一张时会把这个变量设好，图片还没
   解码完成也不影响这里量出来的框的位置——.incense-ember/.incense-ash
   两个锚点要用它。 */
.idle-photo-frame {
  position: absolute;
  left: 8%;
  bottom: 8%;
  /* 这里是整张开屏构图唯一的尺寸旋钮：高度由 --idle-photo-ratio（JS 按当前
     随机到的那张照片的实际比例设）跟着走，香头/灰烬两个锚点是框内百分比
     定位，烟的路径又完全由这两个锚点的实际渲染位置算出来
     （js/idle-scene.js 的 buildIdleSmokePath），所以只改这一个数就是整张
     图连同烟的起点一起等比放大，不用同步改别处。
     实拍图本身（assets/images/idle/*.jpg，1000px 宽）已经裁到产品边缘、
     四周没有多余留白，所以"让产品更大"没有别的路子，就是把这个框调大。
     历史值：横屏 1920 时代 320px → 2026-08-24 转竖屏按同比例换算成 180px
     → 2026-08-28 用户"开屏的产品自身可以大一点"先放到 360px，看过之后
     "再大一点，我说的是产品自身"，再放到 540px（占 1080 宽的一半）。 */
  width: 540px;
  aspect-ratio: var(--idle-photo-ratio, 1.35);
}
.idle-photo-inner {
  position: relative;
  width: 100%;
  height: 100%;
}
.idle-photo-inner img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  mix-blend-mode: multiply; /* 把实拍图的纯白影棚背景融进页面背景，不留边框感的矩形 */
}
/* .incense-ash/.incense-ember 现在纯粹是定位锚点，不再是画出来的灰烬/
   香头色块——坐标（left/top 用百分比）由 idle-scene.js 按当前这张照片里
   香梗实际位置设置，buildIdleSmokePath 用它们的 getBoundingClientRect 算
   文字烟雾该从哪冒出来、朝哪个方向飘，两个元素本身不需要画出来。ember
   保留一个很小的暖色呼吸光点叠在照片里香头的位置上，像"这截香正燃着"的
   提示；ash 完全不可见，只用来定角度。 */
.incense-ash {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}
.incense-ember {
  position: absolute;
  /* 照片放大一倍之后这个点也跟着调过一次（6→10px），实测太大了：香梗本身
     才两三个像素宽，10px 的实心点读起来是"香头上浮着一颗球"，不是"香正
     燃着"。核心只放到 7px，剩下的交给下面那圈光晕——真实的香头本来就不比
     香梗粗多少，亮的是它周围的一团光。 */
  width: 7px;
  height: 7px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: #ff8a4c;
  box-shadow: 0 0 9px 3px rgba(255, 138, 76, 0.6), 0 0 24px 9px rgba(255, 138, 76, 0.18);
  animation: ember-breathe 2.4s ease-in-out infinite;
}
@keyframes ember-breathe {
  0%, 100% { opacity: 0.75; transform: translate(-50%, -50%) scale(0.88); }
  50% { opacity: 1; transform: translate(-50%, -50%) scale(1.15); }
}

/* 引导文字：不再是一整块 CSS 文字平移，而是用 canvas 逐字沿一条从香头到右上角的
   曲线绘制，字符朝向跟随路径切线旋转、逐渐淡出模糊——手法和④漫游记录的文字笔刷
   （js/canvas.js 的 drawGlyphsAlongSegment）是同一套，呼应"由文字构成"的核心意象。
   具体路径/逐帧绘制逻辑见 js/idle-scene.js。 */
#idle-smoke-canvas {
  position: absolute;
  inset: 0;
  /* width/height:100% 不能省——<canvas> 是"替换元素"，inset:0 单独并不会把
     替换元素撑满定位祖先（这点跟普通 div 不一样），没有这两行时它会退回自己
     的默认固有尺寸 300×150，而 js/idle-scene.js 读 clientWidth 来定位图分辨率，
     两者一结合就成了自我强化的死循环——画布永远卡在那个 300×150 的固有尺寸
     附近出不来，完全脱离了 #stage/香头的实际位置，不管怎么调整窗口大小都
     不可能对准。 */
  width: 100%;
  height: 100%;
  pointer-events: none;
}

#view-idle .mock-hint {
  position: absolute;
  bottom: 77px; /* 原 4vh，竖屏改成 4% × 1920 新高度，见 js/stage.js 2026-08-24 那条 */
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.85rem;
  opacity: 0.3; /* 背景改回米白后，直接继承全局深色 --ink 就够用，不用再单独指定颜色 */
}

/* ---------- identifying ---------- */
/* ---------- ①开屏动画（2026-09-02）---------- */
#view-splash {
  position: relative;
  /* .view.active 只给了 display:flex，默认方向是 row——不显式写 column 的话
     justify-content:flex-end push 的是**右边**不是下边，按键会贴到右边缘去
     （2026-09-02 实测 x=660/宽 420，正好右对齐）。 */
  flex-direction: column;
  align-items: center;
  justify-content: flex-end; /* 按键压在下方，不挡住画面主体 */
  padding-bottom: 214px;
  background: var(--ink); /* 视频加载出来之前是黑底，不要闪一下米白 */
  overflow: hidden;
  transition: opacity 420ms ease; /* 时长要跟 splash.js 的 SPLASH_VIDEO_FADE_MS 对上 */
}
#view-splash.leaving { opacity: 0; }
#splash-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover; /* 片子本身就是 1080×1920，跟设计分辨率一致，正常情况下不会裁到 */
  display: block;
}

/* 悬停触发的按键：手停在范围内 1 秒就触发（见 js/gestures.js 的 updateDwell）。
   --dwell（0~1）是停留进度，由那边实时写进来。
   进度必须**画在按键自己身上**、而且是一条从左往右填满的实色带——不能只靠
   光标上那个小圆环：人站得远、眼睛看的是按键不是光标，看不见反馈就会以为
   没反应而把手挪开，正好在快要触发的时候前功尽弃。 */
/* 2026-09-02 用户："不要加奇怪的描边"——原来是个半透明深色块 + 纸色描边 +
   毛玻璃，压在定格动画上像贴了张标签。现在**没有任何盒子**：只有字和两侧
   的箭头，靠文字自己的投影保证在任何一帧画面上都读得清。
   触发方式也从"停留 1 秒"改成"手向左或向右挥一下"（见 gestures.js 的
   updateSwipe），所以两侧那对箭头本身就是操作说明——它在左右轻轻摆动，
   摆的就是要用户做的那个动作。 */
.dwell-btn {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 34px;
  padding: 0;
  cursor: pointer;
  background: none;
  border: none;
}
.swipe-arrow {
  width: 66px;
  height: 40px;
  flex-shrink: 0;
  color: var(--paper);
  filter: drop-shadow(0 2px 7px rgba(0, 0, 0, 0.8));
  animation: swipe-hint 2.2s ease-in-out infinite;
}
.swipe-arrow.right { transform: scaleX(-1); }
/* 两边的箭头朝各自的外侧来回摆——"往左或者往右挥都行"这件事，光靠静止的
   箭头说不清楚，得让它动起来 */
@keyframes swipe-hint {
  0%, 100% { transform: translateX(0); opacity: 0.55; }
  50%      { transform: translateX(-16px); opacity: 1; }
}
.swipe-arrow.right { animation-name: swipe-hint-right; }
@keyframes swipe-hint-right {
  0%, 100% { transform: scaleX(-1) translateX(0); opacity: 0.55; }
  50%      { transform: scaleX(-1) translateX(-16px); opacity: 1; }
}
/* .dwell-fill 随盒子一起删了（2026-09-02 改成挥手触发，没有停留进度可画） */
.dwell-text {
  position: relative;
  z-index: 1;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  color: var(--paper);
  /* 压在定格动画上，画面明暗每一帧都在变——给一圈很淡的暗描边保证任何一帧
     底下字都读得清，比依赖混合模式可靠 */
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.7);
}

#view-identifying {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* 2026-09-02：识别是这一款香第一次"露脸"的地方，色调从这一屏就该起来 */
  background: var(--scent-wash);
}
/* ---- 档案打开：竖版对开书本（每片 505×1000，中缝居中，封面绕书脊 3D 翻开） ---- */
.open-folder { position: relative; width: 1010px; height: 1000px; perspective: 2400px; }
/* 右面板＝里页：装订杆 + 素材叠 + 斜角袋 + 露出的香型名。占右半（中缝在容器中线 505） */
.of-page {
  position: absolute; top: 0; left: 505px; width: 505px; height: 1000px;
  background: #fdf9e3; /* 纸色（实色，不叠白噪纹） */
  border: 1px solid rgba(60,45,25,0.18); border-left: none;
  box-shadow: 0 40px 90px -40px rgba(30,20,10,0.5);
  color: #6b5a3e; overflow: hidden;
}
/* 装订杆：贴书脊（左边），竖线 + 两孔 */
.of-binding { position: absolute; left: 40px; top: 150px; bottom: 150px; width: 18px; }
.of-binding::before { content: ''; position: absolute; left: 8px; top: 0; bottom: 0; width: 2px; background: rgba(60,45,25,0.4); }
.of-binding i {
  position: absolute; left: 1px; width: 16px; height: 16px; border-radius: 50%;
  background: color-mix(in srgb, var(--scent-ink, #2c2119) 14%, transparent);
  box-shadow: inset 0 0 0 2px rgba(60,45,25,0.42);
}
.of-binding i:first-of-type { top: 50px; } .of-binding i:last-of-type { bottom: 50px; }
/* 装订夹（两孔中间的金属夹子） */
.of-clip { position: absolute; left: -4px; top: 50%; transform: translateY(-50%); width: 26px; height: 36px; border-radius: 4px; background: linear-gradient(180deg, #cfd2d6, #a7abb1); border: 1px solid #92969e; box-shadow: 0 3px 6px -2px rgba(0,0,0,0.35); }
.of-clip::before { content: ''; position: absolute; left: 6px; right: 6px; top: 7px; height: 11px; border: 2px solid #b8bcc2; border-bottom: none; border-radius: 6px 6px 0 0; }
/* 露出的香型名 */
.of-brand { position: absolute; top: 64px; left: 90px; font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.8rem; letter-spacing: 0.16em; opacity: 0.55; }
.of-scent { position: absolute; top: 330px; left: 90px; right: 40px; font-size: 3.2rem; font-weight: 800; letter-spacing: 0.06em; line-height: 1.1; opacity: 0; }
.of-en { position: absolute; top: 396px; left: 92px; font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 1.1rem; letter-spacing: 0.22em; opacity: 0; }
.of-addr { position: absolute; bottom: 44px; left: 90px; font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.66rem; letter-spacing: 0.1em; opacity: 0.5; }
/* 一叠"文件"：上下边对齐、完全堆叠在一起，只有顶部标签横向错开（像带分隔标签的一叠文件） */
.of-filestack { position: absolute; left: 64px; right: 40px; top: 210px; bottom: 96px; }
.of-file {
  position: absolute; inset: 0; border-radius: 4px 10px 10px 10px;
  background: var(--f-bg, #30352f);
  border: 1px solid rgba(0,0,0,0.18); box-shadow: 0 14px 26px -14px rgba(0,0,0,0.4);
}
/* 后面几张各露一点点边，让人看出是"一叠"，但上下对齐。
   递增 z-index：f1 在最上；这样标签文字（都被抬到纸上边缘之上）不会被别的纸盖住。 */
.of-file.f3 { transform: translateX(14px); filter: brightness(0.96); z-index: 2; }
.of-file.f2 { transform: translateX(7px); filter: brightness(0.98); z-index: 3; }
.of-file.f1 { transform: none; z-index: 4; }
/* 标签：每张一个，横向错开，全部露在顶边。
   关键：文字整体坐在标签"上半段"（纸上边缘 y=0 之上），避免后排标签的下半截
   被前排文件纸盖住而把字裁成半截（老板 #103 反馈的"乱码"）。 */
.of-file-tab {
  position: absolute; top: -22px; min-width: 84px; height: 28px; padding: 3px 15px 0;
  display: flex; align-items: flex-start; justify-content: center; border-radius: 7px 7px 0 0;
  /* 标签跟"文件档案"一体：用线香包装色 --f-bg 打底（跟下面的文件卡同色），
     不是封面的纸色（2026-09-04 老板要求）。文字用 --f-ink 深/浅自适应保证可读。 */
  background: var(--f-bg, #fdf9e3); color: var(--f-ink, #8a7748);
  border: 1px solid rgba(60,45,25,0.16); border-bottom: none;
  font-size: 0.64rem; font-weight: 500; letter-spacing: 0.1em; white-space: nowrap;
}
.of-file.f1 .of-file-tab { left: 20px; }
.of-file.f2 .of-file-tab { left: 146px; }
.of-file.f3 .of-file-tab { left: 272px; }
.of-file-side {
  position: absolute; left: 16px; top: 44px; writing-mode: vertical-rl;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.52rem; letter-spacing: 0.1em;
  color: var(--f-sub, #aac5be); opacity: 0.5;
}
.of-file-photo {
  position: absolute; top: 60px; left: 60px; right: 44px; height: 340px;
  background: #fdfcf8; padding: 12px 12px 34px; border-radius: 2px;
  box-shadow: 0 14px 26px -12px rgba(0,0,0,0.4); transform: rotate(-1deg);
}
.of-file-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 斜角袋：压住整叠文件的下角（不要 z-index，免得盖到封面上） */
.of-pocket {
  position: absolute; right: 30px; bottom: 40px; width: 210px; height: 104px;
  background: color-mix(in srgb, #fdf9e3 55%, #d8c79a);
  border: 1px solid rgba(60,45,25,0.3);
  clip-path: polygon(0 62%, 100% 0, 100% 100%, 0 100%);
  box-shadow: 0 -5px 12px -8px rgba(30,20,10,0.25);
}
/* 翻盖：单块封面板，占右半，绕左书脊(transform-origin 0% 50%)做 rotateY。
   两面各是一张 inset:0 的纸，靠 preserve-3d + JS 切换显示（animateCover），
   不用 backface-visibility（剔除不可靠）。初始闭合(0°)：正面显示、反面隐藏。 */
.of-cover {
  position: absolute; top: 0; left: 505px; width: 505px; height: 1000px; z-index: 6;
  transform-origin: 0% 50%; transform-style: preserve-3d; transform: rotateY(0deg);
}
.of-cover-face {
  position: absolute; inset: 0; background: #fdf9e3;
  border: 1px solid rgba(60,45,25,0.16);
  /* 柔和近对称的浅投影：翻开平铺后书脊处不会斜出怪影，闭合悬浮也够自然
     （原来 0 40px 90px 的大偏移投影在翻转后会歪） */
  box-shadow: 0 14px 40px -22px rgba(30,20,10,0.34);
  display: flex; align-items: center; justify-content: center;
}
.of-cover-back {
  display: none;                 /* 默认闭合看不到反面；animateCover 过 90° 后切显示 */
  flex-direction: column; gap: 20px;
  transform: rotateY(180deg);    /* 翻过去后内容不镜像、正着读 */
}
/* 金属装订杆：翻开后落在左内页靠中缝一侧，竖条 + 两枚压片 */
/* 四个标签（全部和内页同色 #fdf9e3），沿顶边并排：香型名 + 漫游地点/心情/场景 */
.of-cover-tabs { position: absolute; top: -28px; left: 40px; right: 40px; display: flex; gap: 8px; }
.of-cover-tabs .oct {
  flex: 1; height: 36px; display: flex; align-items: center; justify-content: center;
  border-radius: 8px 8px 0 0;
  /* 同上：标签属于"文件档案"，用线香色 --f-bg，不是封面纸色（2026-09-04 老板要求） */
  background: var(--f-bg, #fdf9e3); color: var(--f-ink, #b0a074);
  border: 1px solid rgba(60,45,25,0.14); border-bottom: none;
  font-size: 0.72rem; font-weight: 500; letter-spacing: 0.1em;
  white-space: nowrap;
}
/* logo：用真实 logo 文件（COSMIC SPECULATION 宇宙的猜想 + CS）做遮罩，填封面字色 */
.of-cover-mark {
  width: 260px; height: 182px; background-color: #dbcc9e;
  -webkit-mask: url(../assets/brand/logo.png) center / contain no-repeat;
          mask: url(../assets/brand/logo.png) center / contain no-repeat;
}
/* 进屏即播：封面翻开由 js/carousel.js 的 animateCover 用 rAF 驱动（要按角度切正/反面，
   纯 CSS keyframe 做不到）；香型名等封面翻过去露出底板后再淡入。 */
#view-identifying.active .of-scent { animation: fadein 0.7s ease forwards 2.0s; }
#view-identifying.active .of-en { animation: fadein 0.7s ease forwards 2.2s; }
@keyframes fadein { to { opacity: 1; } }
/* 翻盖反面（左内页）里的 logo/副标题 */
.of-leftpage-logo {
  width: 220px; height: 154px; background-color: #cdbb86;
  -webkit-mask: url(../assets/brand/logo.png) center / contain no-repeat;
          mask: url(../assets/brand/logo.png) center / contain no-repeat;
}
.of-leftpage-sub { font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.72rem; letter-spacing: 0.18em; color: #b0a074; }

/* ---------- customizing ---------- */
#view-customizing {
  flex-direction: column;
  align-items: stretch;
  padding: 154px 130px; /* 原 8vh 12vw，竖屏改成 8%×1920 / 12%×1080，见 js/stage.js 2026-08-24 那条 */
  position: relative;
  /* 2026-09-07：整屏铺蓝白条纹布纹（四款统一），不再按香型铺纯色。
     --poster-bg 仍由 js/carousel.js 按香型注入，只是不再画背景——它还被
     文件夹上那些字用来派生颜色（见 applyPosterVars）。 */
  background: var(--wander-cloth, url("../assets/poster/bg/sunday_afternoon.jpg")) center / cover no-repeat, var(--poster-bg, var(--scent-wash));
}
/* 抽屉柜整体压在打字机纸上面（2026-09-02）。上面把纸调矮了，正常情况下两者
   已经不重叠，但**纸的高度是跟着内容长的、抽屉的深度是跟着候选数量长的**，
   两个都会随文案变化——只靠调数字迟早还会撞上。这条 z-index 是兜底：真撞上
   了也是抽屉盖住纸（抽屉是朝使用者这一侧拉出来的，本来就该在前面），而不是
   纸把正在操作的抽屉挡掉。 */
/* z-index 必须大于 .typewriter-desk 的 40 —— 2026-09-02 第一次改这里只给了 2，
   用户反馈"还是挡住的啊"：打字机整台（连同那张纸）是 z-index:40，2 根本压不过它。
   改这个数之前先去看一眼 .typewriter-desk 那条。 */
#option-list { position: relative; z-index: 50; }
.scent-tag { font-size: 0.95rem; letter-spacing: 0.15em; opacity: 0.74; margin-bottom: 58px; flex-shrink: 0; } /* 原 3vh，竖屏改成 3%×1920 */
/* 2026-08-24：原来这里是 .assembled（顶部即时显示"拼到目前为止"的文案），
   已经被下面的"打字机纸"（.typewriter-paper）取代，不再需要——纸本身就是
   唯一的进度展示，顶部只留 .scent-tag 和 #progress 的"X/Y"数字。 */
.option-list {
  display: flex; flex-direction: column; gap: 1rem;
  /* 2026-08-24：柜体（.drawer-cabinet）现在永远保持关闭时的固定高度，不会
     再撑高（见 .drawer-cabinet 的说明），这一块不用再兜底"被压缩"的情况，
     flex-shrink:0 就够了。下面的打字机整块（.typewriter-desk）是
     position:absolute 贴死在屏幕底部固定一段高度（见那边的说明），不再是
     这一块"让出剩余空间"给下面的 flex 兄弟，两者之间没有空间争抢关系了，
     也就不需要 overflow 之类的兜底。 */
  flex-shrink: 0;
}
/* ---------- ③屏底部：打字机（只露上半截）+ 从滚筒里卷出来的纸 ----------
   历史：这块最早是 .assembled 顶部即时文本，2026-08-24 换成"打字机纸"
   （一张凭空浮在底部三分之一的纸 + 打完一行撕成小卡片落进下面的卡片堆）。
   2026-08-28 用户反馈"没有打字的感觉"，并给了两张参照图（一张老照片里
   字一个一个被敲在纸上，一张只露出机身上沿和压纸滚筒的打字机，明确说
   "不需要出现打字的键盘，但是可以出现这种打字机的一小部分"），于是改成
   现在这版：底部真的立着一台打字机的上半截，纸从它的滚筒里卷出来。

   为什么整块还是 position:absolute 贴死屏幕底部（这条从 08-24 那版继承
   下来，原因没变）：柜体拉开的候选堆是 position:absolute、会探出自己的
   柜体边界，如果这块是柜体的 flex 兄弟，它在 DOM 顺序上排在后面、会盖住
   探出来的候选堆，看起来像"候选被裁掉了"。所以这块固定占屏幕底部一段
   高度、并给一个明显高于柜体内部所有 z-index（.drawer-face 21 /
   .drawer-trapezoid-wrap 20）的值，上面稳稳的一大半留给柜体自由使用。

   几何关系（都是 1080×1920 设计像素，改一个要连带看另一个）：
     .typewriter-machine  高 208，贴 desk 底部
     .tw-shell            机身上沿，高 150（desk 底起 0~150）
     .tw-platen           压纸滚筒，跨在机身上沿之上（desk 底起 148~208）
     .typewriter-paper    下缘 bottom:146px —— 比滚筒顶低 62px，也就是纸的
                          最下面 62px 被滚筒挡住，视觉上"卷在滚筒里"；
                          高度不写死，跟着纸上的行数长，见那一条
     纸的下内边距 100px = 纸被机器挡住的 62px + 打字点到压纸杆的 38px 余量，
                          让正在打的那一行正好落在滚筒口上方一点点（真打字
                          机的打字点就在这），又不会被横过纸面的压纸杆压到 */
/* ---------- 定制完成后的"漫游记录"档案纸（2026-09-01）----------
   用户："这个页面可以是没有打字机，就变成这一整页的纸"，并点名要标题、香型
   名字、日期、主要香材、香气描述五样。抬头内容来自《宇宙的猜想漫游一刻档案
   文案》docx，已接进 data.js。
   版式跟③抽出来那张档案记录卡、教学说明单同一套（大标题 + 小号全大写副标 +
   右端日期 + 一条虚线 + 字段名/值的两栏），整个项目的"纸上印刷品"语言保持一致。
   平时 display:none，只有 #view-customizing.finished 时才出现；同一个 class
   把打字机整块收走。 */
.final-sheet { display: none; }
#view-customizing.finished .typewriter-desk { display: none; } /* 打字完了，机器就该退场 */
/* 完成态：整屏只剩这张漫游记录纸。
   打字机退场之后下半屏全空了，纸要垂直居中，否则挤在顶部、下面一大片空白。
   2026-09-02：下一步入口从纸**下面**一个独立方框按钮改成**贴在纸上**的一张
   箭头便签（#go-wander，见 .sticky-flag），所以原来那两条靠 order 把按钮
   排到纸后面的规则不需要了；#option-list 在完成态是空的，直接收起来。 */
#view-customizing.finished { justify-content: center; }
#view-customizing.finished .option-list { display: none; }
/* 2026-09-11：结果页不再隐藏提示——老板要在正上方居中放一张纸条写
   「捏合 6 秒确认打印」。提示条现在是绝对定位的，不占文档流，不会挤版式。
   （原来这里是 `.finished .step-hint { display:none }`，所以 showResult 里
   设的那行「捏合保持 6 秒」其实一直看不见。） */
#view-customizing.finished .final-sheet {
  display: flex;
  flex-direction: column;
  align-self: center;
  position: relative;
  width: 820px;
  padding: 50px 56px 48px;
  background: #f7f2e6;
  background-image: var(--paper-grain);
  background-blend-mode: multiply;
  box-shadow:
    0 0 0 1px rgba(74, 50, 22, 0.16),
    0 14px 34px -16px rgba(74, 50, 22, 0.45),
    0 2px 5px rgba(74, 50, 22, 0.12);
  color: color-mix(in srgb, var(--ink) 88%, #4a3a20);
}
.fs-head {
  display: flex;
  align-items: baseline;
  gap: 15px;
  padding-bottom: 10px;
  border-bottom: 1px dashed rgba(74, 50, 22, 0.5);
}
.fs-title { font-size: 1.5rem; font-weight: 700; letter-spacing: 0.3em; text-indent: 0.3em; }
.fs-sub { font-size: 0.68rem; letter-spacing: 0.22em; opacity: 0.68; text-transform: uppercase; }
.fs-date { margin-left: auto; font-size: 0.74rem; letter-spacing: 0.1em; opacity: 0.7; font-variant-numeric: tabular-nums; }
/* 字段区：左边小号全大写字段名，右边值——跟档案卡的"情绪 EMOTION"同一种写法 */
.fs-meta { margin-top: 20px; }
.fs-row { display: flex; gap: 16px; align-items: baseline; padding: 7px 0; }
.fs-row + .fs-row { border-top: 1px solid rgba(74, 50, 22, 0.13); }
.fs-label {
  width: 112px;
  flex-shrink: 0;
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  opacity: 0.7;
  text-transform: uppercase;
}
.fs-value { font-size: 0.88rem; line-height: 1.65; letter-spacing: 0.04em; }
/* 整首诗。固定句/自选句的强调差异沿用全项目统一那条规则（自选句更大更实、
   固定句小而淡），跟③打字机纸和④画布的 GLYPH_EMPHASIS 对应。 */
.fs-poem {
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px dashed rgba(74, 50, 22, 0.4);
}
.fs-line { padding: 5px 0; }
.fs-line.fixed { font-size: 1rem; font-style: italic; opacity: 0.62; letter-spacing: 0.05em; }
.fs-line.chosen { font-size: 1.24rem; font-weight: 600; letter-spacing: 0.06em; }

.typewriter-desk {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 704px;
  z-index: 40;
  pointer-events: none; /* 纯展示，别抢走柜体/候选文件的拖拽手势 */
}
/* 纸：z-index 比机器低，下缘被滚筒压住 = 从滚筒里卷出来。视觉上比背景更
   "白"一点（背景是米白 --paper），加纸纹理和一点点侧向投影，克制地点出
   纸的质感，不做写实信纸插画，主角还是被敲上去的字。 */
.typewriter-paper {
  position: absolute;
  left: 118px; right: 118px; bottom: 146px;
  z-index: 1;
  /* 不设 top、不设固定高度：纸的高度由纸上现有内容决定，打完一行纸就往上
     长一行（高度由 rollPaper 显式动画，跟内容上移同步），纸的上缘就这样
     一点点从机器里露出来。这是真打字机的样子——刚上纸的时候只露出很短
     一截，行数越多露出来的越多；固定一整块大白纸摆在那儿反而不像在打字。
     max-height 兜底：万一以后文案行数变多，纸最多长到 desk 的可用高度为止，
     超出的部分由 overflow:hidden 从**上边**裁掉（flex + justify-content:
     flex-end 的溢出方向就是上边），也就是先打的行卷出画面外，不会把正在
     打的这一行顶掉。 */
  /* 2026-09-02：从 558 收到 470。根字号加大之后纸变高，上缘顶进了抽屉的
     范围，把拉开的抽屉挡住了（用户："拉出抽屉不能被纸挡住"）。连同下面
     几处字号一起调小，纸需要的高度本来也小了。 */
  max-height: 470px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  z-index: 1;
  overflow: hidden;
  padding: 44px 62px 100px;
  border-radius: 3px 3px 0 0;
  background: #fffdf7;
  background-image: var(--paper-grain);
  background-blend-mode: multiply;
  box-shadow: 0 -12px 30px -18px rgba(30, 24, 16, 0.34), 0 0 0 1px rgba(30, 24, 16, 0.09);
}
/* 纸上的内容：底对齐，新行在最下面贴着滚筒口，旧行被顶上去（rollPaper 给
   这个元素加 transform 动画做"纸往上卷一行"的过程）。 */
.tw-sheet {
  flex: 0 0 auto;
}
/* 纸张抬头——参照图②里纸上那行"@心想事成的小寞  2025/12/15"：一条虚线
   加左右两端的小字。取代了 08-24 那版每张小卡片各自带一块香型标签牌的
   做法（纸只有一张，抬头也只要一处，跟真的信纸/档案纸一样）。 */
.tw-sheet-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-top: 10px;
  margin-bottom: 22px;
  border-top: 1px dashed rgba(30, 24, 16, 0.5); /* 整块 header 自己还有 opacity:0.5，这条虚线的实际浓度是这个数再打对折，别照"看着够深"来定 */
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  opacity: 0.68;
}
.tw-sheet-date { font-variant-numeric: tabular-nums; }
.typewriter-stack { display: flex; flex-direction: column; }
/* 一整行（固定句 / 引导半句+自选半句 共用同一行）。行距按打字机的等距行
   走，正在打的那一行和已经打完的行用同一套排版——纸上不该有"当前行长得
   不一样"这回事，区别只在有没有那个打字点光标。 */
.tw-line {
  line-height: 2.05;
  padding: 2px 0;
  min-height: 1.75rem; /* 空行也要占住一行的高度——打字点固定在滚筒口，行高得先立住。跟着 .tw-fixed 字号一起调小 */
}
/* 会出现用户自选半句的那种行：自选句字号大得多（下面 .tw-chosen），空行就
   得先按最终高度占好位，不然自选半句的第一个字落下来的那一刻整行突然长高、
   纸跟着猛地一跳。1.72rem × 2.05 行高 ≈ 3.53rem。 */
.tw-line.has-chosen { min-height: 2.7rem; } /* 1.28rem × 2.05 行高 ≈ 2.62rem，见 .tw-chosen */
.tw-fixed { font-size: 0.82rem; font-style: italic; opacity: 0.62; letter-spacing: 0.06em; }
/* 自选句仍然要比固定句醒目（这条是项目定的规则，③屏和④画布共用），但
   08-24 那版的圆角药丸底色在"打字机纸"上读起来太数码了——改成打字机自己
   的强调办法：重敲一遍（text-shadow 做的 double strike，字更实更黑）+
   一条打上去的下划线。颜色仍旧用香型的 accent 色保留辨识。 */
.tw-chosen {
  display: inline;
  font-size: 1.28rem; font-weight: 600; letter-spacing: 0.08em;
  /* 2026-09-01：四款香都要显出自己的颜色（用户："现在只有3号香型打字机打出来的
     字是对应香型的颜色，其他也可以用对应颜色"）。原来兑的是 --scent-accent，
     而酒店房间/午后客厅的 accent 本身就是近黑/深褐，兑完看不出颜色，只有阳台的夜
     那款浅蓝才显色。改用 --scent-vivid（data.js 里"这一款的代表色"，四款都是
     鲜明的），但**不能直接拿它当字色**——那是浅色，打在纸上对比度只有 1.x。
     所以把它兑进深墨里：颜色够深保证可读，同时明确带上这一款的色相。
     比例是按四款分别实测对比度定的（都 ≥7），改这个数要重新量四款。 */
  color: color-mix(in srgb, var(--scent-vivid, var(--scent-accent, var(--ink))) 42%, #221a12);
  text-shadow: 0.55px 0 0 currentColor; /* 打字机的"重敲加粗"，不是字体加粗 */
  border-bottom: 1.5px solid color-mix(in srgb, var(--scent-accent, var(--ink)) 42%, transparent);
  box-decoration-break: clone; -webkit-box-decoration-break: clone; /* 换行时下划线每段各自完整 */
}
/* 每个字符自己的"敲上去"——08-24 那版是从上方 0.28em、放大 1.35 倍慢慢
   落下来的弹跳（0.18s，带回弹缓动），用户反馈那不像打字。字锤打纸是
   **瞬间到位**的：第 1% 帧就已经是全不透明（硬出现，不是渐显），只在
   90ms 里做一个"砸下去一点点又弹回"的极小行程。真正让它像打字机的是
   落定之后**保留**的那点误差——typeInto 给每个字随机的 --jx/--jy/--jr/--ink
   （横竖各半个像素级的错位、一点点倾斜、深浅不一的墨），这就是机械打字
   机套准不齐、色带吃墨不匀的样子，所有关键帧都带着这几个变量，动画结束
   停在这个"歪的"状态上，不是停在完美对齐上。 */
.tw-char {
  display: inline-block;
  opacity: var(--ink, 1);
  transform: translate(var(--jx, 0px), var(--jy, 0px)) rotate(var(--jr, 0deg));
  animation: tw-strike 90ms cubic-bezier(0.18, 0.9, 0.28, 1) both;
}
@keyframes tw-strike {
  0%   { opacity: 0; transform: translate(var(--jx, 0px), calc(var(--jy, 0px) - 0.05em)) rotate(var(--jr, 0deg)) scale(1.1); }
  1%   { opacity: var(--ink, 1); }
  55%  { opacity: var(--ink, 1); transform: translate(var(--jx, 0px), calc(var(--jy, 0px) + 0.018em)) rotate(var(--jr, 0deg)) scale(0.985); }
  100% { opacity: var(--ink, 1); transform: translate(var(--jx, 0px), var(--jy, 0px)) rotate(var(--jr, 0deg)) scale(1); }
}
/* 打字点：不是电脑光标那种竖条（打字机没有光标），是打字点位置的一小段
   横线——下一个字会砸在这儿。打字过程中常亮（字在往右推它），停下来等
   用户从抽屉里选的时候慢慢闪，提示"机器在等你"。 */
.tw-caret {
  display: inline-block;
  width: 0.72em; height: 2px;
  margin-left: 0.06em;
  vertical-align: 0.1em;
  background: currentColor;
  opacity: 0.4;
}
.tw-caret.waiting { animation: tw-caret-blink 1.15s steps(2, end) infinite; }
@keyframes tw-caret-blink { 0%, 100% { opacity: 0.42; } 50% { opacity: 0.06; } }

/* ---------- 机器本体：只做上半截（机身上沿 + 两侧凸起的肩 + 字锤扇形 +
   压纸滚筒 + 滚筒旋钮 + 压纸杆），不画键盘——用户明确"不需要出现打字的
   键盘"。全是 CSS 画的，不用图片素材。
   结构照着用户给的参照图②那台打字机从上往下拆：一根横过纸面的细金属压纸
   杆 → 两边各一块比中间高出来的圆肩（旋钮就装在肩上）→ 中间凹下去的暗部
   （压纸滚筒 + 字锤扇形）→ 机身正面（压印的品牌名）。两侧的肩比中间高，
   是这台机器一眼能认出是打字机的主要轮廓，不能省成一条平的机身上沿。
   机身颜色跟着当前香型走：在中性暖灰底上兑一点这一款的 --scent-vivid，
   既有参照图②那台橄榄绿打字机的"有色机身"感，又不会跟同屏的档案柜
   （大面积 --scent-vivid 实色）抢眼。
   纵向坐标都以机器自己的底边为 0（下面每条的 bottom 值），改一处要连带
   看 .typewriter-paper 那边的说明——纸的下缘要一直压在滚筒下面。 */
.typewriter-machine {
  position: absolute;
  left: 40px; right: 40px; bottom: 0;
  height: 208px;
  z-index: 2;
  --tw-body: color-mix(in srgb, var(--scent-vivid, #cfcabb) 34%, #d7d2c4);
  --tw-body-dark: color-mix(in srgb, var(--tw-body) 72%, #3a352c);
  --tw-body-lit: color-mix(in srgb, var(--tw-body) 78%, #fff);
}
/* 机身正面：顶部两个大圆角 + 上缘一道高光、下方渐暗，做出"一整块被从上方
   打光的圆滚滚外壳"。 */
.tw-shell {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 150px;
  border-radius: 30px 30px 0 0;
  /* 渐变按**整台机器的高度**（208px）从底往上铺，不是按这个元素自己的高度
     ——下面的圆肩用同一条渐变、同样按 208px 从底对齐，两者重叠的地方色值
     天然一致，接缝看不出来。要是各自按自己的高度铺，肩和机身正面在交界处
     就会有一道明显的色阶断层。 */
  background-image: linear-gradient(180deg, var(--tw-body-lit) 0%, var(--tw-body) 30%, var(--tw-body-dark) 100%);
  background-size: 100% 208px;
  background-position: bottom;
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.55),
    inset 0 -18px 26px -20px rgba(0, 0, 0, 0.5),
    0 -6px 18px -10px rgba(30, 24, 16, 0.35);
}
/* 两侧凸起的圆肩：比机身上沿再高出一截，滚筒旋钮就装在上面。DOM 里排在
   滚筒后面，所以会盖住滚筒的两端——滚筒是"架在两块肩之间"的，不是一根
   浮在机器上面的黑棍子。 */
.tw-shoulder {
  position: absolute;
  bottom: 0;
  width: 200px; height: 208px;
  border-radius: 64px 64px 30px 30px;
  background-image: linear-gradient(180deg, var(--tw-body-lit) 0%, var(--tw-body) 30%, var(--tw-body-dark) 100%);
  background-size: 100% 208px; /* 跟 .tw-shell 同一条渐变、同样按整机高度从底对齐，见那边说明 */
  background-position: bottom;
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.6),
    0 -4px 14px -8px rgba(30, 24, 16, 0.3);
}
.tw-shoulder-l { left: 0; }
.tw-shoulder-r { right: 0; }
/* 压纸滚筒：纸绕着它卷上来的那根胶辊，架在两块肩之间、比肩低，两端被肩
   盖住。上下渐变 + 中段一条高光 = 圆柱体。 */
.tw-platen {
  position: absolute;
  left: 120px; right: 120px; bottom: 148px;
  height: 52px;
  border-radius: 26px;
  background: linear-gradient(180deg, #635d54 0%, #45403a 30%, #302c28 64%, #23201c 100%);
  box-shadow: inset 0 2px 3px rgba(255, 255, 255, 0.16), 0 6px 14px -6px rgba(30, 24, 16, 0.55);
}
.tw-platen::after { /* 圆柱中段的一条高光 */
  content: '';
  position: absolute;
  left: 22px; right: 22px; top: 11px;
  height: 7px;
  border-radius: 4px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0));
}
/* 滚筒旋钮：装在肩上的圆盘。每打完一行 rollPaper 会把它们转一档
   （transform:rotate），跟纸往上卷同时发生——盘面上那圈细放射纹
   （repeating-conic-gradient 的防滑纹）加中间偏心的轴帽高光，就是为了让
   这个转动看得出来；没有纹路的纯色圆盘转起来是看不见的。 */
.tw-knob {
  position: absolute;
  bottom: 116px;
  width: 96px; height: 96px;
  border-radius: 50%;
  background:
    repeating-conic-gradient(from 0deg,
      color-mix(in srgb, var(--tw-body-dark) 26%, transparent) 0deg 5deg,
      transparent 5deg 11deg),
    radial-gradient(circle at 40% 34%, var(--tw-body-lit) 0%, var(--tw-body) 52%, var(--tw-body-dark) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.4),
    inset 0 -6px 12px -6px rgba(0, 0, 0, 0.45),
    0 4px 10px -5px rgba(30, 24, 16, 0.5);
  transition: transform 380ms cubic-bezier(0.22, 1, 0.36, 1);
}
.tw-knob::after { /* 中心轴帽——盖住放射纹的中心（不然纹路会收成一个脏点） */
  content: '';
  position: absolute;
  inset: 26px;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, var(--tw-body-lit), var(--tw-body-dark));
  box-shadow: inset 0 -2px 4px rgba(0, 0, 0, 0.38), 0 1px 2px rgba(0, 0, 0, 0.18);
}
.tw-knob-l { left: 50px; }
.tw-knob-r { right: 50px; }
/* 字锤扇形：机身上沿正中那个凹进去的黑色扇形槽，里面是一排字锤
   （.tw-bar，JS 生成）。每敲一个字随机挑一根往上弹一下（strikeMachine），
   这是整台机器"在工作"的主要动静。 */
.tw-segment {
  position: absolute;
  left: 50%; top: 10px;
  width: 468px; height: 72px;
  transform: translateX(-50%);
  border-radius: 234px 234px 14px 14px / 72px 72px 14px 14px;
  overflow: hidden;
  background: radial-gradient(120% 150% at 50% 118%, #4a453d 0%, #26221d 55%, #16130f 100%);
  box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.75), 0 1px 0 rgba(255, 255, 255, 0.35);
}
.tw-bar {
  position: absolute;
  bottom: 0;
  width: 5px;
  border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, #8d867a 0%, #46413a 34%, #14120f 100%);
  transform-origin: 50% 100%;
}
.tw-brand {
  position: absolute;
  left: 0; right: 0; bottom: 22px;
  text-align: center;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 0.86rem; font-weight: 700; letter-spacing: 0.34em; text-indent: 0.34em;
  color: color-mix(in srgb, var(--tw-body-dark) 76%, #fff);
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.45), 0 -1px 0 rgba(0, 0, 0, 0.3); /* 压印进机身，不是印上去的 */
  opacity: 0.85;
}
/* 压纸杆：横在纸面**前方**的那根细金属杆 + 两个小压纸轮（参照图②里滚筒
   上方横过纸面的那根）。它压在纸的前面，所以属于机器这一层（z-index 2）。 */
.tw-bail {
  position: absolute;
  left: 74px; right: 74px; bottom: 222px; /* 比滚筒顶(200px)再高一点，中间露出一小段纸，才看得出纸是从滚筒里出来的 */
  height: 5px;
  border-radius: 3px;
  background: linear-gradient(180deg, #ded9ce 0%, #9d9789 45%, #605b52 100%);
  box-shadow: 0 2px 5px -2px rgba(30, 24, 16, 0.5);
}
.tw-bail i {
  position: absolute;
  top: -6px;
  width: 32px; height: 17px;
  border-radius: 9px;
  background: linear-gradient(180deg, #4c4740, #211e1a);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22);
}
.tw-bail i:first-child { left: 20%; }
.tw-bail i:last-child { right: 20%; }

/* .option 现在只用在"去漫游记录"这个 CTA 上（见下面 .option-cta）——挖空位
   本身的候选项已经改成档案抽屉的样式，见下面 .drawer / .file-tab。 */
.option {
  position: relative;
  font-size: 1.25rem; letter-spacing: 0.05em; cursor: pointer;
  padding: 0.9rem 1.3rem; opacity: 0.85;
  border: 1px solid rgba(0, 0, 0, 0.16);
  border-radius: 2px;
  transition: opacity 0.2s, border-color 0.2s, background-color 0.2s;
}
.option:hover {
  opacity: 1;
  border-color: var(--scent-accent, rgba(0, 0, 0, 0.4));
  background-color: rgba(0, 0, 0, 0.03);
}
.option-cta {
  /* 2026-09-01：文字颜色从 --scent-accent 改回墨色。香型强调色里有两款是很浅的
     （阳台的夜 #A1D6D9 浅蓝、月夜银桂 #F6AB00 亮橙），浅色字打在米白纸底上
     几乎看不见——完成态整屏只剩这一个按钮的时候尤其明显。香型色留在边框上
     做识别就够了，正文一律用墨色，这跟全站"纸+墨"的处理也一致。 */
  margin-top: 1rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-indent: 0.14em;
  color: color-mix(in srgb, var(--ink) 88%, #4a3a20);
  border-color: color-mix(in srgb, var(--scent-accent, var(--ink)) 55%, rgba(74, 50, 22, 0.5));
}
/* CTA 选中时的确认反馈，复用抽屉那套"抽走"动画（沿水平方向直接滑出并淡出） */
.option.selected {
  animation: option-pull-out 0.4s cubic-bezier(0.3, 0, 0.4, 1) forwards;
  pointer-events: none;
  position: relative;
  z-index: 5;
}
@keyframes option-pull-out {
  0% {
    transform: translateX(0);
    opacity: 1;
    background-color: var(--scent-solid, var(--ink));
    border-color: var(--scent-solid, var(--ink));
    color: var(--paper);
  }
  55% { transform: translateX(70px); opacity: 1; }
  100% { transform: translateX(170px); opacity: 0; }
}

/* 2026-08-20 第七版：用户完整讲清楚了整个交互流程（不只是视觉），是一次
   架构级的改动，推翻了第五/六版里"抽出来落进抽屉上方一个固定大小展示台"
   这个设计：
   ①触发后先出现一个"关闭的抽屉"，颜色对应这款香型（--scent-primary/accent）
   ②手势把抽屉往下拉开，才露出里面一沓文件（原来的梯形+file-tab 堆叠）
   ③捏合手指、轻轻上提 = 预览（拖拽过程中句子若隐若现地展开，这部分逻辑
     完全没变——用户明确说了这就是他想要的样子）
   ④拖得够远松手 = 确认（判定标准还是"距离够不够远"，隔空手势量不出真实的
     "力度"，这个也是用户明确认过的）
   ⑤确认后不再是落进一个跟抽屉等宽的小卡片，而是飞成一个几乎占满屏幕的
     大屏展示（.file-tab.spotlight），停留约4秒
   ⑥然后缩小、飞去屏幕右边归档（.file-tab.docked，落进 #dock-rail 里排队），
     再回到下一个挖空位——这时候又是一个新的"关闭的抽屉"，要重新拉开
   之前第六版为了让"预览区"和"抽出来的文件"严格等宽做的 .drawer-stage +
   --drawer-inset 那套精确对齐机制，连同它换算出来的 aspect-ratio/padding-top
   公式，在这一版里全部作废——"预览区"这个概念本身不存在了，确认后的大小
   由 .spotlight 单独决定，不再需要跟抽屉自身的宽度锁死。
   "确认后飞去大屏"和"大屏缩小归档"这两段动画都用同一个 flip() 工具函数
   实现（FLIP 技术：First-Last-Invert-Play），定义在 js/customize.js。 */
/* 2026-08-21 第八版：用户给了5张具体参照图，要求换一套视觉风格——推翻第
   六/七版的线稿/描边风格，改成"实色文件夹"：
   - 抽屉正面/文件条不再是描边+纸色填充，而是纯色色块（参照 Panasonic VIP
     文件夹、WELCOME/VIP/ISLANDERS/BATCH2 那张分层色块图）
   - 颜色用用户给的四色卡——实测这四个颜色其实就是四款香型各自
     colorPrimary/colorAccent 里更鲜艳的那一个（见 data.js 的 colorVivid
     字段和它的注释），不是新配色，是"这四款香在这类场合该用哪个颜色"的
     确认
   - 排列参照 WELCOME 那张：一沓色块从上到下层叠，每一块顶部探出一个圆角
     标签（不再是两侧探出的矩形标签），标签文字直接写在这个凸起的小标签上
   - 文字展示参照 Cleveland Institute 那张信封：被选中/预览的句子文字用一
     个彩色高亮块衬底，像马克笔划重点，而不是纯文字
   这一版之后 .drawer-trapezoid 不再需要自己画一层描边背景（色块本身已经
   足够撑起"一沓文件"的形状），线稿风格用的 --linework 在这个组件里基本
   退场，只在很少几处需要区分层次的地方还用一点点。 */
/* 2026-08-21 第九版：用户反馈第八版"实色色块"方向本身不对——不要科技感，
   要"写实打印质感"，要有一点"真的在调阅档案"的触感。给了两张参照：Hank's
   Gift Card（暖米卡纸、斜切角开窗、里面嵌一张小卡）定"抽出来的文字卡片"该
   长的样子；一张实拍的小抽屉柜照片定"关闭的抽屉"该长的样子。追问确认后，
   互动逻辑本身是对的（抽屉→拉开→文件堆叠→抽出来看→确认→归档），问题集中
   在"风格、颜色搭配、互动效果"——具体说抽屉"不像抽屉，表达力不够，没有
   让人想去拉开它的感觉"。这一版先只重做关闭状态的抽屉这一个组件：
   - 加一个真的"能抓"的把手（凹陷的沟槽，靠内阴影撑出立体感，不是一根细线）
   - 抽屉面和外面柜体之间做出接缝阴影（暗示"这块是能被抽出来的独立部件"）
   - 抽屉面本身不再是纯色平涂，叠一层细腻噪点纹理（SVG feTurbulence 生成，
     不需要额外图片素材）+ 一道柔和的光线渐变，模拟哑光材质在柔光下的样子
   - 颜色整体从"饱和数字色块"调成"哑光染色卡纸/木质"——用 color-mix 把
     colorVivid 往米白纸色（比 --paper 更暖一点的 #ece4d3）方向调淡调哑光，
     不再是原始饱和度的实色
   （抽出来的文字卡片、回形针夹纸条那部分还没动，等这版抽屉确认了方向再改） */
/* 2026-08-21 第十版：用户明确否掉了翻盖旋转，给了精确的结构性要求——
   "做4层抽屉，能拉开的只有对应颜色的那一格"。追问确认了两件事：①这4层
   对应四款香型自己的 colorVivid 颜色，不是随便凑数；②不能交互的那几格
   要跟能交互的这格一样精致（把手、接缝阴影、纸纹理都要有），不能偷工减料
   简化成平涂色块。这是这一版真正要解决的问题——之前几版死磕"单独一格
   怎么做才像抽屉"，用户已经点破根源是"抽屉柜本来就不可能只有一格"，
   所以现在老老实实做一个真的4格柜子：.drawer-cabinet 是柜体外框，四个
   .drawer-unit 按 data.js 里 SCENTS 的固定顺序（hotel_room→sunday_afternoon→
   balcony_night→moonlit_osmanthus）从上到下排列，每个用各自的
   colorVivid（内联在 --unit-vivid 上，见 js/customize.js 的 renderBlankStep）；
   只有 unit.active（对应 STATE.scentId 当前这一款）挂了拖拽手势、显示
   leadIn 文字和"拖开抽屉"提示、装着 .drawer-trapezoid 文件堆叠，其余三格
   是 .drawer-unit.inert——同样的 .drawer-face 结构和视觉细节，只是不接
   任何 pointer 事件、没有文字内容、鼠标样式是 default 不是 grab。
   拉开的动效也从"翻盖旋转"换成更朴素直接的"手风琴展开"：.drawer-face
   本身不再挪动/旋转，拉开之后只是收起过渡态的阴影反馈；真正在动的是
   .drawer-trapezoid-wrap 用 CSS Grid 的 grid-template-rows 从 0fr 展到 1fr
   （比 max-height 猜一个足够大的数字更稳妥，不会因为内容多少不同而被切
   掉或者动画时间对不上），在这一格自己的抽屉正面下方展开，不影响上下其他
   三格的位置——效果是"这一格抽屉的正面掀开一条缝，看得见里面装的文件"，
   而不是整块东西转走或消失。 */
/* 2026-08-24 第三次修正，这次是用户明确点破的核心要求："柜体不动，只动
   抽屉，不影响抽屉的显示"——现实里拉开一个抽屉，柜子的外壳（四周的框）
   是纹丝不动的，会动的只有抽出来的那部分。之前两版（写死 780px / 按
   cabinetBaseHeight+px 精确内联计算）都还是在"柜体本身要不要跟着拉开的
   深度一起变高"这个框架里打转，只是把变化量从拍脑袋改成算得更准，但
   柜体本身仍然会动，跟用户要的"柜体压根不该动"不是一回事。
   现在的做法：`.drawer-cabinet` 彻底不再有任何 JS 驱动的高度变化（没有
   min-height 内联样式、没有 transition），永远保持"四格关闭时"的自然
   高度，柜体外壳的四个圆角/内凹阴影全程原地不动。能交互的这一格拉开时，
   `.drawer-trapezoid-wrap` 往下长出来的内容直接探出柜体的下边界，落在
   柜体外面的页面空白背景上——不再用 overflow:hidden 裁掉，就是让它显式
   地"伸出来"，跟真实抽屉拉开后一截探出柜子外沿是同一个视觉逻辑。这样
   做不会撞见 2026-08-21 那次真正的 bug（见下面 .drawer-unit 那条说明：
   探出来的内容会盖住柜体里其他格子），因为能交互的这一格从那次改动起
   就一直固定排在四格的最后一个，它下面本来就没有别的格子——探出去的
   部分下面只有空白页面背景，不会压到任何东西。 */
.drawer-cabinet {
  position: relative;
  padding: 14px 12px;
  background: color-mix(in srgb, var(--scent-vivid, var(--scent-primary, var(--paper))) 8%, #ece4d3);
  background-image: var(--paper-grain);
  background-blend-mode: multiply;
  border-radius: 10px;
  box-shadow: inset 0 2px 5px rgba(30, 24, 16, 0.12); /* 柜体本身也有一圈很浅的内凹阴影，暗示这是个真的盒子，不是纯装饰边框 */
}
/* 2026-08-21 用户实测反馈：拉第一下应该出现5份——上一版每层拉出的深度是
   DRAWER_MAX_EXTENSION 按挖空位数量硬性均分（3层各86px左右），跟候选文件
   实际需要的高度（5份堆起来轻松超过300-400px）毫无关系，装不下自然被裁掉，
   已经在 js/customize.js 里改成按内容实测高度（scrollHeight）决定每层该
   拉多深，不再是拍脑袋均分。
   2026-08-21 用户反馈"拉开了这个抽屉不代表别的抽屉不存在了"——最早那版
   靠"把其余三格收窄让地方"来解决内容被裁的问题，收窄到用户都认不出那是
   "三个抽屉"了。真正的根源不是"没地方"，是能交互的那一格如果排在中间，
   它往下长出来的内容会直接盖在下面几格上面——现在能交互的这一格永远排
   在四格最后一个（见 js/customize.js 的 buildCabinet），它下面没有别的
   格子会被盖住，所以另外三格不再需要收窄，从头到尾都是原尺寸、一样精致，
   也是上面 .drawer-cabinet 那条"柜体不动、抽屉探出去也不会压到别的格子"
   能成立的前提。 */
.drawer-unit {
  position: relative;
  margin-bottom: 6px;
}
.drawer-unit:last-child { margin-bottom: 0; }
/* 2026-08-21 第十一版：用户讲清楚了完整故事线，"三份"其实是指这一款香型
   模板里的 3 个挖空位（不是单个挖空位的候选项数量，候选项还是 5 个，选
   哪个的机制不变）——同一个抽屉要在整个③定制过程里越拉越深：拉一次进
   第①个挖空位，选完再拉一次进第②个（拉到2/3深），再拉一次到底（3/3）
   进第③个，而不是像之前那样每个挖空位都重新关上重新拉一次。还给了一张
   床头柜抽屉连续拉出的实拍参照——关键差异是抽屉正面（带把手那块）本身
   要跟着一起往外/往下移动，不是钉死在原地、只有它背后一块抽象的"内容区"
   在长高（之前那版正是这样，读起来像内容凭空出现在一块固定的牌子后面，
   跟"抽屉被拉深了"没有因果关系）。
   现在 .drawer-face（active 那格）和 .drawer-trapezoid-wrap 都改成
   position:absolute，从同一个起点（unit 顶部，也就是关闭时抽屉面所在的
   位置）出发：wrap 的高度 = 当前拉出的深度 px，从这个起点往下长；face 用
   同一个 px 值做 translateY，永远贴在 wrap 底边正下方——两者像一个整体
   一起往外移动，face 是这个不断加深的"抽屉"最前沿的唇边，wrap 是它身后
   露出来的内腔，深度数值由 js/customize.js 的 setupDrawerStageDrag 统一
   驱动。.drawer-unit.active 需要一个跟关闭态抽屉正面等高的 min-height，
   因为 face/wrap 变成绝对定位后不再撑开 unit 自己的文档流高度，柜子里这
   一格的"关闭时占位"得靠这个 min-height 单独保证。 */
/* 2026-08-31：能交互的这一格不再固定排在四格最后（见 js/customize.js 的
   buildCabinet），它可能排在中间，拉开时往下长出来的内容会压到下面几格上。
   这是**对的遮挡关系**——抽屉是朝使用者这一侧拉出来的，本来就在下面那几格
   的前面——但要显式抬 z-index 才成立，不然按 DOM 顺序反而是下面那几格盖住
   它。这条替代了 2026-08-21 那个"把 active 排到最后一格"的绕法。 */
.drawer-unit.active { min-height: 132px; z-index: 5; } /* 2026-09-02 跟 .drawer-face 一起加高，见那边 */
.drawer-unit { z-index: 1; } /* 只是 JS 跑起来之前的兜底值——真实高度由 js/customize.js 的 renderBlankStep 按 activeFace.scrollHeight 实测内联覆盖，见那边注释，改这个数字没用 */
.drawer-face {
  /* 每一格抽屉的正面——不管是能交互的那格还是背景的三格，视觉细节完全
     一样（用户明确要求"跟交互那格一样精致"）：染色卡纸质感的哑光颜色
     （跟暖米色 color-mix，不是原始饱和度直接实填）、细腻噪点纹理、柔和
     光线渐变、跟柜体之间的接缝阴影。颜色统一走 --unit-vivid 这个内联变量
     （每个 .drawer-unit 自己设一份，见 renderBlankStep），不再用全局的
     --scent-vivid——那个现在只代表"当前定制的这一款"，四格里只有一格该用
     它，其余三格要用它们自己对应香型的颜色。 */
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  /* 2026-09-02 用户测试：78px 高的抽屉正面隔空压不准，加到 132 */
  min-height: 132px;
  margin: 0 4px;
  padding: 1rem 1.5rem;
  border-radius: 4px;
  background: color-mix(in srgb, var(--unit-vivid, var(--paper)) 62%, #ece4d3);
  background-image:
    linear-gradient(155deg, rgba(255, 253, 245, 0.32) 0%, rgba(255, 253, 245, 0) 32%, rgba(30, 24, 16, 0.05) 78%, rgba(30, 24, 16, 0.12) 100%),
    var(--paper-grain);
  background-blend-mode: normal, multiply;
  color: var(--ink);
  box-shadow:
    inset 0 4px 6px -3px rgba(30, 24, 16, 0.26),
    0 3px 6px -2px rgba(30, 24, 16, 0.18);
  transition: box-shadow 0.2s ease, min-height 0.3s ease, padding 0.3s ease, opacity 0.3s ease;
}
/* 能交互的那一格——加手势/鼠标可拖拽的样式反馈；其余三格保持 cursor:default，
   不给出"可以拉"的暗示，因为它们确实拉不动。 */
.drawer-unit.active .drawer-face {
  /* 2026-09-01：这一格平时就探出一道缝（js 的 DRAWER_AJAR_PX），所以它的落影
     要比其余三格重一档——探出来的抽屉面会在下面那一格上投影，这是"它比别人
     突出来了"的立体依据。只靠位移不加影子的话，扫一眼只觉得"这格位置有点怪"，
     不会读成"这格是拉出来的"。 */
  box-shadow:
    inset 0 4px 6px -3px rgba(30, 24, 16, 0.26),
    0 8px 14px -5px rgba(30, 24, 16, 0.42),
    0 2px 4px rgba(30, 24, 16, 0.2);
  position: absolute;
  top: 0;
  left: 4px;
  right: 4px;
  z-index: 21; /* 比 .drawer-trapezoid-wrap 高一档，是这个不断加深的抽屉最前沿的"唇边" */
  cursor: grab;
  touch-action: none; /* 不然触屏/触控板拖拽会被浏览器当成滚动手势 */
  /* transform（translateY，多深就设多少 px）由 js/customize.js 的
     setupDrawerStageDrag 直接内联设置，不再用 CSS 变量间接驱动——现在这个
     值同时也要喂给 .drawer-trapezoid-wrap 的 height，两处必须是同一个数，
     写在 JS 一处地方管理最不容易两边算出不一样的值。 */
  transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.2s ease;
}
.drawer-unit.active .drawer-face.dragging { transition: none; cursor: grabbing; }
.drawer-unit.active .drawer-face.past-threshold {
  box-shadow:
    inset 0 4px 6px -3px rgba(30, 24, 16, 0.26),
    0 1px 3px -1px rgba(30, 24, 16, 0.14); /* 拉过这一段阈值了，阴影收紧一点，提前给个"再拉就到下一层了"的暗示 */
}
/* 2026-08-24 用户给了实物参照——一张带四角小铆钉的透明卡槽标签牌，要求
   四格抽屉都在左上角挂一个这样的牌子，写这一格对应香型的中英文名字。
   四角的小圆点用四个 radial-gradient 叠在背景里画出来，不用额外加 DOM
   节点；牌子本身用比抽屉正面本身更浅、更"塑料感"的米白半透明底色，跟
   抽屉染色卡纸的哑光质感拉开一点区别，读起来像另外嵌上去的一个小物件，
   不是抽屉正面本身画出来的花纹。 */
.drawer-name-tag {
  /* 抽屉正面左上角的标签牌。2026-08-24 第一版按用户给的"四角小铆钉透明
     卡槽"实物照片做成半透明塑料卡槽 + 四个 radial-gradient 画的铆钉。
     2026-08-31 用户给的两张新参照图里，这个位置是**金属标签框**（带切角的
     金属外框 + 里面嵌一张印好的小卡），跟着"质感不对"这条一起升级成金属：
     外框是上亮下暗的金属渐变，四角用 clip-path 切掉（参照图里金属框的切角
     造型），里面用 ::before 嵌一张米白印刷卡。铆钉去掉了——不是漏掉，是
     新参照里的金属框本身没有铆钉，切角就是它的造型特征；这条覆盖 08-24
     那版的做法，别再改回去。
     位置（左上角）和"四格统一固定尺寸"这两条是 08-24 用户明确定过的，
     这次没动。 */
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  /* 2026-08-24 用户反馈四格标签牌大小不一（原来是跟着文字内容自适应宽度，
     "月夜银桂/MOONLIT OSMANTHUS" 比"酒店房间/HOTEL ROOM"宽出一截）——改成
     四格统一固定尺寸，宽度按最长的英文名（MOONLIT OSMANTHUS/SUNDAY
     AFTERNOON，17个字符）实测需要多宽定的，短名字的牌子里就是多留白，
     这正是"标签牌大小一样"这件事本身要的效果，不是 bug。 */
  width: 116px;
  height: 34px;
  padding: 5px 9px 4px;
  background:
    linear-gradient(180deg, #f2f0ea 0%, #cfcabd 26%, #a49d8e 62%, #cbc6b8 100%); /* 金属外框 */
  clip-path: polygon(5px 0, calc(100% - 5px) 0, 100% 5px, 100% calc(100% - 5px), calc(100% - 5px) 100%, 5px 100%, 0 calc(100% - 5px), 0 5px);
  box-shadow: 0 1px 3px rgba(30, 24, 16, 0.3);
}
.drawer-name-tag::before {
  /* 金属框里嵌的那张印刷小卡 */
  content: '';
  position: absolute;
  inset: 3px;
  background: #fbf7ec;
  box-shadow: inset 0 0 0 1px rgba(58, 44, 24, 0.3), inset 0 1px 2px rgba(30, 24, 16, 0.16);
}
.drawer-name-tag .cn,
.drawer-name-tag .en { position: relative; z-index: 1; } /* 压在上面那张卡之上 */
.drawer-name-tag .cn { font-weight: 700; font-size: 0.68rem; letter-spacing: 0.03em; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.drawer-name-tag .en { font-size: 0.5rem; letter-spacing: 0.02em; text-transform: uppercase; opacity: 0.6; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.drawer-face-handle {
  /* 拉手。2026-08-21 第九版是一根细的凸起拉杆+两端铆钉；2026-08-31 按新
     参照图改成档案柜那种**嵌在正面里的扁金属拉手**：一块带切角的金属底板
     （跟上面标签牌同一套金属渐变，同一个柜子上的五金件应该是同一种材质），
     中间一道横向的凹槽就是手指伸进去勾的地方（靠 ::before 的内阴影做出
     "凹进去"，不是画一条线）。四格统一都有，不能交互的那三格只是没有文字
     标签和提示语。 */
  position: relative;
  width: 116px;
  height: 26px;
  border-radius: 2px;
  background: linear-gradient(180deg, #f2f0ea 0%, #cfcabd 30%, #a49d8e 68%, #d3cec1 100%);
  clip-path: polygon(4px 0, calc(100% - 4px) 0, 100% 4px, 100% calc(100% - 4px), calc(100% - 4px) 100%, 4px 100%, 0 calc(100% - 4px), 0 4px);
  box-shadow: 0 2px 4px rgba(30, 24, 16, 0.32);
}
.drawer-face-handle::before {
  /* 中间凹进去的横槽——手指勾的地方 */
  content: '';
  position: absolute;
  left: 10px;
  right: 10px;
  top: 7px;
  height: 12px;
  border-radius: 2px;
  background: linear-gradient(180deg, #6f695c 0%, #8d8778 55%, #cdc8bb 100%);
  box-shadow:
    inset 0 2px 3px rgba(16, 10, 4, 0.6),
    inset 0 -1px 0 rgba(255, 255, 255, 0.5);
}
/* 2026-09-01：.drawer-face-hint（写在抽屉正面上的"拖开抽屉"）已删除，提示挪到
   了画面顶端的 .step-hint 小边框里。 */
/* 画面顶端的操作提示——一个克制的小边框，跟③屏其他元素一样是纸+墨，不是
   界面控件：细实线框、无填充、字距拉开。位置在 .scent-tag 和柜子之间居中。 */
/* 2026-09-06：去掉那个灰色描边小方框。操作提示是一句耳语，不是一个控件——
   框起来反而像个按钮，在这种纸感画面里也是最扎眼的一块 UI 感。 */
.step-hint {
  align-self: center;
  flex-shrink: 0;
  margin-bottom: 30px;
  padding: 7px 20px 8px;
  border: none;
  font-size: 0.8rem;
  letter-spacing: 0.22em;
  text-indent: 0.22em;
  color: color-mix(in srgb, var(--ink) 78%, #5a4526);
  opacity: 0;
  transition: opacity 0.3s ease;
}
.step-hint.visible { opacity: 0.85; }
/* 2026-08-21 第十一版：跟 .drawer-face 是同一个起点（unit 顶部，即关闭时
   抽屉面的位置）往下长的"内腔"——高度就是当前拉出的深度 px，由
   js/customize.js 的 setupDrawerStageDrag 统一驱动，跟 .drawer-face 的
   translateY 用的是同一个数字，两者永远严丝合缝地贴在一起（wrap 的底边
   正好是 face 的顶边），不会再出现"内容原地长高、正面钉在原地不动"的
   割裂感——face 是这个越拉越深的抽屉最前沿的唇边，wrap 是它身后露出来的
   内腔，整体感觉是同一个东西在往外/往下移动。 */
.drawer-trapezoid-wrap {
  position: absolute;
  top: 0;
  left: 4px;
  right: 4px;
  height: 0; /* 由 JS 内联设置，跟 .drawer-face 的 translateY 用同一个 px 值 */
  /* 2026-09-01：从 overflow:hidden 换成只裁下边的 clip-path。
     用户："纸抽出来是可以挡住后面的其他层的抽屉的"，但抽出来的那张档案卡一直
     被裁掉左右两边（截图可见"漫游记录"卡的左边框整个没了）。
     根因：抽屉开合动画要靠这个容器裁剪——高度 0→depth，内容随之露出来——所以
     必须裁。但**真正需要裁的只有下边**（那条边就是"抽屉口"）：容器顶部以上、
     左右两侧本来就没有内容，裁不裁都一样，唯独会把**被抽出来、既往上提又比
     抽屉宽**的那张纸切掉。
     inset(-1000px -600px 0 -600px)＝上/左/右各放开一大截、下边照常裁在 0，
     开合动画完全不受影响，抽出来的纸却能越出抽屉去盖住上面几格。 */
  overflow: visible;
  clip-path: inset(-1000px -600px 0 -600px);
  z-index: 20; /* 比 .drawer-face 低一档，不会盖过自己的"唇边"；能交互的这一格永远排在四格最后一个（见 js/customize.js 的 buildCabinet），下面没有别的格子，不需要再考虑盖住谁的问题 */
  /* 2026-08-24 去掉了这里原来的 filter: drop-shadow(...)——那是"柜体会跟着
     撑高"那版留下的，投影落在被盖住的下一格上强调"悬在前面"；现在柜体不动、
     这一截直接探出柜体边界落在页面空白背景上，用户截图指出这圈投影在探出
     来的位置糊出一道很明显的浅色斜切阴影，不像"抽屉探出来"，倒像画错了一
     道光。柜体自己已经有 box-shadow 撑出立体感，.drawer-trapezoid 自己也有
     inset 阴影表现"内腔"，不需要再靠这层额外的 drop-shadow 强调"悬浮感"。 */
  transition: height 0.3s cubic-bezier(0.2, 0.8, 0.2, 1); /* 跟 .drawer-face 的开合动画用同一条时长/曲线——两者必须严丝合缝贴在一起（见上面的说明），时长/缓动不一致的话收放到一半会有一瞬间对不齐，2026-08-24 发现过一次两者时长不一样导致的脱节，统一成同一条曲线后不会再有 */
}
/* 2026-08-21 用户反馈："抽出来没有文件查阅的感觉，文件肯定是在抽屉里排列，
   抽屉表层应该在最外面"——之前文件堆叠只是平铺展开在页面背景上，跟"抽屉"
   这个容器没有视觉关联，感觉像是凭空出现的一份列表，不是"打开抽屉、看见
   里面装着的文件"。现在给文件堆叠包一层"抽屉内腔"——比文件本身更暗、
   带一圈向内凹的阴影（模拟抽屉正面的"唇边"往里投的影子，暗示光线是从
   前面照进来的，越往里越暗），文件们收在这个凹进去的暗色内腔里，才有
   "东西被装在容器里"的感觉，而不是漂在页面上。 */
/* 2026-08-21 又反馈了一版："现在这个像百叶窗，不是抽屉"——上一步给整叠
   文件套了一个 perspective+rotateX，让它们变成同一个刚性平面统一往后倾斜，
   数学上必然是一组等距离、等角度的平行梯形，这正好就是百叶窗/窗帘那种
   规律重复图案的定义，跟"一沓有各自形状、错落不齐的文件夹"完全是两回事。
   现在把整体倾斜去掉，改成让每一份文件自己的标签变成真的文件夹缺角形状
   （clip-path 斜切一个角，见下面 .file-tab-label），用"每一份的形状不是
   规规矩矩的矩形"来打破重复感，而不是用"整体倾斜"这种会制造更强规律性的
   手法。纵深感当时靠 --depth 控制的宽度差异来给。
   2026-08-24 用户要求所有文件统一长度——宽度差异去掉了，纵深感现在只靠
   --depth 控制的颜色深浅（越靠近抽屉口越深）来表达，见下面 .file-tab 的
   width。 */
/* 2026-08-31 第十二版：用户给了两张新参照图，说"抽拉的档案和质感还是不太
   对"——①一个拉开的木抽屉，里面竖着塞满米白卡纸档案夹，每份顶上探出一个
   小小的彩色索引标签（黄绿/浅蓝），最前面那份露出正面：方格纸 + 印好的
   表格抬头（标题栏、ASSIGNMENT UNIT、DR.BY/CH.BY/RATING 这些字段格）；
   ②一份被抽出来的档案立起来、微微后仰，露出整个正面，顶边卡着一个金属
   标签牌。
   跟上一版（第八/九版沿用下来的做法）最根本的差别：**整条带子不该是香型
   色的实色色块，档案本身是米白卡纸，只有顶上那个小索引标签才是彩色的**。
   之前一沓五条饱和色带排在一起，读起来是"色卡/标签列表"，不是"一沓档案"
   ——参照图里颜色的用量极少，绝大部分面积是纸。香型色因此从"整条带子的
   填充色"降级成"索引标签的颜色"，这不是削弱香型识别，是把它放回它在真实
   档案柜里该在的位置。
   纵深不再用颜色饱和度表达，改用光照：--depth 越小＝越靠抽屉里面＝越暗
   （--dim，见 .file-tab），这既是物理上对的（抽屉深处照不到光），也正好
   让最靠外那几份最清楚，视线自然落在能抽的那几份上。
   注意 2026-08-21 那条"像百叶窗"的教训仍然有效：不要给整叠文件套统一的
   perspective+rotateX（那会得到一组等距等角的平行梯形＝百叶窗）。这一版
   的后仰只作用在**被抽出来的那一份**身上（见 .file-tab.past-threshold），
   单个元素倾斜跟整叠一起倾斜是两回事，不会复现那个问题。 */
.drawer-trapezoid {
  position: relative; /* 给下面那层统一打光的 ::after 定位用 */
  /* 同上：木头内腔也只裁下边，否则被抽出来的那张纸在这一层又会被切一次。 */
  overflow: visible;
  clip-path: inset(-1000px -600px 0 -600px);
  /* min-height:100% 是"抽屉不能断开"的双保险：拉开的深度写在 .drawer-trapezoid-wrap
     的 height 上，木头内腔要是比它矮，wrap 底部就会露出一条没有木头的空档，
     木箱和抽屉正面之间看着就断开了（2026-09-01 修过一次，根因是深度用了
     scrollHeight 而木头只有 offsetHeight 高）。就算以后深度的算法又变，
     这一条也能保证木头始终铺满。 */
  min-height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 22px 9px 10px;
  perspective: 900px; /* 只为"被抽出来那一份后仰"服务，其余文件 rotateX 都是 0，等于没影响 */
  perspective-origin: 50% 120%;
  /* 抽屉内腔改成木头——参照图里抽屉body是木的，档案是纸的，两种材质对比
     正是"一沓纸装在木盒子里"的读感来源；之前内腔是跟文件很接近的一种土
     黄色，纸和盒子糊在一起，谁也衬不出谁。木纹用两层 repeating-linear-
     gradient（一层深纹一层浅纹，角度差 3° 让纹理不呆板）叠在一条上深下浅
     的底色渐变上，纯 CSS，不用图片素材。 */
  /* 木纹。上一版是两条 repeating-linear-gradient，周期 22/34px——**数学上
     完美重复的条纹**，跟档案那边"完美规整"是同一个电脑感来源，只是换了个
     地方。改法有两条：①三层条纹的周期取 17/29/41 这种两两互质的数，叠在
     一起要走过 17×29×41 才重复一次，肉眼范围内看不出规律；②再叠两团位置
     不规则的斑块（radial-gradient 的椭圆），木头本来就有深浅不匀的料色，
     纯条纹不管多密都还是布纹不是木头。 */
  background-color: #7d5f3f;
  background-image:
    repeating-linear-gradient(88.4deg, rgba(38, 24, 10, 0.075) 0 2px, transparent 2px 17px),
    repeating-linear-gradient(89.3deg, rgba(38, 24, 10, 0.05) 0 3px, transparent 3px 29px),
    repeating-linear-gradient(90.7deg, rgba(255, 240, 210, 0.04) 0 2px, transparent 2px 41px),
    radial-gradient(ellipse 55% 34% at 22% 26%, rgba(30, 18, 6, 0.16), transparent 72%),
    radial-gradient(ellipse 46% 40% at 78% 68%, rgba(255, 238, 205, 0.07), transparent 74%),
    linear-gradient(180deg, #553c26 0%, #7d5f3f 32%, #684c31 100%);
  border-radius: 0 0 4px 4px;
  box-shadow:
    inset 0 12px 16px -8px rgba(16, 10, 4, 0.65), /* 顶部最暗——挨着抽屉正面"唇边"投下的阴影 */
    inset 0 0 0 1px rgba(16, 10, 4, 0.35),        /* 内壁分界线 */
    inset 3px 0 6px -3px rgba(16, 10, 4, 0.5),    /* 左右两侧的木壁也各投一道，强调这是个有厚度的盒子 */
    inset -3px 0 6px -3px rgba(16, 10, 4, 0.5);
}
/* 罩在整沓档案之上的一层"光"——2026-08-31 第五轮加的，跟 applyPaperJitter
   是同一次修正的两半。
   前面每一份档案自己都有 --dim 表示"插得越里面越暗"，但那是**逐份各算各的**，
   整个抽屉里没有一个统一的光源：左右两边、靠里的角落跟正中间一样亮，抬头看
   处处均匀。均匀就是电脑渲染最典型的签名——真实照片里一定有方向性的光，
   有falloff，有角落里积起来的暗。这一层就是补这个：左右两侧被抽屉木壁挡住
   的地方压暗，最靠里的一条最暗，往外/往中间逐渐亮起来。
   它罩在所有档案**之上**（z-index:5 高于静止档案的 1），所以是一层真正的
   光照，不是每张纸各自的底色——这正是"统一光源"和"各自调色"的区别。
   z-index 特意低于被拖出来那一份的 10：抽出来的档案是被拿到光下看的，
   不该还压着抽屉里的阴影。
   pointer-events:none 是必须的，否则这层会挡住底下所有档案的拖拽手势。 */
.drawer-trapezoid::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background:
    linear-gradient(90deg, rgba(28, 16, 4, 0.3) 0%, rgba(28, 16, 4, 0.06) 9%, transparent 22%, transparent 78%, rgba(28, 16, 4, 0.06) 91%, rgba(28, 16, 4, 0.3) 100%),
    linear-gradient(180deg, rgba(28, 16, 4, 0.3) 0%, rgba(28, 16, 4, 0.07) 10%, transparent 30%);
}
.file-tab {
  /* 一份档案 = 一张米白卡纸。看到的是它竖着插在抽屉里露出来的那一截正面：
     方格纸底 + 顶部两条印刷横线（表格抬头的位置）+ 顶边一道受光的高光。
     --dim 由 --depth 换算：越靠抽屉里面越暗，见上面模块说明。fillers 的
     --depth 是负数，自然就比真候选更暗更"看不真切"，不用另写一套。 */
  --dim: calc((4 - var(--depth, 0)) * 0.012);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: center;
  width: 94%; /* 参照图里档案几乎占满抽屉内宽，只在两侧留一条缝——原来 68% 太窄，读起来像居中摆的卡片而不是塞满的一沓 */
  /* 静止时露出多少由 js 的 applyPaperJitter 按每一份各自算（薄的填充纸 / 厚一些
     的候选纸），走自定义属性而不是内联 min-height——原因见那边的长注释，简单说
     内联样式会把下面 .past-threshold 的展开高度整个盖掉。 */
  --sheet-h: 46px;
  --open-h: 250px; /* 抽出来展开成"一整张纸"的高度，见 .file-tab.past-threshold */
  min-height: var(--sheet-h);
  /* 贴着上一份排，不给索引标签单独留空档——参照图里这一沓是塞满的，标签
     是**压在后一份纸面上**的（每份档案在 DOM 里排在前一份之后，天然画在
     它上面，标签往上探出去正好盖在前一份的下半截上）。第一版给了 22px
     的间距把每份隔开，中间露出一条条木头底，一沓纸就散成了"几条卡片摆在
     木板上"，正是"质感不对"里那个不对。 */
  margin-top: 3px;
  padding: 0.5rem 1.1rem;
  border-radius: 2px 2px 1px 1px;
  /* 纸色抽成变量：顶上那块"抬起来的纸"（见 .file-tab-label）必须跟纸面一模
     一样，才连得上。--tone 是这一张纸自己的深浅偏移（js 的 applyPaperJitter
     给的，±1.5%）——同一沓纸不可能每张一模一样白，这点差别单看一张察觉不到，
     一沓摞起来才有"真纸"的参差。 */
  --card-paper: hsl(43 38% calc(89% + var(--tone, 0%)));
  background-color: var(--card-paper); /* 米白卡纸，不再是香型实色 */
  /* 2026-08-31 第二轮：用户明确"不需要把纸做成参考图里那种格子的"——上一版
     给纸面铺了方格纸 + 表格抬头双横线（那是照着第一张参照图里最前面那份
     工程表格描的），全部去掉。参照图里绝大多数档案夹本来就是**空白米白
     卡纸**，只有最前面那一份恰好是张表格；把表格当成所有档案的通用材质
     是过度概括。现在纸面只留纸本身该有的东西：一道从上往下的柔光 + 纸颗粒。
     文件之间分得清完全靠下面 box-shadow 那组"每张纸自己的厚度"，不靠纸面
     的花纹——这点在去掉格子之后实测仍然成立。 */
  background-image:
    linear-gradient(180deg, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 34%, rgba(96, 72, 40, 0.07) 100%),
    var(--paper-grain);
  background-blend-mode: normal, multiply;
  color: var(--ink);
  cursor: grab;
  touch-action: none; /* 不然触屏/触控板拖拽会被浏览器当成滚动手势 */
  /* --tilt/--nudge-x 是这一张纸"手放进去的"不齐整，见 js/customize.js 的
     applyPaperJitter。放在 translateY/scale 之后：拖拽用的位移和缩放先算，
     这张纸自己的歪斜叠在最后，两者互不干扰。 */
  transform: translate(var(--nudge-x, 0px), var(--pull, 0px)) scale(var(--scale, 1)) rotateX(var(--lean, 0deg)) rotate(var(--tilt, 0deg));
  transform-origin: center bottom;
  box-shadow:
    /* --dim 那层压在最上面：越深的文件被抽屉的阴影盖得越狠 */
    inset 0 0 0 999px rgba(30, 20, 8, var(--dim, 0)),
    inset 0 1px 0 rgba(255, 252, 244, 0.9),       /* 顶边受光的亮边＝纸的厚度 */
    inset 0 -1px 0 rgba(120, 92, 52, 0.12),       /* 底边的暗边——很轻，重了就成了一条条硬横线 */
    0 5px 9px -4px rgba(74, 50, 22, 0.42),        /* 往后一份上投的影——一沓纸分得清主要靠这个软影，不靠硬线 */
    0 1px 2px rgba(74, 50, 22, 0.18);             /* 贴身的一层浅影，纸和纸之间的缝 */
  transition: transform 0.34s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.2s, opacity 0.2s;
  z-index: 1;
}
/* 拖动过程中位移要**跟手**（transform 不能有过渡），但"抽过阈值展开成一整张纸"
   这件事必须平滑——2026-09-01 用户反馈"抽出来单张纸的漫游记录有一种会断一下的
   感觉"，就是这里：原来 .dragging 一刀切 transition:none，min-height 从 46 跳到
   250 是瞬间完成的，手上没停但画面咔一下。所以只让 transform 无过渡，
   min-height/margin 仍然走过渡。 */
.file-tab.dragging {
  transition: min-height 0.26s cubic-bezier(0.2, 0.8, 0.2, 1), margin-bottom 0.26s cubic-bezier(0.2, 0.8, 0.2, 1);
  cursor: grabbing;
  z-index: 10; /* 提到最上层，不被别的文件挡住 */
}
/* 纯装饰的"填充文件"（见 js/customize.js 的 renderBlankStep）——不带标签、
   不接手势，只用来让这一沓文件看起来更满。cursor/touch-action 都要还原成
   默认值，不然会看着能拖但拖不动；pointer-events:none 更进一步保证隔空
   手势/鼠标都不会误落在它们身上触发悬停反馈。 */
.file-tab.filler {
  cursor: default; touch-action: auto; pointer-events: none; /* 看着能拖但拖不动最糟，这三条要一起还原 */
  margin-top: 2px;
  /* 投影必须跟着"薄"一起收紧。默认那组投影（偏移 5px、模糊 9px）是按露出
     40 多 px 的候选纸调的；填充纸只露 11~17px，同一组投影在它身上占掉大半个
     身子，一沓薄纸就糊成一条条深色横带，反而又变成规律条纹（等于把"百叶窗"
     换了个形式请回来）。薄纸挨得紧、投影本来也短，这里收成贴身的一层。 */
  box-shadow:
    inset 0 0 0 999px rgba(30, 20, 8, var(--dim, 0)),
    inset 0 1px 0 rgba(255, 252, 244, 0.85),
    0 2px 3px -1px rgba(74, 50, 22, 0.3),
    0 1px 1px rgba(74, 50, 22, 0.12);
}
/* 掠过（不管是鼠标 hover 还是隔空手势扫过，见 js/gestures.js 的
   updateGestureHover 给的 .gesture-hover）都要有明显反应，像一个"确认信号"
   ——不是选中，只是"我看到你在这上面了"的提示，所以比 past-threshold 浅一档。
   卡纸不好再靠"整块变色"做反馈（那正是这一版要去掉的东西），改成把这一份
   往外提一点点、影子加重——像手指搭在这份文件上把它稍微顶出来。 */
/* 掠过反馈。2026-09-02 用户测试反馈之四："选中之前没有反馈，不知道压中没有"。
   原来只是把这一份的阴影加重一点点——一沓纸本来就每份都有影，加重那一点在
   一米开外完全看不出来。现在改成三件同时发生：**整份纸往上抬 14px 离开
   纸堆**（位置变化是最容易被余光捕捉到的）、描一圈这一款香的强调色边、
   影子明显加重。抬起来这件事本身还兼作"这份是可以被抽的"的提示。 */
.file-tab:hover,
.file-tab.gesture-hover {
  --dim: 0;
  transform: translate(var(--nudge-x, 0px), calc(var(--pull, 0px) - 14px)) scale(var(--scale, 1)) rotateX(var(--lean, 0deg)) rotate(var(--tilt, 0deg));
  box-shadow:
    inset 0 0 0 999px rgba(30, 20, 8, var(--dim, 0)),
    inset 0 0 0 3px color-mix(in srgb, var(--scent-ink, var(--ink)) 70%, transparent),
    inset 0 1px 0 rgba(255, 252, 244, 0.95),
    0 16px 26px -8px rgba(74, 50, 22, 0.55),
    0 3px 6px rgba(74, 50, 22, 0.26);
  z-index: 3; /* 抬起来就要盖住相邻那两份，否则抬了也看不出来 */
}
/* "预览"态——拖过阈值、句子若隐若现地展开了，但手指还没松开。参照图②：
   被抽出来的那一份立起来、微微后仰，露出整个正面。所以这里做三件事：
   ①--lean 让它绕底边后仰（只这一份，不是整叠，见模块顶部说明）；②纸面
   彻底提亮到全白纸（--dim 归零 + 底色更白），像被拿到光下看；③影子放大
   放远，跟还留在抽屉里那几份拉开距离。 */
.file-tab.past-threshold {
  --dim: 0;
  /* 2026-09-02：后仰角度归零。用户连着两次问"抽出来的纸为啥有透明度"——
     其实纸一直是实色（hsl(43 42% 93%)，opacity 1，祖先链也全是 1，都实测过），
     "透明"是 perspective:900px + rotateX 的产物：卡被画成一个**梯形**，两侧
     是斜边，斜边之外露出后面的木头和纸，看上去就是"纸边透出后面的东西"。
     采样也证实了这点——按 getBoundingClientRect 在卡内取色会取到 (90,85,79)
     这种暗色，因为那些点落在梯形外面。
     一张被拿起来看的档案本来就该正对着人，后仰只是装饰，去掉之后纸是一块
     规整的实心矩形，问题自然消失。`.drawer-trapezoid` 上那个 perspective
     留着不动——它只对 --lean 非 0 的元素起作用，现在没有元素用了，
     以后想恢复后仰把这个值改回负数即可。 */
  --lean: 0deg;
  --tilt: 0deg;      /* 抽出来拿到手里看的这一份要摆正——歪着插在沓里是它的静止状态，被拿起来就该正过来 */
  --nudge-x: 0px;
  /* 拖过阈值这一份要"打开"——参照图②里被抽出来的档案是一整张立起来的
     表格纸，不是抽屉里那条窄边。长高 46px 露出更多正面。
     margin-bottom 用等量的负值抵掉：这是个 flex 纵向列表，直接长高会把
     下面几份一起往下顶（拖到一半整叠跟着抖），负 margin 正好抵消这部分
     增量，长出来的部分盖在后一份上面（它 z-index:10、又被 --pull 提起来，
     本来就该盖在那儿）。两个数必须一起改，改一个就会露馅。
     长高这一下是瞬间的（.dragging 那条把 transition 关了）——这不是缺陷，
     阈值本来就需要一个明确的"咔哒"反馈告诉用户"这一份已经算抽出来了"。 */
  /* 展开成一整张纸。高度和"补偿用的负 margin"必须是同一对数算出来的：
     margin-bottom = 静止高度 - 展开高度，这样这一份在文档流里占的总空间不变，
     后面几份不会被顶下去（拖到一半整叠跟着抖）。用 calc 从同两个变量算，
     不再是写死的一对数字，静止高度是每份各自随机的也不会算错。
     纸往下长、下半截被抽屉前沿裁掉是**对的**——参照图②里那份被抽出来的档案
     也是下半截还留在抽屉里，不是整张飘在空中。 */
  min-height: var(--open-h);
  margin-bottom: calc(var(--sheet-h) - var(--open-h));
  /* 展开之后纸面交给 .file-card 那张档案记录卡排版（它是绝对定位铺满整张纸），
     这里不用再管文字位置。 */
  /* 别用接近纯白（原来是 #fbf7ec）——一整张 250px 的纸铺开之后，那个亮度在
     一抽屉暖米色里读成"一块白色面板"，不是纸。只比这一沓里的纸亮一档就够，
     "被拿到光下看"靠的是它比周围亮，不是靠它接近白色。 */
  background-color: hsl(43 42% 93%);
  /* 2026-08-31 第二轮：那几条横向栏位线去掉了——现在纸上是一张有完整版式的
     档案记录卡（.file-card），卡本身就提供结构，再叠一层通栏横线只会跟卡上的
     虚线/大框打架。纸回到干净的米白 + 柔光 + 颗粒。 */
  background-image:
    linear-gradient(180deg, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 34%, rgba(96, 72, 40, 0.06) 100%),
    var(--paper-grain);
  background-blend-mode: normal, multiply;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    inset 0 0 0 1px rgba(58, 44, 24, 0.16),
    0 16px 26px -10px rgba(16, 10, 4, 0.5);
}
/* 2026-08-24：抽出来确认之后不再飞成大屏卡片（.spotlight 那套已删除，见
   下面打字机纸的说明）——"展示"这件事现在交给打字机纸把选中的半句打出来，
   这份候选卡片本身只需要一个简短的"被收走"反馈：轻微放大+淡出，配合
   js/customize.js 里 FILE_CONFIRM_FADE_MS 的延时（等这个过渡播完再让打字机
   继续），不用再停留 4 秒。 */
.file-tab.confirmed {
  cursor: default;
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease;
  opacity: 0;
  transform: scale(0.94) translateY(-8px);
}
/* ---- 索引标签 = 纸自己抬起来的一块，字直接印在上面 ----
   演进（三轮都是同一个病越治越轻，记下来免得又绕回去）：
   ①第一版是"纸边探出来的圆角小舌头"，②第二版改成"贴在纸上的彩色扁平标牌"，
   用户都说"太电子"；③第三版想明白关键是**形状要跟纸连着**（用户原话："你看
   一下这个形状和纸是连着的"），做成了"纸自己抬高一级 + 两侧凹圆角过渡"，
   形状对了；④这一版（2026-09-01）用户说"还是电子感太重，不一定要颜色，但
   要更像纸的一部分"——最后这块电子感来自**那个彩色矩形本身**：不管形状多对，
   只要纸上还贴着一块实色填充的方块，它就是一个"控件"，不是纸。
   所以现在彻底没有"标牌"这个物件了：**标签就是这块抬起来的纸，情绪词直接
   印在纸上**（墨色字，跟这个项目其他地方的文字同一种墨），上下两条细印刷
   线是印上去的栏框——真实档案夹的标签位本来就是这样，纸上印一行字，不是
   另外贴一块彩色塑料片。
   四款香型的颜色轮转随这一版一起去掉了（用户"不一定要颜色"）。要恢复的话：
   css 这里加回 background-color，js/customize.js 的 startCustomizing 里把
   --vivid-1..4 那段加回来即可，颜色源仍是 data.js 的 colorVivid。

   三层结构（都挂在 .file-tab-label 一个节点上，不动 JS/DOM）：
     元素本身 —— 抬起来的那块纸（背景用 --card-paper，跟纸面同一个变量，差一点
                 点就露接缝；靠 padding-bottom 往下探进卡片跟纸面连成一整张）
     ::before —— 情绪词上下的两条印刷细线（原来是彩色标牌，现在改作栏框）
     ::after  —— 两侧的凹圆角过渡；圆弧上带跟纸边同色同粗的轮廓线，少了它
                 台阶会读成"贴了一块方补丁"
   几何：元素 top:-22px，卡片上边缘在局部 y=22；::after 架在 y=15~22 这 7px 上。
   改一个数另外几个都要跟着重算。 */
.file-tab-label {
  position: absolute;
  top: -22px;
  padding: 9px 15px 21px; /* 下内边距把这块纸往下探进卡片，跟纸面连成一整张 */
  font-weight: 700;
  font-size: 0.74rem;
  letter-spacing: 0.2em;  /* 字距拉开＝印在档案标签上的字，不是正文 */
  text-indent: 0.2em;     /* 抵掉最后一个字后面那份字距，视觉上才是居中的 */
  text-align: center;
  white-space: nowrap;
  /* 墨色不用纯黑：印在纸上的字是渗进纤维里的，带一点纸的暖调才像印上去的 */
  color: color-mix(in srgb, var(--ink) 82%, #5a4526);
  background-color: var(--card-paper, #f2ead9);
  background-image: var(--paper-grain);
  background-blend-mode: multiply;
  border-radius: 5px 5px 0 0;
  box-shadow:
    inset 0 0 0 999px rgba(30, 20, 8, var(--dim, 0)), /* 跟着这一份的景深一起变暗，不然抬起的部分会比它自己的纸还亮 */
    inset 0 1px 0 rgba(255, 252, 244, 0.9),           /* 抬起处上边缘的亮边＝纸的厚度 */
    /* 顶边外侧的深色轮廓线——纸的上边缘在平的那一段本来就有一条（上一份纸投
       下来的影），抬起的这一段也得有，整条轮廓才连续。用 `0 -1px 0`（零模糊
       零扩散）而不是带模糊的投影：这块纸的下半截是埋在卡片里的，带模糊的投影
       会在卡片中间糊出一道凭空多出来的横向暗边。 */
    0 -1px 0 rgba(74, 50, 22, 0.26);
  z-index: 2;
}
/* 情绪词上下的两条印刷细线——档案标签上印好的栏框。没有颜色填充之后全靠
   这两条线和抬起的形状把标签位"框"出来，让它在一沓素纸里仍然认得出是个标签，
   而不是纸上随便写了两个字。用 ::before 的上下边框画，比两个伪元素省。 */
.file-tab-label::before {
  content: '';
  position: absolute;
  left: 9px;
  right: 9px;
  top: 5px;
  bottom: 17px;
  z-index: -1;
  border-top: 1px solid rgba(74, 50, 22, 0.42);
  border-bottom: 1px solid rgba(74, 50, 22, 0.42);
}
/* 两侧的凹圆角过渡 */
.file-tab-label::after {
  content: '';
  position: absolute;
  top: 15px;   /* 卡片上边缘在局部 y=22，这 7px 正好垫在它上面 */
  height: 7px;
  left: -7px;
  right: -7px;
  z-index: -1;
  /* 圆弧上也要带同一条深色轮廓线（`7px 8px` 那 1px 环），不然轮廓走到凹角
     就断了——平的一段有线、圆角没线、抬起的一段有线，接缝反而更明显。 */
  background:
    radial-gradient(circle 7px at 0 0, transparent 0 7px, rgba(74, 50, 22, 0.26) 7px 8px, var(--card-paper, #f2ead9) 8px) left top / 8px 8px no-repeat,
    radial-gradient(circle 7px at 100% 0, transparent 0 7px, rgba(74, 50, 22, 0.26) 7px 8px, var(--card-paper, #f2ead9) 8px) right top / 8px 8px no-repeat;
}
/* 标签位置错落——参照图里每份档案的索引标签左右前后都错开，不是排成一列
   也不是简单左右交替（之前是 odd/even 两个位置，五份排下来是"左右左右左"
   的规律锯齿，规律得能一眼看出是程序生成的）。用 5 个位置轮转：这一格里
   前 3 份是无标签的填充文件（见 renderBlankStep），5 份真候选正好落在
   nth-child 4~8 上，对应 66%/82%/6%/26%/46%，散得很自然。 */
.file-tab:nth-child(5n+1) .file-tab-label { left: 6%; }
.file-tab:nth-child(5n+2) .file-tab-label { left: 26%; }
.file-tab:nth-child(5n+3) .file-tab-label { left: 46%; }
.file-tab:nth-child(5n+4) .file-tab-label { left: 66%; }
.file-tab:nth-child(5n+5) .file-tab-label { left: 82%; }
/* 2026-09-01：这里原来是"标签颜色轮转四款香各自的 colorVivid"（4 条
   nth-child(4n+k) 规则），随"不一定要颜色"这条一起删掉了，见上面 .file-tab-label
   那段说明。要恢复的话把那 4 条规则和 js 里的 --vivid-1..4 一起加回来。 */
/* 被抽出来那一份的标签升级成参照图②里那个"卡在档案顶边的金属标签牌"：
   加一圈金属质感的外框和高光。只在 past-threshold 时出现，静止时还是普通
   的纸索引标签——抽出来才看得清它是个金属件，这跟"离得近才看得清"是一致的。 */
/* 抽出来那一份：标签跟着整张纸一起提亮（纸变亮了，印在上面的字和栏框自然
   也在同一片光里），不再另外套一个金属框——金属框跟彩色标牌是同一类东西，
   都是"贴在纸上的另一个物件"，正是这一版要去掉的。 */
.file-tab.past-threshold .file-tab-label::before {
  border-top-color: rgba(74, 50, 22, 0.5);
  border-bottom-color: rgba(74, 50, 22, 0.5);
}

/* ---------- 抽出来那一整张纸上的"档案记录卡" ----------
   2026-08-31 用户给了参照（"雨水观测笔记"那种旧档案卡）并点名了四样东西：
   大抬头「漫游记录」/ 做这次选择的日期时间 / 一个小抬头是对应的情绪词 /
   一个大框里装她选中的那句话。
   参照图是竖版，我们这张纸是横的（约 700×250 设计px），所以版式改成横版排：
   抬头和日期时间同一行分居两端（像表格的页眉），底下情绪词一行，再底下是
   那个占掉大半张卡的大框。四样东西一样不少，只是排布适应横幅。

   【卡必须是 position:absolute + opacity:0 起步】静止时这份档案只露一条边
   （44px），卡面本来就该看不见。用绝对定位它才不会把静止状态的纸撑高（普通
   流会把 min-height: var(--sheet-h) 顶破）；opacity 归 .past-threshold 管，
   跟"纸展开成一整张"同一刻显现。2026-09-01 改标签那次误删过这整块，症状是
   **每一份静止的薄纸上都糊着"漫游记录WANDER HOURS RECORD情绪 EMOTION…"**
   ——一眼就能认出是这块没了。
   pointer-events:none——纯展示层，拖拽手势要照常落在 .file-tab 上。 */
.file-card {
  position: absolute;
  inset: 0;
  padding: 20px 30px 22px;
  display: flex;
  flex-direction: column;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.22s ease;
  color: color-mix(in srgb, var(--ink) 88%, #4a3a20);
}
.file-tab.past-threshold .file-card { opacity: 1; }
/* 2026-09-02 用户："这个排版之前的挺好，现在不好看而且超边问题严重"。
   根字号从 16 一路加到 28 之后，这张卡（宽 724）的抬头一行放不下了：
   "漫游记录"(1.45rem+0.3em字距) + "WANDER HOURS RECORD"(0.68rem+0.22em) 
   加起来已经超过内容宽 664，于是标题折成两行、日期被挤下去压住正文、
   右下角流水号顶到句子上。
   这张卡是**卡片式的表头**，不是正文——它的字本来就该比正文小一档。
   下面几项统一压回原来的观感比例，并且 nowrap 兜底：宁可字距挤一点，
   也不能再折行。**真正要读的那句话（.fc-body）没有跟着变小**，
   "字要大"那条针对的是它。 */
.fc-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  white-space: nowrap;
  padding-bottom: 7px;
  border-bottom: 1px dashed rgba(74, 50, 22, 0.5); /* 参照图里抬头下面那条点线 */
}
.fc-title {
  font-size: 1.0rem;
  font-weight: 700;
  letter-spacing: 0.22em; /* 参照图里大抬头字距拉得很开 */
  text-indent: 0.22em;
}
.fc-sub {
  font-size: 0.46rem;
  letter-spacing: 0.16em;
  opacity: 0.72;
  text-transform: uppercase;
}
.fc-meta {
  margin-left: auto; /* 挤到最右边，跟抬头分居两端，像表格页眉 */
  font-size: 0.5rem;
  letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;
  opacity: 0.72;
}
.fc-field {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-top: 11px;
}
.fc-field-label { /* 参照图里 CATEGORY 那种小号全大写字段名 */
  font-size: 0.5rem;
  letter-spacing: 0.14em;
  opacity: 0.7;
  text-transform: uppercase;
  white-space: nowrap;
}
.fc-field-value { /* 情绪词——参照图里 SPRING RAIN 的位置 */
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-indent: 0.16em;
  white-space: nowrap;
}
.fc-serial { /* 参照图右下角那个流水号，纯档案感 */
  position: absolute;
  right: 30px;
  bottom: 7px;
  font-size: 0.46rem;
  letter-spacing: 0.12em;
  opacity: 0.55;
  white-space: nowrap;
}
/* 大框：卡片主体，装选中的那句话。参照图里那个占掉大半张卡的空框，
   我们把内容放进去。--reveal 让句子在拖动过程中逐渐显形（这段反馈逻辑一直
   没变，只是从"一行带下划线的字"换成了框里的正文）。 */
.file-tab-content {
  flex: 1;
  margin-top: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 20px;
  border: 1px solid rgba(74, 50, 22, 0.45);
  font-size: 1.12rem;
  letter-spacing: 0.06em;
  line-height: 1.6;
  text-align: center;
  opacity: var(--reveal, 0);
  transition: opacity 0.25s;
}
.fc-serial { /* 参照图右下角那个流水号，纯档案感 */
  position: absolute;
  right: 30px;
  bottom: 7px;
  font-size: 0.56rem;
  letter-spacing: 0.16em;
  opacity: 0.42;
}
.file-tab.dragging .file-tab-content { transition: none; }
/* 2026-08-24：原来这里往下是"确认后飞大屏卡片(.spotlight)停留4秒、再缩小
   归档到右边回形针栏(.docked/#dock-rail)"一整套 FLIP 动画——已经被"打字机纸"
   取代（见 js/customize.js 模块顶部说明、css 里 .typewriter-paper 那块），
   确认后的展示和归档现在都在纸上完成，不再需要这两个状态和右侧栏。
   2026-08-28 补：当时说"flip() 留着给 .typewriter-card 的撕下来动画用"——
   那套小卡片已经随打字机改版一起去掉（纸从机器里卷出来，下面就是机身，
   没有地方再落卡片），flip() 也跟着删了。顺带发现它其实一直没生效：它设的
   是 --flip-x/--flip-y/--flip-sx/--flip-sy 四个自定义属性，但从没有任何 CSS
   规则去读这四个变量组成 transform，所以"撕下来"从来就是瞬间出现、没有
   动画。现在纸往上卷那一下（customize.js 的 rollPaper）是直接写 transform
   的，不走自定义属性，不会再有这个问题。 */

#progress { position: absolute; top: 115px; right: 86px; font-size: 0.9rem; opacity: 0.7; } /* 0.6 实测只有 4.33，且这一屏底色随香型变（阳台的夜的 primary 接近黑，底色更深），留足余量 */ /* 原 top:6vh right:8vw，竖屏改成 6%×1920 / 8%×1080 */

/* ---------- 手势教学屏 ----------
   2026-09-01 第三版。用户对第二版的反馈是三条并列的问题：手的姿势读不出"捏合"、
   不该是静态图、整屏排版风格不对。这里解决后两条（姿势那条在 js 里，见
   HAND_TILT 的说明）。
   【排版】原来是 2×2 卡片网格，两个毛病：一是这块屏是 1080×1920 的**竖屏**，
   一个方形网格挤在正中间，上下留下大片空白；二是"卡片网格"是通用 UI 的排法，
   跟这个项目其他地方（档案卡、顶端提示框）那套"纸上印刷品"的语言不搭。
   改成**档案说明单**式的竖排条目：编号 + 图 + 说明，条目之间一条细分隔线，
   抬头下面一条虚线——跟③屏抽出来那张档案记录卡是同一套版式语言。 */
#view-tutorial {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--scent-wash);
  background-image: var(--paper-grain);
  background-blend-mode: multiply;
}
/* 2026-09-02 用户："教学的颜色也要呼应对应线香的颜色"。
   这一屏原来是四款通用的一张白纸，只有背景那层 --scent-wash 有一点点色。
   现在把这一款的代表色（--scent-vivid，跟③屏抽屉正面、便签同一个色）用在
   四个地方：纸顶上的色带、抬头虚线、每行的分隔线、序号。都是**线和小面积**，
   不铺大色块——这张是要读的说明单，正文得留在纸色上。 */
.tut-sheet {
  position: relative;
  /* 2026-09-02 用户："字变大，排版别变"。根字号加到 28 之后 748px 装不下
     一行标题（"漫游记录 · 手势" + "GESTURE GUIDE" 一行要 750+），条目说明
     也开始折行。字号一个没动，**把纸加宽**到 960（1080 的屏两边各留 60），
     排版就回到原来那个"一行一条"的样子了。 */
  width: 960px;
  padding: 54px 48px 46px;
  background: #f7f2e6;
  background-image: var(--paper-grain);
  background-blend-mode: multiply;
  box-shadow: 0 10px 30px -14px rgba(74, 50, 22, 0.4), 0 0 0 1px rgba(74, 50, 22, 0.14);
  color: color-mix(in srgb, var(--ink) 88%, #4a3a20);
  /* 顶上那条色带：像档案夹的包边，一眼认出这一份属于哪一款 */
  border-top: 10px solid var(--scent-vivid, var(--ink));
}
.tut-head {
  display: flex;
  align-items: baseline;
  gap: 16px;
  white-space: nowrap; /* 宁可字距挤一点也不折行，见 .tut-sheet 那条 */
  padding-bottom: 10px;
  /* 跟档案记录卡抬头同一条虚线，颜色兑上这一款的代表色 */
  border-bottom: 1px dashed color-mix(in srgb, var(--scent-ink, #4a3a22) 55%, rgba(74, 50, 22, 0.5));
}
.tut-title { font-size: 1.5rem; font-weight: 700; letter-spacing: 0.3em; text-indent: 0.3em; }
.tut-sub { font-size: 0.68rem; letter-spacing: 0.22em; opacity: 0.68; text-transform: uppercase; }
.tut-grid { display: flex; flex-direction: column; }
.tut-row {
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 16px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--scent-ink, #4a3a22) 26%, rgba(74, 50, 22, 0.16));
}
.tut-row:last-child { border-bottom: none; }
.tut-no { /* 档案编号式的序号，不是圆形步骤点——后者又是通用 UI 的语汇 */
  width: 34px;
  flex-shrink: 0;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;
  /* 序号带这一款的颜色，但不能直接用 --scent-ink：月夜银桂的 ink 是金黄
     #F6AB00，兑淡了在纸上只有 2.10 的对比度（实测）。走 --scent-solid（已经
     保证四款都够深，见 :root 那条），再兑一点纸色让它退到"次要信息"的份量。
     实测四款对比度：酒店 11.10 / 午后客厅 8.89 / 阳台的夜 12.38 / 月夜银桂
     4.83，都过 4.5。也不再靠 opacity 压淡——那是掉对比度的老路子。 */
  color: color-mix(in srgb, var(--scent-solid, var(--ink)) 80%, #9a9184);
}
.tut-icon { width: 96px; height: 96px; flex-shrink: 0; }
.tut-icon svg { width: 100%; height: 100%; display: block; color: var(--ink); overflow: visible; }
/* 箭头/角标：必须显式 fill:none + stroke，否则会继承外层 <g fill="currentColor">
   ——那样箭头的折线会被当成闭合形状**填成一个实心三角**，而直线段没有面积直接
   消失，看到的就是"一个莫名其妙的小黑三角"。2026-09-01 重排版时把这两条规则
   连同旧的卡片样式一起删掉过，就是这个症状。 */
.tut-arrow { fill: none; stroke: currentColor; stroke-width: 5; stroke-linecap: round; stroke-linejoin: round; }
.tut-badge { fill: currentColor; stroke: none; font-size: 19px; font-weight: 700; letter-spacing: 0; }
/* 教学图标里那块小橡皮（05 那条），跟 .tut-arrow 一样是手图标的配件 */
.tut-eraser { fill: none; stroke: currentColor; stroke-width: 4; stroke-linejoin: round; }
.tut-row-text { flex: 1; }
.tut-row-title { font-size: 1.02rem; font-weight: 700; letter-spacing: 0.16em; text-indent: 0.16em; margin-bottom: 5px; }
.tut-row-desc { font-size: 0.82rem; line-height: 1.6; opacity: 0.72; letter-spacing: 0.04em; }

/* ---------- 图标动画 ----------
   用户明确"不该是静态图"。四个手势各有一条循环动画，都在 SVG 内部用 transform
   做，不动布局。
   transform-box:view-box 是必需的：SVG 元素的 transform-origin 默认按自身包围盒
   算，拇指绕"自己的中心"转会甩出去；改成按 viewBox 坐标系算，才能指定"绕拇指
   根部(33,68)转"这个真实的关节位置。旋转角度是负的＝拇指往食指方向合拢。 */
.thumb { transform-box: view-box; transform-origin: 44px 63px; } /* 拇指根部——手形改了这个关节位置要跟着改，js 里的路径和这里必须一致 */
/* 手指之间的分界线：**纸色**描边盖在手上（不是在轮廓里挖空），所以这个颜色
   必须跟 .tut-sheet 的底色一致，改了底色要一起改。真手不是一整块剪影，蜷起的
   手指之间分得开——只画外轮廓的话中间那团永远读成一个疙瘩，这三条线是"像手"
   最关键的一步。 */
/* 手：**直接描自用户给的四格线稿参照**（见 js/customize.js 里 HAND_FRAME_OPEN
   那段说明）。两格叠在一起靠 opacity 互切做翻页动画。
   fill-rule:evenodd 是必须的——描出来的是每根线条的**轮廓环**，用默认的 nonzero
   会把环内也填满，整只手变成一块黑。 */
.hf { fill: currentColor; fill-rule: evenodd; }
.hf-closed { opacity: 0; }
/* 翻页用硬切（关键帧首尾同值＝阶跃），不做渐变：参照本身就是一格一格的线稿，
   硬切更像它，也更能看清"捏上了"这一下。 */
@keyframes hf-once {
  0%, 40% { opacity: 0; }
  46%, 84% { opacity: 1; }
  90%, 100% { opacity: 0; }
}
@keyframes hf-twice {
  0%, 12% { opacity: 0; }
  18%, 30% { opacity: 1; }
  36%, 46% { opacity: 0; }
  52%, 64% { opacity: 1; }
  70%, 100% { opacity: 0; }
}
.anim-pinch-drag .hf-closed { animation: hf-once 3s steps(1, end) infinite; }
.anim-drag-right .hf-closed { animation: hf-once 2.6s steps(1, end) infinite; }
.anim-twice .hf-closed { animation: hf-twice 2.4s steps(1, end) infinite; }
/* 松开：跟"捏合"反过来放——先是捏着的，然后松开 */
.anim-release .hf-closed { animation: hf-release 2.6s steps(1, end) infinite; }
@keyframes hf-release {
  0%, 44% { opacity: 1; }
  50%, 100% { opacity: 0; }
}
/* 只有一只手在移动（松开·移动 / 捏合·移动）：手本身不变形，整只手来回飘 */
.anim-float .hand-move { animation: tut-float 2.8s ease-in-out infinite; }
@keyframes tut-float {
  0%, 100% { transform: translate(0, 0); }
  50% { transform: translate(13px, 0); }
}
/* 捏合·用力上拉：整只手往上窜一下再回来 */
.anim-pull-up .hand-move { animation: tut-pull-up 2.4s cubic-bezier(0.3, 0, 0.2, 1) infinite; }
@keyframes tut-pull-up {
  0%, 22% { transform: translate(0, 0); }
  46%, 62% { transform: translate(0, -16px); }
  86%, 100% { transform: translate(0, 0); }
}
/* 摊开的手（双手那格）仍是描线轮廓 */
.hand-outline {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* .tut-sep 已随第八版重画去掉——新的手用"折起来的中指"那片杏仁表达手指，
   不再需要另画分界线。 */
.hand-move { transform-box: view-box; transform-origin: 50px 62px; }

/* 火花不再单独画——描图用的第 4 格参照本身就带"咔哒"那三道短线。 */

/* 01 捏合并拖动：先合拢，保持捏住的同时整只手移动，再张开 */
.anim-pinch-drag .thumb { animation: tut-close 3s ease-in-out infinite; }
.anim-pinch-drag .hand-move { animation: tut-drag-round 3s ease-in-out infinite; }
@keyframes tut-close {
  0%, 12% { transform: rotate(0deg); }
  26%, 74% { transform: rotate(-17deg); }
  88%, 100% { transform: rotate(0deg); }
}
@keyframes tut-drag-round {
  0%, 30% { transform: translate(0, 0); }
  52% { transform: translate(13px, -9px); }
  70% { transform: translate(0, 0); }
  100% { transform: translate(0, 0); }
}
/* 02 捏合后向右拖：合拢之后一路向右 */
.anim-drag-right .thumb { animation: tut-close 2.6s ease-in-out infinite; }
.anim-drag-right .hand-move { animation: tut-drag-right 2.6s ease-in-out infinite; }
@keyframes tut-drag-right {
  0%, 30% { transform: translate(0, 0); }
  62%, 74% { transform: translate(20px, 0); }
  90%, 100% { transform: translate(0, 0); }
}
/* 03 连续捏合两次：快合快开×2，然后停一拍 */
.anim-twice .thumb { animation: tut-twice 2.4s ease-in-out infinite; }
@keyframes tut-twice {
  0%, 6% { transform: rotate(0deg); }
  14%, 22% { transform: rotate(-17deg); }
  30%, 36% { transform: rotate(0deg); }
  44%, 52% { transform: rotate(-17deg); }
  60%, 100% { transform: rotate(0deg); }
}
/* 04 双手张开：两只手一起拉远再拉近 */
.hand-l, .hand-r { transform-box: view-box; transform-origin: 50px 60px; }
.anim-spread .hand-l { animation: tut-spread-l 3s ease-in-out infinite; }
.anim-spread .hand-r { animation: tut-spread-r 3s ease-in-out infinite; }
@keyframes tut-spread-l {
  0%, 100% { transform: translate(6px, 0); }
  50% { transform: translate(-9px, 0); }
}
@keyframes tut-spread-r {
  0%, 100% { transform: translate(-6px, 0); }
  50% { transform: translate(9px, 0); }
}

/* ---------- 练手区 ----------
   这一屏真正要教会的两件事都在这儿：捏合点在哪、以及必须先松开才能再选一次。
   两个靶心是**空心圆**（不是按钮）——空心圆有一个明确的"圆心"，用户自然会去
   对准它，这正好把"捏合确定的位置＝光标的位置"这件事说清楚了；实心按钮就没有
   这个含义。状态一共四种，见 js/customize.js 的 practiceStage。 */
.tut-practice {
  margin-top: 42px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.tut-practice-hint {
  min-height: 1.5em;
  margin-bottom: 26px;
  font-size: 0.9rem;
  letter-spacing: 0.16em;
  text-indent: 0.16em;
  color: color-mix(in srgb, var(--ink) 78%, #5a4526);
}
.tut-targets { display: flex; flex-direction: column; align-items: center; gap: 26px; }
.tut-target {
  position: relative;
  width: 156px;
  height: 156px;
  border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--scent-ink, #4a3a22) 50%, rgba(74, 50, 22, 0.45));
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.25s, border-color 0.25s, transform 0.25s, background-color 0.25s;
}
.tut-target-dot { /* 圆心那一点——"要对准的就是这里" */
  width: 11px; height: 11px; border-radius: 50%;
  background: color-mix(in srgb, var(--scent-ink, #4a3a22) 70%, rgba(74, 50, 22, 0.55));
  transition: transform 0.2s, background-color 0.2s;
}
.tut-target.hidden { opacity: 0; transform: scale(0.8); pointer-events: none; }
/* 锁着：2 号圆已经出现，但手还捏着，这时候不接受——虚线+压暗表示"还不能用" */
.tut-target.locked {
  opacity: 0.4;
  border-style: dashed;
}
.tut-target.active { opacity: 1; }
/* 光标进圆了、而且手是松开的：给一个明确的"可以捏了"的反馈 */
.tut-target.ready {
  border-color: var(--ink);
  background-color: rgba(74, 50, 22, 0.06);
  transform: scale(1.06);
}
.tut-target.ready .tut-target-dot { transform: scale(1.5); background: var(--ink); }
/* 中了 */
.tut-target.hit {
  border-color: var(--ink);
  background-color: var(--ink);
}
.tut-target.hit .tut-target-dot { background: var(--paper); transform: scale(1.8); }
/* 等待对准时圆圈自己轻轻呼吸一下，指明"该操作这个了"；锁着和已中的不呼吸 */
.tut-target.active:not(.hit) { animation: tut-target-breathe 2.4s ease-in-out infinite; }
@keyframes tut-target-breathe {
  0%, 100% { box-shadow: 0 0 0 0 rgba(74, 50, 22, 0.18); }
  50% { box-shadow: 0 0 0 10px rgba(74, 50, 22, 0); }
}

/* ---------- drawing ---------- */
#view-drawing {
  flex-direction: column;
  justify-content: flex-start;
  position: relative; /* 右侧那一列工具档案夹是绝对定位的，定位上下文在这儿 */
  /* 2026-09-02：④画布原来是唯一一屏完全没有香型色调的（写死 --paper），
     夹在③和⑤中间显得像换了个产品，一并并入同一条配方 */
  background: var(--scent-wash);
}
/* ---- 右侧竖着的那一列工具档案夹（2026-09-03 从屏幕**底部**挪过来）----
   2026-09-02 第一版是横着一叠摆在画布**下方**。用户实测后要求挪走：
   "左边那个像文件夹一样在下面太容易误触了，改到右侧竖着一排"，并给了一张
   手绘：一条竖线（四份文件夹的书脊连成的那条边）＋四个梯形标签**朝左**探出来。
   **为什么底部一定会误触**：那一叠正好压在画布正下方，而画画、擦除、放下
   橡皮擦这些动作本来就在画布下半部分活动，手往下一带就掠过标签——隔空手势
   没有"按下去才算"这层保护，掠过＋捏合就直接选中了。挪到右侧之后，工具跟
   画布在**水平方向**上分开，画画的手不再经过它。
   随之而变的三件事：
     ①抽出方向从"往上"改成**往左**（js/canvas.js 的 setupPullSelect 传 axis='x'）
       ——书脊在右、标签朝左，往左抽才是"把这份文件从架子上抽出来"。
       --pull 的语义没变（负数＝抽出来的位移），只是这里用 translateX 消费它。
     ②卡纸让出右边这一条：#canvas-wrap 的 padding-right 给足 rack 宽度 + 间距，
       画布宽度（js/canvas.js 的 DRAW_CANVAS_W）跟着从 860 降到 786。
       **这两个数是一组的，改一个必须核对另一个**——间距不够时"选中"态往左
       抽出来的文件夹会压到画布上（判据：抽到最左时它的左边缘仍要 > 画布右边缘）。
     ③标签改成**中文竖排**（writing-mode: vertical-rl）：四个字自上而下，标签
       才能又窄又够高——窄是为了给画布留宽度，够高是为了隔空手势瞄得准
       （2026-09-02 那次真人测试的结论：标签太薄就瞄不准）。
   颜色仍然是四款香的 colorVivid（2026-09-02 用户："用我们的产品颜色"）。 */
#tool-folders {
  /* 这一列占的宽度 ＝ 标签 88 + 书脊 64。跟 #canvas-wrap 的 padding-right 是一组。 */
  --rack-w: 152px;
  --tab-w: 88px;
  --folder-h: 204px;
  /* 步距＝高度，四份**紧挨着**，书脊接成一条连续的竖线——手绘图上那条线是
     一整条、不是四段。分界靠 .folder-body / .folder-tab 自己那圈 1px 内描边
     （相邻两份挨在一起就是一条 2px 的暗线），不靠留缝。留缝反而会把"一个
     文件架"读成"四块飘着的色块"。 */
  --folder-step: 204px;
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%); /* 整列垂直居中——卡纸也是居中的，两者对齐在同一条中线上 */
  width: var(--rack-w);
  height: calc(3 * var(--folder-step) + var(--folder-h));
  z-index: 3;
}
.folder {
  --pull: 0px;
  --reveal: 0;
  position: absolute;
  right: 0;
  top: calc(var(--folder-i) * var(--folder-step));
  width: var(--rack-w);
  height: var(--folder-h);
  z-index: calc(var(--folder-i) + 1);
  cursor: grab;
  transform: translateX(var(--pull)); /* --pull 是负值＝往左抽出来 */
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), filter 0.2s;
  /* 投影方向跟着抽出方向转了 90°：往左抽，影子就落在左边 */
  filter: drop-shadow(calc(-2px - var(--reveal) * 6px) 0 calc(5px + var(--reveal) * 9px) rgba(74, 50, 22, calc(0.2 + var(--reveal) * 0.2)));
}
.folder.dragging { cursor: grabbing; transition: none; }
/* 书脊：贴着屏幕右边缘那条色带，四份接起来就是手绘图上那条竖线 */
.folder-body {
  position: absolute;
  top: 0; bottom: 0; right: 0; left: var(--tab-w);
  background: var(--folder-paper);
  background-image: var(--paper-grain);
  background-blend-mode: multiply;
  border-radius: 4px 0 0 4px;
  box-shadow: inset 1px 0 0 rgba(255,255,255,0.4), inset 0 0 0 1px rgba(74,50,22,0.18);
}
/* 标签：从书脊往**左**探出来，左窄右宽的梯形（手绘图上那四个四边形） */
.folder-tab {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: var(--tab-w);
  /* 中文竖排。四个字自上而下，英文小字在它左边一列（竖排里拉丁文自然侧躺，
     正好是档案盒书脊上那种排法）。 */
  writing-mode: vertical-rl;
  display: flex;
  flex-direction: column; /* 竖排下这条是"块轴"＝从右往左，所以中文在右、英文在左 */
  align-items: center;
  justify-content: center;
  gap: 4px;
  background: var(--folder-paper);
  background-image: var(--paper-grain);
  background-blend-mode: multiply;
  clip-path: polygon(0 12px, 100% 0, 100% 100%, 0 calc(100% - 12px));
  box-shadow: inset 1px 0 0 rgba(255,255,255,0.4);
}
.folder-label {
  font-size: 0.8rem; font-weight: 700; letter-spacing: 0.14em; text-indent: 0.14em; line-height: 1;
  color: color-mix(in srgb, var(--ink) 84%, var(--folder-paper));
}
.folder-sub {
  font-size: 0.5rem; letter-spacing: 0.2em; line-height: 1; opacity: 0.66;
  color: color-mix(in srgb, var(--ink) 84%, var(--folder-paper));
}
/* 掠过：往左探出一截（跟笔同一套反馈、同一个幅度，站着远看要看得出来） */
.folder:hover, .folder.gesture-hover { transform: translateX(calc(var(--pull) - 26px)); }
/* 拉过阈值：标签描一道强调边，"松手就是它了" */
.folder.past-threshold .folder-tab { box-shadow: inset 0 0 0 2px var(--scent-ink, var(--ink)); }
/* 选中的模式停在抽出来的位置 */
.folder.selected { transform: translateX(calc(var(--pull) - 56px)); }
.folder.selected:hover, .folder.selected.gesture-hover { transform: translateX(calc(var(--pull) - 64px)); }
.folder.selected .folder-tab { box-shadow: inset 0 0 0 2px var(--scent-ink, var(--ink)); }
/* ---- 插在档案纸背后的那排笔（2026-09-02，取代原来工具栏里的 .swatch 小圆点）----
   叠放关系：#pen-rack 在 #draw-card **后面**（z-index 0 对 1），笔杆整体比露出
   来的那截长得多，多出来的部分被卡纸压住，所以看起来就是"插在纸背后"。
   往上抽的行程/阈值在 js/canvas.js 的 PEN_PULL_MAX / PEN_PULL_THRESHOLD_RATIO，
   阈值跟③屏抽档案是同一个数（用户要的就是同一种手感）。 */
#card-stage {
  position: relative;
  display: inline-flex; /* 尺寸完全由里面的卡纸撑出来，笔是绝对定位的浮层，不参与撑大 */
}
#draw-card { position: relative; z-index: 1; }
/* 2026-09-02：笔从"居中一排"挪到**纸的左边**，右边那半留给橡皮擦
   （用户："这个笔可以被放在纸的左边，然后可以在右边的空白区域放一块橡皮擦"）。
   两样都在卡纸上沿那条空带里，都是压在卡纸下面的实物。 */
#pen-rack {
  position: absolute;
  z-index: 0; /* 比卡纸低 —— 这一条就是"插在背后"的全部实现 */
  /* 2026-09-03 从 56 收到 24：卡纸让出右边一列给工具档案夹之后宽度从 948 降到
     874，8 支笔连间距一共 826px，left 还留 56 的话最后一支会顶到纸的右边缘外。 */
  left: 24px;
  bottom: 100%;            /* 贴着卡纸上沿 */
  margin-bottom: -128px;   /* 再往下压回去一截，笔的下半截就被卡纸盖住了 */
  display: flex;
  justify-content: flex-start;
  align-items: flex-end;
  gap: 22px;
  pointer-events: none;    /* 空隙不吃事件，免得挡住卡纸；笔自己再打开 */
}

/* ---- 橡皮擦：放在纸右上那块空白里，捏合提起来移动就能擦 ----
   擦除半径是固定的 ERASER_RADIUS_PX（js/canvas.js），跟这块橡皮的**视觉大小
   无关**——视觉大小只是让它看着像一块橡皮、好捏得住。 */
#eraser {
  --ex: 0px;
  --ey: 0px;
  position: absolute;
  z-index: 2;              /* 提起来之后要盖在卡纸上面，所以比卡纸高 */
  /* 2026-09-02 用户："橡皮擦移动到纸的右下吧"。原来在纸的右上角，跟卡纸
     抬头（漫游记录/日期那行）挤在一起；挪到右下角之后上方那条空带就完全
     留给笔了，两样工具各占一头，也不再压住抬头。
     【坐标是相对 #card-stage（＝整张卡纸）算的，但橡皮擦该待在**画布**里】
     卡纸的内边距是 40/44/42，所以画布的右边缘＝卡右缘-44、下边缘＝卡下缘-42。
     用户反馈"擦头在纸外面"就是这个：原来 right:40/bottom:34 比内边距还小，
     橡皮擦有一角探出了可画区域（实测右超 4px、下超 8px）。
     现在 = 内边距 + 26px 余量，保证整块都落在画布里。 */
  right: 70px;   /* 44(卡内边距) + 26 */
  bottom: 68px;  /* 42(卡内边距) + 26 */
  /* 2026-09-02 用户测试后加大：46px 高隔空捏不住 */
  width: 152px;
  height: 78px;
  cursor: grab;
  transform: translate(var(--ex), var(--ey));
  transition: transform 0.34s cubic-bezier(0.22, 1, 0.36, 1), filter 0.2s;
  filter: drop-shadow(0 3px 5px rgba(74, 50, 22, 0.24));
}
/* 提起来的时候要跟手（去掉过渡）、影子拉长（离开桌面） */
#eraser.lifted {
  cursor: grabbing;
  transition: filter 0.2s;
  filter: drop-shadow(0 16px 16px rgba(74, 50, 22, 0.3));
}
.eraser-body {
  position: absolute;
  inset: 0;
  border-radius: 5px;
  background: #efe7d6;
  background-image:
    var(--paper-grain),
    linear-gradient(180deg, rgba(255,255,255,0.75), rgba(0,0,0,0.06) 62%, rgba(0,0,0,0.16));
  background-blend-mode: multiply, normal;
  box-shadow: inset 0 0 0 1px rgba(74, 50, 22, 0.3);
}
/* 中间那圈套纸：真实橡皮上那道印着字的纸箍，加了它才不像一块纯色圆角方块 */
.eraser-sleeve {
  position: absolute;
  left: 34%;
  right: 8%;
  top: 0;
  bottom: 0;
  border-radius: 0 5px 5px 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.5), rgba(0,0,0,0.1));
  background-color: var(--scent-solid, var(--ink));
  box-shadow: inset 1px 0 0 rgba(0,0,0,0.22);
  opacity: 0.9;
}
#eraser:hover, #eraser.gesture-hover { filter: drop-shadow(0 7px 9px rgba(74, 50, 22, 0.3)); }

/* ---- 便签：一头是尖的箭头指示贴（参照用户给的荧光箭头贴照片）----
   用在两处：④教程屏下面那张"开始漫游"、③完成态漫游记录纸上贴的"去漫游"。
   形状靠 clip-path 切出右端的箭头尖，不用贴图；颜色用这一款香的实色，
   不用参照照片里的荧光色——那张照片是在说"我要的是这种便签"，不是配色。 */
.sticky-flag {
  --flag-h: 78px; /* 2026-09-02 跟着"字要大"一起加大，也更好瞄 */
  display: inline-flex;
  align-items: center;
  padding: 0 54px 0 30px;   /* 右边多留出箭头尖的宽度，字不会顶到尖上 */
  height: var(--flag-h);
  /* 2026-09-02 用户："这个标签做线香对应香型的底色"——用 --scent-vivid
     （data.js 里"这一款的代表色"，跟③屏抽屉正面那格是同一个色），不是
     --scent-solid 那种兑到近黑的实色。四款 vivid 都是浅/中明度，所以字必须
     是墨色不能是纸色，否则白底白字。实测四款对比度见下面 color 那行的注释。 */
  background: var(--scent-vivid, var(--ink));
  color: color-mix(in srgb, var(--ink) 88%, #4a3a20); /* 跟档案纸上的正文同一个墨色 */
  font-size: 1.02rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  cursor: pointer;
  clip-path: polygon(0 0, calc(100% - 26px) 0, 100% 50%, calc(100% - 26px) 100%, 0 100%);
  box-shadow: 0 4px 12px -4px rgba(74, 50, 22, 0.5);
  transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.28s;
}
.sticky-flag:hover, .sticky-flag.gesture-hover { transform: translateX(12px); }
/* 撕下来带走：往右滑出去 + 淡出，时长要跟 js 的 CTA_PULL_MS 对上 */
.sticky-flag.taken { transform: translateX(180px); opacity: 0; }

/* ④教程屏那张：教程说明单下面居中一张 */
#tut-start { margin-top: 46px; }

/* ③完成态那张：贴在漫游记录纸的右边缘，尖头朝外探出纸外——
   跟参照照片里"指示贴从书页边缘探出来"是同一个关系 */
/* 2026-09-02：两张便签挪到整屏的左右下角，不再贴在纸边上。
   只在完成态显示——平时那一屏还在打字，不该出现"去漫游"。 */
#go-wander, #redo-wander { display: none; }
#view-customizing.finished #go-wander,
#view-customizing.finished #redo-wander { display: inline-flex; }
#go-wander {
  position: absolute;
  right: 60px;
  bottom: 72px;
}
/* 「重新录入」在左下角＝退一步；它不该跟右下角"往下走"抢注意力：浅一点、
   字小一号，底色兑到纸色里去，主次一眼分得开。箭头也反过来朝左。 */
#redo-wander {
  position: absolute;
  left: 60px;
  bottom: 72px;
}
.sticky-flag.flag-secondary {
  padding: 0 26px 0 46px; /* 尖头在左边，所以留白也反过来 */
  font-size: 0.94rem;
  background: color-mix(in srgb, var(--scent-vivid, var(--ink)) 45%, #efe9dc);
  box-shadow: 0 3px 9px -4px rgba(74, 50, 22, 0.45);
  clip-path: polygon(26px 0, 100% 0, 100% 100%, 26px 100%, 0 50%);
}
.sticky-flag.flag-secondary:hover,
.sticky-flag.flag-secondary.gesture-hover { transform: translateX(-12px); }
.sticky-flag.flag-secondary.taken { transform: translateX(-180px); opacity: 0; }
.pen {
  --pull: 0px;
  --reveal: 0;
  pointer-events: auto;
  position: relative;
  /* 2026-09-02 用户测试：30px 宽的笔隔空根本按不准（摄像头抖动量就不止这个
     数）。加到 84——卡纸内宽 836px 放 8 支：8×84 + 7×22(gap) = 826，正好排得下。 */
  width: 84px;
  height: 232px;
  cursor: grab;
  transform: translateY(var(--pull));
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), filter 0.2s;
  /* 笔身的投影：抽得越出来影子越明显，是"离开纸面"的唯一提示 */
  filter: drop-shadow(0 calc(3px + var(--reveal) * 7px) calc(4px + var(--reveal) * 10px) rgba(74, 50, 22, calc(0.18 + var(--reveal) * 0.22)));
}
.pen.dragging { cursor: grabbing; transition: none; } /* 拖的时候要跟手，不能有过渡延迟 */
.pen-barrel {
  position: absolute;
  left: 0; right: 0; top: 34px; bottom: 26px;
  background: var(--pen-color);
  border-radius: 3px;
  /* 圆柱体的高光/暗面：一条竖向渐变叠在实色上，笔杆才不是一块平涂的色条 */
  background-image: linear-gradient(90deg,
    rgba(0, 0, 0, 0.22) 0%, rgba(0, 0, 0, 0.06) 22%,
    rgba(255, 255, 255, 0.42) 42%, rgba(255, 255, 255, 0.1) 58%,
    rgba(0, 0, 0, 0.1) 82%, rgba(0, 0, 0, 0.26) 100%);
  box-shadow: inset 0 0 0 1px rgba(74, 50, 22, 0.28);
}
/* 笔尖：朝上（笔是尖头朝上插着的，抽出来就能用），用一个三角把笔杆顶端收掉 */
.pen-nib {
  position: absolute;
  left: 0; right: 0; top: 0; height: 40px;
  background: var(--pen-color);
  background-image: linear-gradient(90deg, rgba(0,0,0,0.24), rgba(255,255,255,0.34) 45%, rgba(0,0,0,0.24));
  clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
}
/* 笔夹：金属色的一小条，别在笔杆上端，让这东西一眼读得出是"笔"而不是色块 */
.pen-clip {
  position: absolute;
  right: 12px;
  top: 46px;
  width: 12px;
  height: 62px;
  border-radius: 3px;
  background: linear-gradient(90deg, #9a9282, #e6e0d2 45%, #8d8474);
  box-shadow: 0 0 0 0.5px rgba(74, 50, 22, 0.3);
  z-index: 2;
}
/* 掠过（真实鼠标 :hover 和手势光标自己切的 .gesture-hover 共用同一条规则，
   见 gestures.js 的 updateGestureHover）——跟③屏掠过候选文件是同一套反馈。
   2026-09-02 从 -10px 加到 -26px：用户"手路过画笔，笔上抬的效果可以再明显
   一点"。这是隔空手势下唯一告诉用户"光标现在压在哪支笔上"的信号，人是站着
   远看这块屏的，10px 在那个距离上基本看不出来。顺带把笔尖提亮一档。 */
.pen:hover, .pen.gesture-hover { transform: translateY(calc(var(--pull) - 26px)); }
.pen:hover .pen-clip, .pen.gesture-hover .pen-clip {
  background: linear-gradient(90deg, #b0a68d, #fffaf0 45%, #a79d86);
}
/* 拖过阈值：抽出来一大截 + 笔夹发亮，告诉用户"松手就是它了" */
.pen.past-threshold .pen-clip { background: linear-gradient(90deg, #b9ae94, #fffaf0 45%, #ada284); }
/* 选中的那支停在抽出来的位置，别的都插回去——一眼看得出现在用的是哪支。
   要比掠过（-26px）明显高出一截，否则"正在用的那支"和"手正划过的那支"分不开 */
.pen.selected { transform: translateY(calc(var(--pull) - 52px)); }
.pen.selected:hover, .pen.selected.gesture-hover { transform: translateY(calc(var(--pull) - 60px)); }
.pen.selected .pen-clip { background: linear-gradient(90deg, #8a7f66, #fff6e0 45%, #8a7f66); }
/* 画布区：一张居中的卡纸。卡的尺寸由里面画布的尺寸撑出来，而画布的高宽比
   是从打印版式反推的（见 js/canvas.js 里 printArtAspect 的说明），所以这里
   不写死画布尺寸，只管卡本身的纸感。 */
#canvas-wrap {
  flex: 1;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 右边这一条是留给 #tool-folders 那一列的（2026-09-03 工具从底部挪到右侧）：
     152(rack) + 30(间距)。左边只留 24——右边已经有一整列了，两边再对称留白
     会把卡纸挤得更小；卡纸靠左、工具靠右，本来就是"纸摊在桌上、文件架在手边"
     那种不对称。**这个 padding-right 跟 js/canvas.js 的 DRAW_CANVAS_W 是一组的**，
     见 #tool-folders 那段注释。 */
  padding: 26px 182px 26px 24px;
}
#draw-card {
  padding: 40px 44px 42px;
  background: #f7f2e6;
  background-image: var(--paper-grain);
  background-blend-mode: multiply;
  /* 纸边 + 落在桌面上的投影。跟③屏那张档案记录卡、教学屏的说明单同一套纸感 */
  box-shadow:
    0 0 0 1px rgba(74, 50, 22, 0.16),
    0 14px 34px -16px rgba(74, 50, 22, 0.45),
    0 2px 5px rgba(74, 50, 22, 0.12);
  color: color-mix(in srgb, var(--ink) 88%, #4a3a20);
}
.draw-card-head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding-bottom: 9px;
  margin-bottom: 22px;
  border-bottom: 1px dashed rgba(74, 50, 22, 0.5); /* 跟档案记录卡抬头同一条虚线 */
}
.draw-card-title { font-size: 1.32rem; font-weight: 700; letter-spacing: 0.28em; text-indent: 0.28em; }
.draw-card-sub { font-size: 0.66rem; letter-spacing: 0.22em; opacity: 0.68; text-transform: uppercase; }
.draw-card-date { margin-left: auto; font-size: 0.72rem; letter-spacing: 0.1em; opacity: 0.7; font-variant-numeric: tabular-nums; }
/* 画布尺寸由 js 按打印比例设成具体 px，这里不写 width/height，免得两处打架 */
#draw-canvas { display: block; touch-action: none; }

/* ---------- printing ---------- */
#view-printing {
  flex-direction: column; align-items: center; justify-content: center; gap: 2rem;
  background: var(--scent-wash);
}
#print-status { font-size: 1rem; opacity: 0.72; }
/* 打印进度条（2026-09-03）。两段共用同一根条：先是"生成画面"的真进度，
   点了打印之后重新从 0 走"正在打印"的估算进度，见 js/print.js。 */
.print-progress {
  width: 620px;
  height: 10px;
  border-radius: 5px;
  overflow: hidden;
  background: color-mix(in srgb, var(--scent-ink, var(--ink)) 14%, transparent);
  opacity: 0;
  transition: opacity 0.3s ease;
}
.print-progress.visible { opacity: 1; }
.print-progress .pp-bar {
  display: block;
  width: 100%;
  height: 100%;
  transform-origin: left center;
  transform: scaleX(0);
  background: var(--scent-solid, var(--ink));
  /* 60ms 的过渡把分片之间的台阶抹平，又不至于让条落后于真实进度太多 */
  transition: transform 60ms linear;
}
/* 2026-09-20 老板"明信片也可以再大一些"：1056×756 → 1320×900 */
#print-preview-img { max-height: 1320px; max-width: 900px; box-shadow: 0 4px 24px rgba(0,0,0,0.12); }
.print-actions { display: flex; gap: 1.5rem; }
.print-actions button {
  border: 1px solid var(--ink); background: transparent; color: var(--ink);
  padding: 0.7rem 1.8rem; font-size: 1rem; cursor: pointer; border-radius: 2px;
}
.print-actions button.primary { background: var(--ink); color: var(--paper); }

/* ---------- 手势光标/提示（见 js/gestures.js） ---------- */
/* 指尖光标：固定定位 + translate 跟手移动，pointer-events:none 避免自己挡住
   elementFromPoint() 命中真正要点的元素（否则每次点击都会点到光标本身）。
   默认不占布局空间、不可见，只有识别到手且在③④⑤手势屏才显示（.visible）。 */
/* ---------- 双手调笔刷大小的量规（2026-08-31）----------
   两只手举起来时出现：两手之间拉一条虚线，中点一个圆点表示"待会儿画出来
   就是这么粗"，上面标着倍数。圆点直径是按 canvas.js 里那个字实际会用的字号
   算的，不是随便找的比例——所见即所得，用户看到多大就是画出来多大。
   全都 pointer-events:none：这是纯提示层，不能挡住底下画布的任何事件。
   坐标由 JS 直接写 transform（跟 #gesture-cursor 同一套做法），位置来自
   摄像头坐标映射到 #stage 实际渲染矩形，不走布局。 */
#brush-gauge {
  position: fixed;
  inset: 0;
  z-index: 9998; /* 比 #gesture-cursor(9999) 低一档——光标要始终压在最上面 */
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.18s ease;
}
#brush-gauge.visible { opacity: 1; }
/* 捏合确定那一下：量规整体收一点、变实，然后（由 JS 在 420ms 后）收起——
   给一个明确的"定了"反馈，不是悄无声息地消失。 */
#brush-gauge.committed { transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1); transform: scale(0.94); opacity: 0; }
#brush-gauge.committed .bg-dot { background: color-mix(in srgb, var(--scent-accent, #A1D6D9) 88%, transparent); }
#brush-gauge .bg-line {
  position: absolute;
  top: 0; left: 0;
  height: 0;
  transform-origin: 0 0; /* JS 给的 transform 是"移到左手位置再转向右手"，旋转必须绕这个起点 */
  border-top: 2px dashed color-mix(in srgb, var(--scent-accent, #A1D6D9) 70%, var(--ink));
  opacity: 0.55;
}
#brush-gauge .bg-dot {
  position: absolute;
  top: 0; left: 0;
  border-radius: 50%;
  background: color-mix(in srgb, var(--scent-accent, #A1D6D9) 55%, transparent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--scent-accent, #A1D6D9) 85%, var(--ink)) inset;
}
#brush-gauge .bg-label {
  position: absolute;
  top: 0; left: 0;
  transform-origin: 0 0;
  margin-left: -1.4em; /* JS 给的是中点坐标，这里把标签自己拉回来居中 */
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--ink);
  text-shadow: 0 1px 3px var(--paper), 0 0 6px var(--paper); /* 画布上什么颜色都可能，给个纸色的外发光保证读得出来 */
}
#gesture-cursor {
  position: fixed;
  top: 0;
  left: 0;
  /* 2026-09-02 用户测试反馈之四："选中之前没有反馈，不知道压中没有"。
     26px 的小圆点站着远看根本找不到。加大到 46 + 一圈白描边 + 深投影，
     保证压在任何底色上都看得见自己在哪。 */
  width: 46px;
  height: 46px;
  margin: -23px 0 0 -23px;
  border-radius: 50%;
  border: 3px solid var(--ink);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85), 0 3px 10px rgba(0, 0, 0, 0.35);
  background: rgba(244, 241, 234, 0.55);
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  transition: opacity 0.15s ease;
  will-change: transform;
}
#gesture-cursor.visible { opacity: 0.85; }
/* 捏合中：实心填充，让用户看得出"系统认为我捏上了"。
   【2026-09-10 老板：实心那块要跟着这一款香的颜色走】用 --scent-vivid
   （applyScentTone 按香型注入，就是每款"能大面积铺的那支代表色"）：
       酒店房间 #CEE2C4 淡绿 · 午后客厅 #F8EBB9 淡黄
       阳台的夜 #A2D7D9 淡青 · 月夜银桂 #F6AB00 金黄
   ⚠️ **只换填充，外圈那道边保持深墨色**：四款里有三款的代表色都很浅，
   连边框一起换掉的话，光标压在浅底上（第一层那张蓝白条纹布纹、月夜的米白）
   就整个糊住了。深边 + 白描边 + 浅填充，压在什么底上都还看得见。
   用 --scent-vivid 而不是 --scent-accent：后者好几处别的地方也在吃
   （brush-gauge、卡片边框…），动它会波及一片，而且 css:883 那条注释记着
   "两款强调色太浅"的旧账。 */
#gesture-cursor.pinching {
  /* 【2026-09-11 老板：做成从圆心往外扩散、直到填满】
     原来是捏上就整个实心，看不出"还要捏多久"。现在填充半径跟着 --progress 走
     （updatePinchHold 每帧写，0→1 对应捏住 0→2 秒 / 结果页 0→6 秒），
     像水位从中心涨满，配合外圈那道环是双重反馈。
     · closest-side 让渐变半径正好等于光标半径（23px），填满＝刚好到边；
     · 起始半径不是 0 而是 18%：捏上那一瞬间就得有个看得见的点，
       表示"系统认了"，否则前半秒像没反应；
     · 两个色标之间留 1.5% 的过渡，纯硬边在圆弧上会有锯齿。 */
  background:
    radial-gradient(circle closest-side,
      var(--scent-vivid, var(--ink)) calc((0.18 + var(--progress, 0) * 0.82) * 100%),
      transparent calc((0.18 + var(--progress, 0) * 0.82) * 100% + 1.5%)),
    rgba(244, 241, 234, 0.55);
}
/* 确认那一下：整只（含边）都换成这一款的色，给个一次性的闪烁 */
#gesture-cursor.confirmed { background: var(--scent-vivid, #A1D6D9); border-color: var(--scent-vivid, #A1D6D9); }

/* 2026-08-24 用户要求加的"捏合进度提示"：捏合之后开始往右拖、但还没拖够
   GESTURE_CONFIRM_DRAG_PX 距离触发确认这段过程中，圆点外圈显示一个逐渐
   填满的环形进度（--progress 由 gestures.js 按拖动距离/阈值实时算，0~1），
   让人看得出"已经拖了多少、还差多少"，不是拖到底才有反馈。用 conic-gradient
   画扇形 + radial-gradient 遮罩抠成圆环，不需要额外的 SVG。只在"拖右确认"
   这条手势路径上出现（不含④画布/③抽屉拖拽那两类，那两类捏上就已经在
   拖真正的内容了，没有"还差多少"这回事）。 */
#gesture-cursor::after {
  content: '';
  position: absolute;
  inset: -7px;
  border-radius: 50%;
  background: conic-gradient(var(--scent-vivid, #A1D6D9) calc(var(--progress, 0) * 360deg), transparent 0deg);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  opacity: 0;
  transition: opacity 0.15s ease;
}
#gesture-cursor.confirming::after { opacity: 1; }

/* 2026-09-04 老板要求删掉"请将手抬到摄像头前"这个提示 pill。JS 逻辑照旧
   （仍会 toggle .visible），这里统一 display:none 让它永不显示，改动最小。 */
#gesture-hint {
  position: fixed;
  bottom: 4vh;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(26, 26, 26, 0.82);
  color: var(--paper);
  padding: 0.6rem 1.4rem;
  border-radius: 999px;
  font-size: 0.95rem;
  letter-spacing: 0.05em;
  pointer-events: none;
  z-index: 9999;
  display: none;
}
#gesture-hint.visible { display: none; }

/* ---------- 打印专用（只在实际打印时显示，见 print-export.md） ---------- */
#print-frame { display: none; }
#print-frame img { width: 100%; }

@media print {
  body > *:not(#print-frame) { display: none !important; }
  #print-frame { display: block !important; }
  /* 纸张尺寸(@page size)、明信片在纸上的实际毫米数、四边等距的边距，全部由
     js/print.js 在打印那一刻注入（#print-page-size），这里不写死——写死就会跟
     print.js 里的尺寸各说各话。下面这条只是兜底：万一注入没跑成，至少还能按比例
     缩进纸里，不会被裁。 */
  #print-frame img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; margin: 0 auto; }
}

/* ---- 卡片录入模式（?enroll=1，见 js/rfid.js）----
   只有布展时用得到，样式够看清就行，不参与整体调性。 */
#rfid-enroll {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  background: rgba(20, 18, 14, 0.92);
  color: var(--paper);
  text-align: center;
}
#rfid-enroll .re-title { font-size: 1.1rem; letter-spacing: 0.3em; text-indent: 0.3em; opacity: 0.7; }
#rfid-enroll .re-step { font-size: 2rem; font-weight: 700; letter-spacing: 0.14em; }
#rfid-enroll .re-hint { font-size: 0.86rem; opacity: 0.6; letter-spacing: 0.08em; }

/* ============================================================
   carousel 选择流程（2026-09-03 重构）—— 取代原抽屉/打字机那套。
   复用既有 token：--scent-wash 铺底、--scent-solid 实色按钮、--scent-vivid
   点缀、--paper / --paper-grain 纸质感。所有尺寸是 1080×1920 设计像素。
   ============================================================ */

/* 读卡器没连上时那行提示（见 js/rfid.js 的 setBridgeHint）。只加一点暖红，
   不改字号位置——待机画面是给客人看的，不能变成报错屏。 */
.mock-hint.warn { color: #d98b6a; }

/* 开屏＝待机屏也用一下 mock-hint（原来挂在 #view-idle 上，现在在 splash） */
#view-splash .mock-hint {
  position: absolute; left: 0; right: 0; bottom: 40px; text-align: center;
  font-size: 0.8rem; letter-spacing: 0.1em; opacity: 0.28; color: var(--paper);
}

/* 选择屏：覆盖原 customizing 的大内边距，给卡带让出横向空间 */
#view-customizing {
  padding: 96px 60px 84px;
  justify-content: flex-start;
  gap: 0;
}

.caro-topbar {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-shrink: 0; margin-bottom: 40px;
}
.caro-topbar .scent-tag { margin-bottom: 0; }
#caro-progress {
  font-size: 1.1rem; letter-spacing: 0.14em; font-variant-numeric: tabular-nums;
  opacity: 0.5;
}


/* 抽出的一份档案：竖向堆叠（引导句 → 卡带 → 圆点 → 提示 → 确定） */
.caro-file {
  flex: 1 1 auto; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 28px; min-height: 0;
}
.caro-file.slide-in { animation: caroFileIn 460ms cubic-bezier(.2,.7,.2,1) both; }
@keyframes caroFileIn {
  from { opacity: 0; transform: translateY(40px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

/* 第二步那句话：写在一张**撕边纸**上（沐果素材17，自带顶部胶带），文字居中。
   纸比例 1.205，按它给尺寸不变形。 */
#caro-recap {
  /* 2026-09-08 挪到右上：往下往右压住档案夹的右上角一点点，但不碰照片。
     底边 300+295=595，第一步照片顶边约 682、第二步相框顶边更低，都躲得开；
     右边缘 996 略越过卡片右缘（卡宽 859、居中 → 右缘 969），就是那"一点点"。
     ⚠️ z-index 必须高于 200——updateStrip 给焦点卡设的就是 200，
     纸原来是 4，一跟卡片重叠就会被整个盖住。 */
  position: absolute; left: 640px; top: 300px; z-index: 300;
  width: 356px; height: 295px;
  background: url("../assets/poster/note-torn.png") center / 100% 100% no-repeat;
  filter: drop-shadow(0 10px 20px rgba(40,28,14,0.22));
  /* 素材顶部那截胶带是探出纸面的，所以盒子中心比纸的视觉中心高——
     padding 上大下小，把字压到纸真正的中间。 */
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 62px 40px 30px;
  font-size: 0.92rem; letter-spacing: 0.06em; line-height: 1.85;
  color: #4a4236; text-align: center; visibility: hidden;
}
#caro-recap span { display: block; white-space: nowrap; }
/* 第二步：纸条在**右下角**，左上角压住文件夹右下一块，并向右倾 3.5°。
   位置是被诗句卡死的：实测这一屏 文件夹 B=1591 R=951、诗句纸叠 B=1563、
   **诗最后一行底 1492、诗文字最右 864**。纸条 356 宽、屏幕 1080，
   left 最大只能 724，所以一往上就会压到 x 700~864 那段字。
   1478 是倾斜后仍不碰字的上限：转 3.5° 会让顶边最高点再抬约 11px（→1469），
   而最后一行的字顶在 1466。要再往上，得先把 .mp-lines 的右 padding 加大、
   让诗句文字整体左收。 */
#caro-recap.at-mood { left: 700px; top: 1478px; transform: rotate(3.5deg); }

.caro-lead {
  font-size: 1.5rem; letter-spacing: 0.04em; opacity: 0.82;
  min-height: 1.6em; text-align: center; flex-shrink: 0;
  color: color-mix(in srgb, var(--ink) 82%, var(--scent-ink, var(--ink)));
}

/* 横向卡带视口：中间聚焦卡满显，两侧候选探头 */
.caro-viewport {
  /* 900→1200：卡片放大到 859×1100 之后要装得下叠卡（ad=2 那张 ty=-84、scale .9）。
     横向也够：ad=2 卡右缘 = 82 + 859×.9/2 ≈ 468 < 520（viewport 半宽）。 */
  position: relative; width: 1040px; height: 1200px;
  overflow: hidden; flex-shrink: 0;
}
.caro-strip { position: absolute; inset: 0; }

/* ---- 一份档案夹（整体做大：460×624；字号整体调小，留白更多、更编辑感） ---- */
.caro-card.folder {
  position: absolute; top: 50%; left: 50%;
  /* 卡片＝海报里那张档案夹本身（第一步 734×940，比例 0.781），不含四周的底色。
     2026-09-07 再放大一档到 859×1100——屏幕 1920 高，#view-customizing 上下
     padding 154 之后还剩 1600+，之前 594×760 用不满。
     放大后缩放比都到了 1 附近，海报几乎按原尺寸显示，小字也就清楚了。
     上限是叠卡定的：ad=2 那张 scale .9 / ty -84，要它顶边不出 viewport，
     卡高 ≤ (viewport/2 - 84)/0.45；viewport 1200 → ≤ 1369。 */
  width: 859px; height: 1100px;
  --ps-scale: 1.170;   /* 第一步：859/734（档案夹宽） */
  --mp-scale: 1.019;   /* 第二步：859/843（文件夹+纸叠宽） */
  transition: transform 400ms cubic-bezier(.2,.7,.2,1), opacity 300ms ease;
  will-change: transform; cursor: pointer; user-select: none;
  /* 皮肤变量由 js/carousel.js 按香型包装色注入 */
}
/* 夹身：包装色 + 纸纹 */
.folder-body {
  position: absolute; inset: 0; border-radius: 4px 18px 18px 18px;
  background: var(--paper-grain), var(--f-bg, #d8ccb2);
  border: 1px solid rgba(60,45,25,0.28);
  box-shadow: 0 22px 48px -26px rgba(60,45,25,0.55);
  overflow: hidden; color: var(--f-ink, #2c2119);
  transition: filter 300ms ease, box-shadow 300ms ease;
}
.folder.dark .folder-body { border-color: rgba(0,0,0,0.4); }
.caro-card:not(.focus) .folder-body { filter: brightness(0.97) saturate(0.94); }
/* 焦点档案：抬起 */
.caro-card.focus .folder-body { box-shadow: 0 42px 84px -30px rgba(30,20,10,0.66); }

/* 顶部标签：真·档案夹标签——从夹子顶边"裁"出来的梯形凸起（2026-09-04 按老板
   参考图重做）。跟夹身**同色一体**(--f-bg)、无边框无阴影＝像是从夹子上直接切
   出来的，不是贴上去的小色块；两侧内收成梯形＝档案夹标签的经典轮廓；偏左放。
   ⚠️ 用 .caro-card 提高特异性：上面还有一条**旧抽屉流程的 `.folder-tab`**（竖排
   writing-mode + flex-direction:column），同类名会把竖排/列布局漏进来（文字变竖排），
   这里显式复位 writing-mode/flex-direction/width/bottom/box-shadow 挡掉那些残留。 */
.caro-card .folder-tab {
  /* z-index 必须给：DOM 里 card.appendChild(tab) 排在 appendChild(body) 前面，
     两者都不带 z-index 时后画的夹身压在标签上，把「漫游地点」切掉下半截。 */
  z-index: 6;
  /* top 从 -34 抬到 -44：-34 时标签底边还有 9.7px 落在卡内，而 .tab-label 的实际
     行高(0.82rem×1.2≈27.6px)正好让字压在夹身顶边那条线上、下半被切。-44 让整枚
     标签完全在卡外，字怎么排都不会碰到边。 */
  position: absolute; top: -44px; left: 40px; bottom: auto;
  min-width: 176px; width: auto; height: 44px; padding: 0 28px;
  display: flex; flex-direction: row; align-items: center; justify-content: center;
  writing-mode: horizontal-tb;
  background: var(--f-bg, #fdf9e3); box-shadow: none;
  clip-path: polygon(18px 0, calc(100% - 18px) 0, 100% 100%, 0 100%);
  transition: opacity 260ms ease;
}
.caro-card .folder-tab .tab-label {
  writing-mode: horizontal-tb;
  font-size: 0.82rem; font-weight: 500; letter-spacing: 0.12em; white-space: nowrap;
  color: var(--f-ink, #8a7748);
}
/* 扇形叠卡里，背景卡片的间距（~34px）远小于标签宽度（96px），一排同类别标签
   会互相重叠、每个只露一条边把字切碎（用户 #105 反馈）。而且背景卡片全是同一
   类别、标签文字都一样，堆一排半截的相同标签没有信息量。所以**只在聚焦卡片上
   显示标签**，背景卡片的标签淡出——扇形叠卡的层次靠卡身本身表现，不靠标签。 */
.caro-card:not(.focus) .folder-tab { opacity: 0; }
/* 侧栏：英文感官诗句，打字机铅字竖排、极淡 */
.folder-side {
  position: absolute; top: 116px; left: 17px; z-index: 3;
  writing-mode: vertical-rl;
  max-height: 440px; overflow: hidden;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 0.6rem; letter-spacing: 0.05em; line-height: 1.5; white-space: nowrap;
  color: var(--f-sub, #5c4c3d); opacity: 0.4;
}
/* 参考编号（打字机字角标） */
.folder-code {
  position: absolute; top: 176px; right: 34px; z-index: 5; text-align: right;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 0.6rem; letter-spacing: 0.1em; color: var(--f-sub, #5c4c3d);
  opacity: 0.7; transform: rotate(-2deg);
}
/* 回形针 */
.folder-clip {
  position: absolute; top: -14px; left: 262px; width: 26px; height: 84px; z-index: 7;
  border: 3px solid #aeb2b8; border-radius: 13px; background: transparent;
  box-shadow: 0 2px 4px rgba(0,0,0,0.25);
}
.folder-clip::before {
  content: ''; position: absolute; top: 8px; left: 5px; right: 5px; bottom: 22px;
  border: 3px solid #c7cbd0; border-radius: 8px; border-bottom: none;
}
/* 拍立得：产品大片 */
.folder-photo {
  position: absolute; top: 58px; left: 44px; width: 258px; height: 294px; z-index: 4;
  background: #fdfcf8; padding: 12px 12px 36px; border-radius: 2px;
  box-shadow: 0 18px 36px -18px rgba(30,20,10,0.6);
  transform: rotate(var(--rot-photo, -1.6deg));
  overflow: hidden;
}
.folder-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.folder-photo.noimg { background: #e9e2d0; }
.folder-photo .photo-cap {
  position: absolute; left: 0; right: 0; bottom: 10px; text-align: center;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-style: italic;
  font-size: 0.62rem; letter-spacing: 0.06em; color: #6a5a48;
}
/* 胶带 */
.folder-tape {
  position: absolute; top: -13px; left: 40%; width: 104px; height: 32px; z-index: 6;
  background: linear-gradient(180deg, rgba(255,251,235,0.62), rgba(238,228,200,0.5));
  border-left: 1px dashed rgba(255,255,255,0.5); border-right: 1px dashed rgba(180,160,120,0.4);
  transform: rotate(-8deg); box-shadow: 0 2px 6px rgba(0,0,0,0.12);
}
/* 邮票 */
.folder-stamp {
  position: absolute; top: 62px; right: 32px; width: 80px; height: 96px; z-index: 6;
  background: #fff; padding: 6px; transform: rotate(var(--rot-stamp, 4deg));
  box-shadow: 0 6px 14px -6px rgba(30,20,10,0.5); border: 0;
  display: flex; align-items: center; justify-content: center; flex-direction: column;
}
.folder-stamp::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background:
    radial-gradient(circle 2.5px at center, #fff 60%, transparent 62%) top left / 10px 6px repeat-x,
    radial-gradient(circle 2.5px at center, #fff 60%, transparent 62%) bottom left / 10px 6px repeat-x,
    radial-gradient(circle 2.5px at center, #fff 60%, transparent 62%) top left / 6px 10px repeat-y,
    radial-gradient(circle 2.5px at center, #fff 60%, transparent 62%) top right / 6px 10px repeat-y;
}
.folder-stamp::before {
  content: ''; position: absolute; inset: 5px; background: var(--f-accent, #7a5a38); opacity: 0.9;
}
.folder-stamp .stamp-key {
  position: relative; z-index: 1;
  font-size: 1.3rem; font-weight: 800; letter-spacing: 0.04em; color: var(--f-tabtext, #fff);
  writing-mode: vertical-rl; line-height: 1.05; max-height: 74px; overflow: hidden;
}
.folder-stamp .stamp-cn {
  position: relative; z-index: 1; margin-top: 2px;
  font-size: 0.46rem; letter-spacing: 0.2em; opacity: 0.8; color: var(--f-tabtext, #fff);
}
/* 行李牌：场景 occasion */
.folder-tag {
  position: absolute; top: 360px; right: 28px; width: 168px; z-index: 5;
  padding: 13px 16px 11px 30px;
  background: #d9c49b; color: #4f3d28;
  transform: rotate(var(--rot-tag, 5deg));
  box-shadow: 0 8px 18px -10px rgba(30,20,10,0.5);
  clip-path: polygon(14px 0, 100% 0, 100% 100%, 14px 100%, 0 50%);
}
.folder-tag::before {
  content: ''; position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--f-bg, #d8ccb2); box-shadow: inset 0 0 0 2px rgba(80,60,40,0.5);
}
.folder-tag .tag-en { font-size: 0.62rem; font-weight: 700; letter-spacing: 0.13em; display: block; }
.folder-tag .tag-cn { font-size: 0.8rem; letter-spacing: 0.1em; display: block; margin-top: 3px; }
/* 香材便签 */
.folder-notes {
  position: absolute; left: 38px; bottom: 158px; z-index: 5;
  display: flex; gap: 8px;
}
.folder-notes .note-chip {
  font-size: 0.62rem; letter-spacing: 0.05em; color: #5a4a38;
  background: #efe7d5; padding: 4px 10px; border-radius: 2px;
  box-shadow: 0 3px 8px -4px rgba(30,20,10,0.4); transform: rotate(-2deg);
}
.folder-notes .note-chip:nth-child(2) { transform: rotate(3deg); }
/* 文案（多行截断） */
.folder-cap {
  position: absolute; left: 36px; right: 30px; bottom: 32px; z-index: 5;
  font-size: 0.9rem; line-height: 1.45; text-align: left; color: var(--f-ink, #2c2119);
  border-top: 1px dashed color-mix(in srgb, var(--f-sub, #5c4c3d) 60%, transparent);
  padding-top: 10px;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}

/* ---- 版式变体：每张卡按序 a/b 轮换，b 是左右镜像，翻页时每页排版都不一样 ---- */
.folder.layout-b .folder-tab   { left: auto; right: 28px; }
.folder.layout-b .folder-side  { left: auto; right: 17px; }
.folder.layout-b .folder-code  { right: auto; left: 34px; text-align: left; }
.folder.layout-b .folder-clip  { left: auto; right: 262px; }
.folder.layout-b .folder-photo { left: auto; right: 44px; }
.folder.layout-b .folder-stamp { right: auto; left: 32px; }
.folder.layout-b .folder-notes { left: auto; right: 38px; }
.folder.layout-b .folder-tag {
  right: auto; left: 28px; padding: 13px 30px 11px 16px;
  clip-path: polygon(0 0, calc(100% - 14px) 0, 100% 50%, calc(100% - 14px) 100%, 0 100%);
}
.folder.layout-b .folder-tag::before { left: auto; right: 8px; }
.folder.layout-b .folder-cap { text-align: right; }
/* 选定后的盖章反馈 */
.caro-card.stamped .folder-body { animation: caroStamp 460ms ease; }
.caro-card.stamped .folder-body::after {
  content: ''; position: absolute; inset: 0; border-radius: 4px 16px 16px 16px;
  border: 4px solid var(--f-accent, var(--ink)); opacity: 0;
  animation: caroStampRing 460ms ease;
}
@keyframes caroStamp { 0%,100% { transform: none; } 30% { transform: scale(0.97); } }
@keyframes caroStampRing { 0% { opacity: 0; transform: scale(1.05); } 40% { opacity: 1; } 100% { opacity: 1; transform: scale(1); } }

/* 左右箭头：既是提示也是挥手/点击落点 */
.caro-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 76px; height: 76px; border-radius: 50%; z-index: 3;
  background: color-mix(in srgb, var(--paper) 80%, transparent);
  border: 1px solid color-mix(in srgb, var(--scent-ink, var(--ink)) 24%, transparent);
  color: color-mix(in srgb, var(--scent-ink, var(--ink)) 70%, var(--ink));
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; backdrop-filter: blur(2px);
  box-shadow: 0 6px 18px -8px rgba(0,0,0,0.4);
}
.caro-arrow svg { width: 34px; height: 34px; }
.caro-arrow.left { left: 6px; }
.caro-arrow.right { right: 6px; }
.caro-arrow:active { transform: translateY(-50%) scale(0.92); }

.caro-dots { display: flex; gap: 12px; flex-shrink: 0; }
.caro-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: color-mix(in srgb, var(--scent-ink, var(--ink)) 30%, transparent);
  transition: all 240ms ease;
}
.caro-dot.on {
  background: var(--scent-solid, var(--ink));
  transform: scale(1.35);
}

/* 操作指引纸条（2026-09-11 老板要求）。三步各放一个位置，都贴**屏幕**的角，
   不是卡片里的元素：
     第一步（地点）→ 左下角      第二步（心情）→ 左上角
     结果页        → 正上方居中
   用的是第一步地点中文条那张牛皮纸素材（assets/guide/strip-note.png，959×253），
   400×106 同比。定位基准是 #view-customizing（它本来就是 position:relative）。
   躲开的东西：#caro-recap 第一步在右上(640,300)、第二步在右下(700,1478)，
   卡片 859 宽居中（x 110..969）、viewport 1200 高居中（y 约 360..1560），
   所以左下 bottom:90（y 1724 起）和左上 top:90（y 90..196）都不压卡片。
   ⚠️ 捏合时 gestures.js 会把这行字临时换成倒计时（"保持捏合… 3"），松手复原，
      所以纸条宽度要留够，别刚好卡住正常文案。 */
#caro-hint {
  position: absolute; z-index: 320;
  /* 2026-09-11 老板连提两次"大一点"：400×106/25px → 500×132/31px → **570×150/31px**。
     最后这一档只放大纸条、字不动，文字周围留白多一些，更像一张随手压的纸条。
     ⚠️ 别再拿"会不会顶到卡片"当上限——**三处纸条跟卡片在垂直方向本来就错开**：
     卡片（859×1100，viewport 1200 高居中）占 y 约 360..1560，
     而左下那条在 y≈1659 起、左上和正上那条在 y≈63..230，都不在卡片的行程里。
     真正的上限是文案：内容区 = 570-80(左右撕边毛口) = 490，
     最长那句「挥手翻页　捏合 2 秒确认」12 字符 ×(31+.1em) ≈ 410，还宽裕。 */
  width: 570px; height: 150px;
  background: url("../assets/guide/strip-note.png") center / 100% 100% no-repeat;
  display: flex; align-items: center; justify-content: center;
  /* 字在纸条里往下压一点（2026-09-11 老板）。纸条素材上下不对称——上缘的撕口
     比下缘浅，正几何居中看着会偏高。用 padding-top 把内容区往下挤 22px，
     文字在剩下的区域里再居中，等于整体下移 11px。
     全局是 border-box（style.css:73），所以 padding 不会把 150 的高度撑大、
     背景图也不会跟着拉伸。 */
  padding-top: 22px;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 31px; letter-spacing: 0.1em; text-indent: 0.1em;
  color: #4b3a26; opacity: 1; white-space: nowrap;
  filter: drop-shadow(0 3px 7px rgba(32, 31, 29, .2));
  flex-shrink: 0;
}
#caro-hint.at-loc    { left: 60px; bottom: 90px; transform: rotate(-2deg); }
/* 2026-09-18 左上角多了返回箭头（.back-btn 占 x 30..146、y 56..172），
   第二步这张纸条原来贴在 left:60 会被压住，整条往右让到箭头外面 */
#caro-hint.at-mood   { left: 176px; top: 90px;   transform: rotate(2deg); }
#caro-hint.at-result { left: 50%;  top: 70px;    transform: translateX(-50%) rotate(-1.5deg); }

/* 确定 / 去打印 按钮 —— 纸质实色 */
.caro-confirm {
  flex-shrink: 0; margin-top: 6px;
  padding: 18px 46px; border: none; border-radius: 999px;
  background: var(--scent-solid, var(--ink)); color: var(--paper);
  font-size: 1.15rem; letter-spacing: 0.12em; cursor: pointer;
  box-shadow: 0 14px 30px -16px rgba(0,0,0,0.6);
  transition: transform 160ms ease, filter 160ms ease;
}
.caro-confirm:active { transform: scale(0.96); filter: brightness(1.05); }

/* ---------- 完成态：整齐排列的漫游记录 ---------- */
.caro-final { display: none; }
#view-customizing.finished { justify-content: center; }
#view-customizing.finished .caro-topbar { display: none; }
#view-customizing.finished .caro-file { display: none; }
#view-customizing.finished .caro-final {
  display: flex; flex-direction: column; align-items: center;
  gap: 34px; animation: fadein 0.5s ease both;
}
.cf-head {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding-bottom: 22px; position: relative;
}
.cf-head::after {
  content: ''; position: absolute; left: 10%; right: 10%; bottom: 0; height: 1px;
  background: repeating-linear-gradient(90deg,
    color-mix(in srgb, var(--ink) 45%, transparent) 0 6px, transparent 6px 12px);
}
.cf-title { font-size: 2rem; font-weight: 700; letter-spacing: 0.2em; text-indent: 0.2em; }
.cf-sub { font-size: 0.8rem; letter-spacing: 0.3em; opacity: 0.5; }
.cf-date { font-size: 0.9rem; letter-spacing: 0.1em; opacity: 0.6; margin-top: 4px; }
.cf-body {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  max-width: 820px; text-align: center;
}
.cf-line { line-height: 1.6; }
.cf-line.fixed { font-size: 1.15rem; opacity: 0.5; }
.cf-line.chosen { font-size: 1.5rem; opacity: 0.96; letter-spacing: 0.02em; }

/* ============================================================
   三选一版（2026-09-04）：选择卡内容 + 结果三标签档案夹
   ============================================================ */

/* ---- 选择卡内容（2026-09-06 重排）----------------------------------------
   老问题：三步各排各的——地点卡居中、心情卡的字贴右下、场景卡又居中，叠卡露出
   的方向还从"右+下"跳到"右+上"，三步之间没有共同的版式；内容掉在正中间，四周
   空着，那不是留白是没安排。
   现在：**夹身是包装色，里面夹一张白纸，内容全在白纸上**。三步共用同一张白纸、
   同一个内容框、同一条左基线，只有框里装的东西不同。这也正好落在"文件夹打开→
   里面是一份份文件"那条线索上：夹子是彩色的，文件是白的。
   留白按日式的"天地"来：上方和左侧给足，内容靠上左，下方留空。 */
/* 候选卡的夹身**本身就是一张真实的档案页**（folder-sheet.png = 素材 16.png，
   米白、右侧一列侧标签，w/h 0.742 正好等于卡片的 460/624）。原来是 CSS 画的
   圆角矩形 + 色块，跟压在上面的实物素材不是一个世界。
   素材自带形状和阴影，所以这里要关掉 CSS 的圆角/描边/底色/box-shadow，
   投影改用 drop-shadow 贴着 PNG 的真实轮廓走。
   线香色只落在压上去的那张卡片纸(.cc-sheet)上——底是中性的，色相才分得开。 */
.caro-card.choice .folder-body {
  /* --folder-img 由 js/carousel.js 按香型注入（见 FOLDER_BY_SCENT） */
  background: var(--folder-img, url("../assets/archive/fd-sunday.png")) center / 100% 100% no-repeat;
  border: none; border-radius: 0; overflow: visible;
  box-shadow: none;
  filter: drop-shadow(0 22px 40px rgba(60,45,25,0.42));
}
.caro-card.choice.focus .folder-body {
  box-shadow: none;
  filter: drop-shadow(0 34px 60px rgba(30,20,10,0.5));
}
/* 类别名：四款香换成各自的档案夹之后，素材自带的标签舌位置各不相同
   （月夜银桂那张在左上，其余在右上），没法再把文字贴到某个固定的舌上。
   改成卡片左上角的一行小字，四款统一；top 取卡高的 13%，避开所有素材
   顶部那段标签舌／缺口。 */
.caro-card.choice .folder-tab {
  background: none; clip-path: none; box-shadow: none;
  top: 76px; left: 46px; right: auto; bottom: auto;
  min-width: 0; width: auto; height: auto; padding: 0;
  writing-mode: horizontal-tb;
  align-items: baseline; justify-content: flex-start;
}
.caro-card.choice .folder-tab .tab-label {
  writing-mode: horizontal-tb;
  font-size: 0.58rem; font-weight: 500; letter-spacing: 0.22em;
  color: #6b5b45; white-space: nowrap;
}
/* 夹身固定成浅纸色之后，落在夹身上的字不能再跟着香型走——阳台的夜的 --f-ink
   是浅色(#eef3ef)，在浅纸上就废了。卡片纸**里面**的字仍用 --f-ink，那是跟
   --f-bg 配套调的（浅青配深棕、深绿配浅白），四款都成立。 */
.caro-card.choice .cc-name,
.caro-card.choice .cc-mood-line,
.caro-card.choice .folder-tab .tab-label { color: #3a2f22; }

/* ============================================================
   地点候选卡 = A4 拼贴海报
   数值全部来自 claude-code-prompt.md，**不要在这里"顺手调"**：
   舞台按 794×1123 原尺寸搭好，再整体 scale(0.5794) 塞进 460×651 的卡片
   （794×0.5794=460，1123×0.5794=650.7）。缩放前后 1:1，改版式只改这一处比例。
   ============================================================ */
/* 2026-09-07 结构调整：薄荷底色**不再画在卡片里**——那样它就成了一个跟着卡片
   一起翻动的色框。底色现在铺满整屏（见 #view-customizing），卡片只保留那张
   黑色档案夹，也就是海报里 (30,120) 起、734×940 的那块。
   做法：stage 仍按 794×1123 原样搭（坐标一个不改），再往左上挪 (-30,-120)×scale，
   把档案夹以外的部分推出卡片、由 overflow 裁掉。 */
.poster-stage {
  position: absolute;
  left: calc(-30px * var(--ps-scale)); top: calc(-120px * var(--ps-scale));
  width: 794px; height: 1123px;
  transform: scale(var(--ps-scale)); transform-origin: 0 0;
  background: none;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
}
.poster-stage > * { position: absolute; }
/* 1 档案夹：米黄夹压到近黑 */
/* 1 档案夹：用素材当**遮罩**、填成这一款的夹子色。四款差得太远
   （近黑 / 棕 / 纯黑 / 金黄），靠滤镜调不准。 */
.ps-folder { left: 30px; top: 120px; width: 734px; height: 940px;
  background-color: var(--mp-folder, rgb(91,69,44));
  -webkit-mask: url("../assets/poster/folder-cream.png") center / 100% 100% no-repeat;
  mask: url("../assets/poster/folder-cream.png") center / 100% 100% no-repeat; }
/* 2 照片堆第二层：三张候选各一张纸。三张素材比例不同（0.933 / 0.845 / 0.811），
   各按自己的比例给尺寸才不变形，位置对齐同一个左上角。 */
.ps-strip { position: absolute; object-fit: fill; }
.ps-strip.m-0 { left: 276px; top: 276px; width: 336px; height: 360px; transform: rotate(-2.4deg); }
.ps-strip.m-1 { left: 282px; top: 272px; width: 330px; height: 390px; transform: rotate(-1.4deg); }
.ps-strip.m-2 { left: 286px; top: 268px; width: 326px; height: 402px; transform: rotate(-3deg); }
/* 3 NOTES 便签条 + 手写地址（右半故意被照片压住） */
.ps-note { left: 288px; top: 264px; width: 168px; height: 395px; transform: rotate(-4.5deg); }
.ps-note-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; }
.ps-addr { position: absolute; left: 26px; right: 22px; top: 84px;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 17px; line-height: 1.72; color: #3f4a52; }
/* 4/5 照片堆（2026-09-07 整体放大一档）：黑白照仍是彩色照的两倍长、顶边对齐。
   底边落在 y=264+590=854，海报底部那行字在 bottom:156（y≈967），中间留 113px 空。
   放大就到此为止——再大字和图就贴上了。 */
.ps-mat-bw { left: 430px; top: 264px; width: 308px; height: 590px; padding: 13px;
  box-sizing: border-box; background: #f7f4ee; transform: rotate(1deg); }
.ps-mat-bw img { width: 100%; height: 100%; object-fit: cover; display: block;
  filter: grayscale(1) contrast(1.05); }
/* 彩色照：盖住黑白照的上半，比它更大更靠前 */
.ps-mat-color { left: 346px; top: 264px; width: 320px; height: 299px; padding: 17px;
  box-sizing: border-box; background: #fcfaf5; }
.ps-mat-color img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 6 回形针 */
.ps-clip { left: 486px; top: 232px; width: 34px; height: 99px; }
.ps-clip path { fill: none; stroke: #9d9787; stroke-width: 4.5; stroke-linecap: round; }
/* 7 胶带标签（最上层） */
.ps-tape { left: 430px; top: 512px; width: 316px; height: 76px; transform: rotate(-2.6deg);
  display: flex; align-items: center; justify-content: center; }
/* 胶带素材(60(1))是竖长的一条(0.24)，直接 fill 进 300×72 会压成一条线。
   按原比例给 72×300、再转 90°，视觉上正好是 300×72 的横胶带。 */
.ps-tape-img { position: absolute; left: 50%; top: 50%; width: 72px; height: 300px;
  transform: translate(-50%, -50%) rotate(90deg); object-fit: fill; }
/* 胶带上只写一个英文词，花体 Snell Roundhand（macOS 系统自带，不用下载；
   装置不是 Mac 的话会落到已本地化的 Mrs Saint Delafield）。
   花体的 x-height 小，26px 会显得比原来的中文小一大截，提到 40px。 */
.ps-tape-txt { position: relative;
  font-family: "Snell Roundhand", cursive;
  font-size: 40px; line-height: 1; letter-spacing: 0.02em;
  color: #3a332a; font-weight: 400; white-space: nowrap; }
/* 第二步（心情）胶带上是中文关键词，走手写中文体、回到原来那个字号 */
.p-mood .ps-tape-txt { font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 26px;
  letter-spacing: 0.12em; font-weight: 300; }
/* 档案夹上的字，全部背景薄荷色 */
.ps-elsewhere { left: 92px; top: 148px; font-size: 30px; color: var(--mp-ink, #f0e2b4); }
/* 2026-09-20 只剩花体名一个孩子，左对齐（Chapter III / 竖线 / Incense /
   Wander Hours 已删，对应的样式也一并去掉了）。细线 .ps-hairline 和
   右下那行 .ps-footer 留着。 */
.ps-caption { left: 84px; right: 76px; bottom: 150px; display: flex;
  align-items: flex-end; justify-content: flex-start; color: var(--mp-ink, #f0e2b4); }
/* 2026-09-20 老板：再小一点 68 → 54（第二步那个花体是 46，这边稍大，它是这一屏唯一的标题） */
.ps-scent { font-family: "Snell Roundhand", cursive; font-size: 54px; line-height: 0.8;
  white-space: nowrap; }
/* 地点中文名写在一张撕边纸条上（2026-09-10 从花体右边挪过来，位置是老板圈的）。
   纸条素材 959×253（比例 3.79），这里 300×79 正好同比。字色不跟 --mp-ink 走——
   纸条本身是米白的，四款都得用深褐才压得住。 */
/* 2026-09-11 老板："这个纸条向左倾斜，可以微微压住后面的素材以及右边的图片。"
   原来是 300×79 摆在 (120,656)、转 -2.5°，刻意谁也不碰——实测右端 x=421，
   而右边那张黑白照从 x=425 起，**正好差 4px 擦肩而过**，横线卡也只压到 16px，
   看着像躲着走。现在：
     · 角度 -2.5° → **+5°**，向**右**倾斜（正值＝顺时针＝右端下沉）。
       2026-09-11 先按"向左倾斜"做成了 -5°，老板当场纠正"说反了，向右倾斜"。
     · 尺寸 300×79 → 340×90 → **315×83**（2026-09-11 老板"再小一点点"回调了一档，
       素材 959×253 的比例始终同比，纸条不变形）。缩小的同时 left 120→135，
       否则右端会从 460 缩回 435、跟黑白照只剩 13px 重叠，又变回"擦着走"
     · 上移 656→636，跟浅蓝横线卡（底边 y=665）的重叠从 16px 加到 29px
   层级不用额外设 z-index：纸条在 buildPosterStage 里是倒数第三个 appendChild，
   横线卡和两张照片都在它前面，文档流顺序天然压在上面（实测各元素 z 全是 auto）。 */
.ps-strip-note { left: 135px; top: 636px; width: 315px; height: 83px;
  transform: rotate(5deg); filter: drop-shadow(0 4px 8px rgba(32,31,29,.22)); }
.ps-strip-note img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: fill; display: block; }
.ps-strip-cn { position: absolute; inset: 0; display: flex;
  align-items: center; justify-content: center;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-weight: 400;
  font-size: 22px; letter-spacing: .14em; text-indent: .14em; color: #4b3a26; white-space: nowrap; }
.ps-hairline { left: 84px; right: 76px; bottom: 136px; height: 1px;
  background: var(--mp-ink, #f0e2b4); }
/* 2026-09-20 老板："这里要用品牌 logo，除了颜色以外不能改任何东西"。
   所以不再用字体排 COSMIC SPECULATION，改成拿品牌字标 assets/brand/logo-en.png
   （772×54 纯黑透明底，跟老板发的 logo英文1.png 是同一个文件）当**遮罩**，
   填成这一款的 ink 色 —— 字形一个像素不动，只有颜色跟着香型走。
   ⚠️ 用 `contain` 不用 `100% 100%`：万一盒子的宽高比跟 772:54 对不上，
   contain 只会在盒子里留白，不会把字标拉变形。 */
.ps-footer { right: 76px; bottom: 100px; width: 206px; height: 15px;
  background-color: var(--mp-ink, #f0e2b4);
  -webkit-mask: url("../assets/brand/logo-en.png") center right / contain no-repeat;
  mask: url("../assets/brand/logo-en.png") center right / contain no-repeat; }

/* 海报卡：夹身/内边距那套全部让位，卡片就是海报本身 */
.caro-card.choice.location .folder-body,
.caro-card.choice.mood .folder-body {
  background: none; border: none; border-radius: 0; overflow: hidden;
  box-shadow: none; filter: drop-shadow(0 22px 40px rgba(40,30,16,0.45));
}
.caro-card.choice.location .cc-content,
.caro-card.choice.mood .cc-content { position: absolute; inset: 0; padding: 0; display: block; }

/* 每张卡＝一张海报：图直接压在这张彩色卡纸上，卡纸就是海报的纸。
   （试过在夹身里再垫一张白纸——夹子/白纸/照片三层，卡就从一张印刷品变成了
   一份表单，海报感全没了。那层白纸已去掉。） */
.caro-card.choice .cc-content {
  position: absolute; inset: 0; z-index: 4;
  display: flex; flex-direction: column;
  align-items: flex-start; justify-content: flex-start;
  padding: 58px 44px 46px; gap: 0; text-align: left;
}
/* ---- 堆叠层：主体 + 垫在下面的两张纸 + 压在上面的夹子 -------------------
   参考 "Paper Archives" 那种把几张纸随手摞进档案夹的样子：垫纸要露边角、要
   带角度，主体压在中间，夹子咬住顶边。纸和夹子都是真实实物去背 PNG。 */
.cc-stack { position: relative; width: 100%; height: 372px; flex-shrink: 0; }
.cc-paper, .cc-clip {
  position: absolute; background-repeat: no-repeat; background-size: contain;
  background-position: center; pointer-events: none;
}
/* 垫纸 A：偏左下探出，压在主体后面。加一点点暖色让它跟相纸白边分得开——
   两张都是白的时候会糊成一块，看不出是两张纸。 */
.cc-paper.under-a {
  left: -30px; top: 40px; width: 300px; height: 330px;
  transform: rotate(-5.5deg); opacity: 0.95; z-index: 1;
  filter: sepia(0.16) saturate(1.1) drop-shadow(0 8px 16px rgba(40,28,14,0.2));
}
/* 垫纸 B：偏右上探出 */
.cc-paper.under-b {
  right: -34px; top: -14px; width: 214px; height: 258px;
  transform: rotate(7deg); opacity: 0.94; z-index: 2;
  filter: sepia(0.1) drop-shadow(0 8px 16px rgba(40,28,14,0.18));
}
/* 长尾夹（8.png，浅蓝，w/h 0.90）：跨在主体顶边上，上半探出、下半压住 */
.cc-clip {
  left: 138px; top: -46px; width: 86px; height: 96px;
  transform: rotate(-4deg); z-index: 8;
  filter: drop-shadow(0 8px 14px rgba(30,20,10,0.4));
}
/* 主体：照片嵌进**真实的空相框**（photo-frame.png，中间 alpha=0）。
   实测内窗口 左9.44% 右89.32% 上20.35% 下78.42%（顶上那 20% 是框自带的胶带），
   img 就按这几个百分比落进去，框由 ::after 压在 img 之上。
   不再用 CSS 画白边——白边是画的，框是拍的，两者放一起立刻露馅。 */
.caro-card.choice .cc-photo {
  position: absolute; left: 50%; top: 50%;
  width: 310px; height: 312px; margin: 0;
  transform: translate(-50%, calc(-50% - 10px)) rotate(var(--rot-photo, -1.5deg));
  padding: 0; background: none; box-shadow: none;
  filter: drop-shadow(0 14px 28px rgba(30,20,10,0.42));
  z-index: 5;
}
.caro-card.choice .cc-photo img {
  position: absolute; left: 9.44%; top: 20.35%; width: 79.9%; height: 58.1%;
  object-fit: cover; display: block;
}
.caro-card.choice .cc-photo::after {
  content: ''; position: absolute; inset: 0; z-index: 2;
  background: url("../assets/archive/photo-frame.png") center / 100% 100% no-repeat;
}
/* 标题：海报的题，压在图下方，够大才立得住 */
/* 字要小。html{font-size:28px} 下 1.6rem 是 44.8px，一个地点名占掉半张卡，
   把堆叠的层次全压下去了。参考图里这类标题都是退到边上的小字。 */
.cc-name {
  margin-top: 26px;
  font-size: 0.95rem; font-weight: 500; letter-spacing: 0.14em; line-height: 1.4;
  color: var(--f-ink, #2c2119);
}

/* ============================================================
   结果页「文字板块」海报 900×1320
   坐标全部照 Desktop/漫游一刻/mood/复刻提示词.md 的基准代码，别在这儿改数。
   屏幕是 1080×1920，放得下，所以原尺寸摆、不缩放。
   ============================================================ */
/* 这块是**第二步的选项卡**，跟第一步一样：底色由整屏铺（#view-customizing），
   卡片里只留会翻动的那部分——文件夹(9,84 起 825×1102)加上探出它右边一点的纸叠，
   合起来 843×1102。做法同第一步：stage 按 900×1320 原样搭、坐标一个不改，
   再往左上挪 (-9,-84)×scale，多余的由卡片 overflow 裁掉。 */
.mood-stage {
  position: absolute;
  left: calc(-9px * var(--mp-scale)); top: calc(-84px * var(--mp-scale));
  width: 900px; height: 1320px;
  transform: scale(var(--mp-scale)); transform-origin: 0 0;
  background: none; font-family: "Freud", "Source Han Sans CN", sans-serif;
}
.mood-stage > * { position: absolute; }
/* 2 文件夹：水平镜像（标签舌翻到左边）。素材是肉粉牛皮，这里用它当**遮罩**、
   填成这一款的夹子色——四款差得太远（近黑/棕/纯黑/金黄），靠滤镜调不准。 */
/* 心情板块的文件夹：标签舌在**左上角**。素材 34.png 的舌在右上（实测舌那一段
   右边缘 x 0.935~0.995、纵向 y 0.07~0.32，主体右边缘只到 0.935），做水平镜像
   就翻到左上，镜像后舌占 x 0.005~0.065。
   走过两个弯路：19.png 是顶标签款、形状不对；36.png 镜像后舌在**中部**高度，
   看着像"开到中间去了"。 */
.mp-folder {
  left: 9px; top: 84px; width: 825px; height: 1102px;
  background-color: var(--mp-folder);
  -webkit-mask: url("../assets/mood/folder-side.png") center / 100% 100% no-repeat;
  mask: url("../assets/mood/folder-side.png") center / 100% 100% no-repeat;
  transform: scaleX(-1);
  filter: drop-shadow(0 18px 34px rgba(40,26,20,.34));
}
/* 3 夹上的三处字 */
/* WANDER MOOD 压在左上角那个标签舌上。位置按镜像后的舌区间换算：
   横向 9 + 825×0.005 ≈ 13 起、宽 825×0.06 ≈ 50，
   纵向 84 + 1102×0.07 ≈ 161 起、到 84 + 1102×0.32 ≈ 437。
   rotate(180) 让字从下往上读，跟参考稿一致。 */
/* 标签舌上的字（2026-09-20）：中文心情竖排 + 英文横排整行逆时针转 90°。
   舌区 x13..63 / y161..437 量自素材，见上面 .mp-folder 那段说明。
   ⚠️ 中文这一行**不能套 rotate(180deg)**。原来那行是英文 WANDER MOOD，转 180°
   是为了让它从下往上读；换成中文之后 180° 会把每个字倒过来（"停留"变成倒立的）。
   中文竖排本来就是从上往下，vertical-rl 一个属性就够。
   英文反过来：不逐字竖排（那样一个字母一行很怪），而是**整行横排再转 -90°**，
   这是老板明确要的做法。 */
.mp-side {
  left: 13px; top: 161px; width: 50px; height: 276px; right: auto;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px; color: var(--mp-ink);
}
.mp-side-cn {
  writing-mode: vertical-rl;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 26px; letter-spacing: .16em;   /* 2026-09-20 老板嫌 34 大了 */
  white-space: nowrap;
}
/* 英文整行逆时针转 90°（老板指定）。
   ⚠️ 直接写 transform: rotate(-90deg) 不行——转的只是画面，**布局盒子还是横着的**
   （宽 90 高 20），flex 的 gap 按那个横盒子算，转完的字就会压到上面的中文上。
   用 writing-mode 让浏览器把盒子也变成竖的（窄高），再 rotate(180deg) 把
   sideways 默认的顺时针读向翻成逆时针（从下往上读），这样盒子和画面才一致。 */
.mp-side-en {
  writing-mode: vertical-rl; text-orientation: sideways;
  transform: rotate(180deg);
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 19px; letter-spacing: .2em; font-style: italic;   /* 2026-09-20 老板"可以大一点" */
  white-space: nowrap; opacity: .8;
}
/* 4 四层错位纸叠 */
.mp-sheet { border-radius: 2px; }
.mp-sheet.s-a { left: 40px; top: 676px; width: 812px; height: 496px; background: #d8cfc1;
  transform: rotate(-1.5deg); box-shadow: 0 14px 26px rgba(40,26,20,.26); }
.mp-sheet.s-b { left: 52px; top: 664px; width: 800px; height: 504px; background: #e2dacd;
  transform: rotate(1.2deg); box-shadow: 0 10px 20px rgba(40,26,20,.2); }
.mp-sheet.s-c { left: 46px; top: 660px; width: 790px; height: 500px; background: #eae4d9;
  transform: rotate(-.5deg); box-shadow: 0 8px 16px rgba(40,26,20,.16); }
.mp-sheet.s-d { left: 66px; top: 668px; width: 778px; height: 494px; background: #f1ece3;
  transform: rotate(.6deg); box-shadow: 0 8px 14px rgba(40,26,20,.12); }
/* 5 顶层纸：纸纹 + 整段文案 */
.mp-top { left: 62px; top: 658px; width: 772px; height: 500px; border-radius: 3px;
  overflow: hidden; transform: rotate(-.15deg); box-shadow: 0 16px 34px rgba(40,26,20,.3); }
.mp-paper { position: absolute; inset: 0;
  background: url("../assets/mood/paper.jpg") center / cover no-repeat; }
/* 2026-09-18 字号由 js/carousel.js 的 fitMoodCopy 按这一款最长那行现算（26px 封顶、
   19px 保底）并写在 style 上；这里的 19px 只是拿不到 JS 时的兜底。
   左内边距 86 → 46：字号大了要横向让出地方，右边到压花之间只有 520px。 */
.mp-lines { position: absolute; inset: 0; display: flex; flex-direction: column;
  justify-content: center; padding: 120px 86px 0 46px;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-weight: 400;
  font-size: 19px; line-height: 1.95; color: #33302c; letter-spacing: .04em; }
.mp-line { white-space: nowrap; }
/* 6 回形针 2026-09-20 老板删掉了 */
/* 7 相框组（2026-09-20 重做，见 js/carousel.js 的 sizeMoodFrame）
   垫子不再用 frame.png——那张是固定比例的，一拉伸边宽就变形。改成 CSS 画：
   底色 #e2d8c8、边距 35/40/63，都量自原素材（垫子 799×731、开口 61,144 起 681×558）。
   开口尺寸 --win-w/--win-h 由 JS 按这张照片的比例算，所以框是跟着图走的。
   胶带另做了一张横的 assets/mood/tape.png，压在垫子左上角。 */
/* 2026-09-20 下午：开口统一横构图（老板"不要有的竖着有的横着"），
   并且相框要**微微压住下面那张文案卡**（纸叠从 y=658 起）——
   垫子高 466+103=569，中心放 434 ⇒ 上缘 150、下缘 719，压住 61px。 */
.mp-frame {
  /* 中心 478：垫子高 420+103=523 ⇒ 下缘 739，纸叠从 658 起，压住 81px
     （老板"多压住一点文字卡"）。再往下就要顶到诗行了——正文从 778 开始。 */
  left: 450px; top: 478px; transform: translate(-50%, -50%) rotate(-1.6deg);
  filter: drop-shadow(0 16px 26px rgba(40,26,20,.3));
  z-index: 6;   /* 压在纸叠和顶层纸之上 */
}
.mp-mat {
  background: #e2d8c8; padding: 40px 35px 63px;
  box-shadow: inset 0 0 0 1px rgba(90,74,54,.10);
}
/* 四款一个尺寸的横开口（560×466，比 0.72 之前那版 403×326 大了一圈）。
   心情图多数是 9:16 竖图，cover 会裁掉上下——统一横构图就一定要付这个代价，
   靠把开口放大来缓解。要再少裁只能把开口做得更接近正方，但那就不"横"了。 */
.mp-photo {
  display: block; width: 505px; height: 420px;   /* 2026-09-20 老板"又有点太大了" 560×466 → 505×420 */
  object-fit: cover; object-position: center 42%;   /* 竖图略偏上，人/主体通常在上半部 */
  background: #efe7d6;
}
/* 胶带贴中间（2026-09-20 老板） */
.mp-tape { position: absolute; left: 50%; top: -40px; width: 252px;
  transform: translateX(-50%) rotate(-5deg); pointer-events: none; }
/* 花体香型名：**整个落在垫子上**，不压照片（老板三次调整后定的：
   先"压住图片和框" → "只压一点点" → "还是在框上吧"）。
   算法：垫子下边距 63，字框顶 = bottom + 字号 46。bottom=12 ⇒ 字框顶 58，
   在照片下沿（63）之下 5px，一点不碰。要它重新压上去就把 bottom 调大。 */
.mp-script { position: absolute; left: 40px; bottom: 12px; white-space: nowrap;
  transform: rotate(-4deg); transform-origin: left bottom;
  font-family: "Snell Roundhand", cursive;
  font-style: italic; font-size: 46px; line-height: 1; letter-spacing: .06em; color: #453521; }

/* ============================================================
   明信片 1000×1500（2:3）——照 Desktop/漫游一刻/明信片/postcard-spec.md
   照片到 y=1020，下面纸白；花体斜 -4.6° 跨在那条**水平**切边上。
   spec §7：切边不斜、花体不加描边/渐变/投影、中文不做字号层级。
   ============================================================ */
/* 结果页：明信片夹在一块板夹上（04.png，1000×1413，自带顶部金属夹）。
   板夹按素材比例 0.708 给 940×1328；明信片缩到 0.70（700×1050）压在上面。
   金属夹下沿实测在 y≈177，明信片顶边给 164——**要比夹子下沿再高一点**，
   顶边压进夹子里才像被夹住；给 206 会留一道缝，看着是浮在板上。 */
.pc-board {
  position: relative; width: 940px; height: 1328px;
  background: url("../assets/poster/clipboard-plain.png") center / 100% 100% no-repeat;
  filter: drop-shadow(0 34px 60px rgba(30,20,10,0.42));
}
/* 金属夹是板夹素材自带的，明信片压上去会把它盖住。这里把夹子那一块再画一遍、
   叠在明信片之上，纸就真的被夹住了。background-size 必须跟主背景一样是
   940×1328，background-position 要用负偏移把要的那一块挪进这个盒子。
   ⚠️ 2026-09-20 绕了四轮才找到真因（老板最后发了一张夹子特写才说清）：
   他要的那种夹子**中间是空的**，从框里看到的是**纸**；而我们素材里这只夹子
   中间是一整块实心铬板，所以纸不管藏多深、位置怎么调，看着都是"一块板压在图上"，
   不是"纸夹在夹子里"。**不是尺寸问题，也不是塞多深的问题，是夹子本身的构造。**
   解法：把那块铬板挖掉 —— `clip-frame.png` ＝ clip.png 抹掉 x96..438 / y68..138
   那一块的 alpha（高斯羽化 2.2px，别切出硬口子），只留上杆、左右导轨、下唇、
   两侧黑卡脚，明信片从这个框里透出来。
   窗口在板坐标 x312..634 / y92..158 ⇒ **明信片上边必须在 92 以上**（现在 64），
   否则框里露的是纸板不是明信片。
   中途试错留下的 clip-open.png（把夹子切开一条缝）方向不对，文件没删。 */
.pc-board::after {
  content: ''; position: absolute; left: 222px; top: 100px; width: 502px; height: 179px;
  background: url("../assets/poster/clip-frame.png") 0 0 / 100% 100% no-repeat;
  z-index: 3; pointer-events: none;
}
.pc-card {
  position: absolute; left: 50%; top: 164px; z-index: 1;   /* z-index 1：夹子在明信片之上 */
  width: 1000px; height: 1500px; overflow: hidden;
  background: #f5f3ee;
  box-shadow: 0 18px 34px -18px rgba(30,20,10,0.45);
  /* 屏幕上缩小（打印稿不受影响，那边是 canvas 按 300dpi 另画的）。
     内部坐标一律保持 spec 的原值，只整体缩放，免得每个数都要重算。 */
  transform: translateX(-50%) scale(0.70); transform-origin: top center;
}
.pc-photo { position: absolute; left: 0; top: 0; width: 1000px; height: 1020px;
  object-fit: cover; object-position: center 50%; display: block; }
.pc-overlay { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.pc-script { font-family: "Snell Roundhand", cursive; font-size: 240px; }
.pc-copy {
  /* 2026-09-17 老板嫌字小：19px → 25px。花体标题和底部 logo 之间就这么高，
     行高 1.85→1.7、行间 gap 11→6、底边 104→80 一起收，六行整块顶边仍在 y≈1135，
     让开花体。改这里要同步 js/print.js 第 4 段（打印/保存那张 canvas）。 */
  position: absolute; left: 0; right: 0; bottom: 80px;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 0 50px; text-align: center;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-weight: 300;
  font-size: 25px; line-height: 1.7; letter-spacing: .06em; color: #3c3831;
}
.pc-copy p { margin: 0; }
/* 落款＝品牌英文 logo（2026-09-10 换掉原来的 wander hours 字样）。
   原图 772×54，这里定宽 240px、高度按比例走；opacity 对齐原来那行暖灰字的分量。 */
.pc-sign {
  position: absolute; left: 50%; bottom: 34px; transform: translateX(-50%);
  width: 240px; height: auto; display: block; opacity: .6;
}

/* ---- 结果：明信片排版（参考 #79：题目+图片+场景挂牌贴图+居中文案） ---- */
#view-customizing.finished { justify-content: center; }
#view-customizing.finished .caro-topbar { display: none; }
#view-customizing.finished .caro-file { display: none; }
#view-customizing.finished .caro-final {
  display: flex; flex-direction: column; align-items: center; gap: 40px;
  animation: fadein 0.5s ease both;
}
/* 布局对齐 #102 的占位比例：题注→大标题→副题→大横图→图角小挂牌→居中文案块→两行页脚 */
/* 结果明信片＝一页档案文件（2026-09-04 照 #15 重排）：整页**左对齐**，左上角一枚
   深棕折页标签(香型英文名)，右上四点角标，左下装订圆孔，页脚日期左/品牌右。 */
/* 2026-09-06：纸的材料层。原来整张卡是一块纯 #fdf9e3——一页"档案纸"却没有纸。
   这里不用噪点滤镜（feTurbulence 那种颗粒放大就露怯），改用三层极低对比的大尺度
   径向渐变：一处受光的亮斑 + 两处纤维压暗，模拟纸张本身的不均匀。只影响屏幕，
   打印走 print.js 的 canvas 合成，不受这里影响。 */
.result-postcard {
  position: relative; width: 600px;
  background-color: #fdf9e3;
  background-image:
    radial-gradient(58% 42% at 22% 14%, rgba(255,253,242,0.85), transparent 68%),
    radial-gradient(48% 40% at 84% 74%, rgba(146,120,74,0.07), transparent 70%),
    radial-gradient(42% 34% at 56% 42%, rgba(146,120,74,0.045), transparent 72%);
  border: 1px solid rgba(60,45,25,0.14);
  box-shadow: 0 44px 96px -42px rgba(30,20,10,0.55);
  padding: 66px 46px 46px; color: #4a3d28;
  display: flex; flex-direction: column; align-items: stretch;
}
/* 左上折页标签：档案夹梯形（右下斜切），深棕底白字，印香型英文名 */
.rp-tab {
  position: absolute; top: 0; left: 0; height: 42px; padding: 0 34px 0 46px;
  display: flex; align-items: center;
  background: #8a7752; color: #fdf9e3;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.82rem; letter-spacing: 0.14em; white-space: nowrap;
  clip-path: polygon(0 0, 100% 0, calc(100% - 18px) 100%, 0 100%);
}
/* 右上四点角标 */
.rp-dots {
  position: absolute; top: 20px; right: 46px; width: 6px; height: 6px; border-radius: 50%;
  background: #a5895b; box-shadow: -15px 0 #a5895b, -30px 0 #a5895b, -45px 0 #a5895b;
}
/* 左下装订圆孔（#15）。位置别动：试过挪到跟页脚同一条基线，紧挨着日期就读成
   了项目符号，不再像打在纸上的孔——它要单独待在页脚下方的空白里才成立。 */
.result-postcard::after {
  content: ''; position: absolute; left: 30px; bottom: 24px; width: 11px; height: 11px;
  border-radius: 50%; border: 1.5px solid rgba(120,95,60,0.45);
}
/* 抬头：中文名主、英文名副，各占一行。
   本来想并成一行，但量下来中文名恒宽 223.8px，英文名从 HOTEL ROOM 的 172px 到
   MOONLIT OSMANTHUS 的 293px——后两款加起来超过 506px 的内容宽，会掉到第二行，
   于是四款出现两种抬头。要挤成一行就得把英文名压到 0.62rem 才装得下最长的那个，
   小得读不清。所以统一两行：四款一致，字号也不用为最长的名字让步。 */
.rp-head { width: 100%; text-align: left; }
.rp-title {
  display: block;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-weight: 400;
  font-size: 1.85rem; line-height: 1.15; letter-spacing: 0.08em;
  color: #3a2f1e; margin: 0; white-space: nowrap;
}
.rp-sub {
  display: block; margin-top: 9px;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.72rem; letter-spacing: 0.2em;
  color: #7f6c44; white-space: nowrap;   /* ≈4.6:1，小字要过 4.5 */
}
/* 字段线：抬头与内容之间的分隔，档案表单上真实存在的那条线 */
.rp-rule { display: block; height: 1px; margin: 18px 0 0; background: rgba(120,95,60,0.28); }
/* 图片：大幅横构图、接近满宽 */
.rp-photo { position: relative; width: 100%; margin: 22px 0 0; }
/* 照片压进纸的色温里：整页是米黄单色调，全彩照片会像贴上去的另一个世界。
   只降一点饱和、加一点暖，不做灰度——地点的颜色本身是内容。 */
.rp-photo > img {
  width: 100%; height: 306px; object-fit: cover; display: block;
  filter: saturate(0.86) sepia(0.07);
  box-shadow: 0 22px 44px -22px rgba(30,20,10,0.5);
}
/* 地点名：是内容不是数据，用正文字体，不用打字机体。颜色从 #9c8a60 加深到
   #6b5a3e——前者在 #fdf9e3 纸上只有约 3:1，小字读不住。 */
.rp-photo-cap {
  display: block; text-align: left; margin-top: 30px;
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.86rem;
  letter-spacing: 0.08em; color: #6b5a3e;
}
/* 场景挂牌：吊在大图右下角**外侧**（一半探出图外、往下垂，对应 #11）。下方的
   "我漫游在…"说明用更大的 margin-top 让开它，避免像 #6 那样被挂牌切到。 */
/* 挂牌照 #13 改成**平顶圆角**（去掉原来的尖顶 clip-path），像一枚干净的行李/吊牌。
   加宽一点让英文和日期各自一行不折行；圆孔落在平顶正中。 */
.rp-hangtag {
  position: absolute; right: 14px; bottom: -20px; width: 124px; padding: 22px 12px 12px;
  background: #e7dcc2; color: #3a2c1c; transform: rotate(7deg);
  box-shadow: 0 14px 26px -10px rgba(30,20,10,0.5);
  border-radius: 10px;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
}
.rp-hang-hole { position: absolute; top: 8px; left: 50%; transform: translateX(-50%); width: 9px; height: 9px; border-radius: 50%; background: #fdf9e3; box-shadow: inset 0 0 0 2px rgba(80,60,40,0.5); }
.rp-hang-cn { font-size: 0.72rem; font-weight: 500; letter-spacing: 0.06em; white-space: nowrap; }
.rp-hang-en { font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.4rem; letter-spacing: 0.16em; opacity: 0.6; text-align: center; white-space: nowrap; }
.rp-hang-time { font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.4rem; letter-spacing: 0.06em; opacity: 0.5; margin-top: 5px; border-top: 1px dashed rgba(120,95,60,0.4); padding-top: 5px; text-align: center; line-height: 1.5; }
/* 文案块：心情词是这一段的题目，散文跟在下面 */
.rp-copy { display: flex; flex-direction: column; align-items: flex-start; gap: 9px; margin-top: 30px; text-align: left; }
/* 心情词：层级靠字号和字重，不靠颜色——四款香的 accent 里阳台的夜(#bfe0d9)和
   月夜银桂(#e0a63a)印在米黄纸上都到不了 3:1，纸上只该有一种墨。 */
.rp-copy-title {
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-weight: 500;
  font-size: 1.5rem; line-height: 1.2; letter-spacing: 0.16em;
  color: #3a2f1e; margin-bottom: 5px;
}
/* 宋体正文给多一点行距。字号从 0.8rem 提到 0.86rem（0.8 在现场站着看偏小），
   但不能再大：这些行是 white-space:nowrap，午后客厅最长那句在 0.88rem 下量到
   508px，比 506px 的内容宽多 2px，屏幕上看不出、打印会被裁掉。字距同时
   0.03em → 0.02em 再留一点余量。 */
/* 2026-09-06 换回品牌中文字（思源黑体，跟全站第 73 行一致）。思源只装了
   Regular/Bold 两个字重，原来的 300 会被浏览器合成伪细体、边缘发虚，所以落到 400。 */
.rp-copy-line { font-family: "Freud", "Source Han Sans CN", sans-serif; font-weight: 400; font-size: 0.86rem; line-height: 1.72; letter-spacing: 0.02em; color: #6b5a3e; white-space: nowrap; text-align: left; }
/* 页脚 #b6a271 在纸上约 2.2:1，读不住，压到 #7a6540（≈4.7:1） */
.rp-foot { margin-top: 34px; display: flex; flex-direction: row; justify-content: space-between; align-items: baseline; gap: 16px; font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.56rem; letter-spacing: 0.14em; color: #7a6540; }
.rp-foot > span { white-space: nowrap; }

/* ---- 三选一卡：心情诗页排版 + 场景挂牌（2026-09-04 迭代） ---- */
/* 地点：我漫游在 · xx（长了也不溢出） */
.cc-name { max-width: 320px; line-height: 1.4; }

/* 心情：档案文件式——总结词 title「」 + 组里的几句（诗块，右对齐衬线），字更小更细、留白更大 */
/* 心情卡对齐到地点卡的同一套骨架：关键词占满和照片等高的那个方框、字沉在框底，
   于是它的下缘和地点卡照片的下缘落在同一条线上，下面那行小字也就对齐了。
   原来是 align-items:flex-end 整块贴右、justify-content:center 垂直居中，
   跟地点卡完全两套排法。 */
/* 心情卡＝一张字为主的海报：关键词是主视觉，占满和地点卡主图等高的那块，
   字沉在底——于是两步的题落在同一条线上，但各自仍是一张海报，不是一份表单。 */
.caro-card.choice.mood .cc-content { align-items: flex-start; justify-content: flex-start; gap: 0; padding: 58px 44px 46px; }
/* 心情卡的主体跟地点卡的照片同一个位置、同一个尺寸、同一个角度——区别只是
   地点卡那张是照片，心情卡这张是**写着关键词的卡片纸**。
   （试过让关键词直接铺满 stack：字压在垫纸和便签上，笔画和纸边绞在一起。
   字得有一张自己的纸。） */
/* 心情卡：关键词写在一张**卷角白纸**上（paper-curl.png），位置跟地点卡的
   相框一致，一样被长尾夹咬住 */
.cc-mood-sheet {
  position: absolute; left: 50%; top: 50%; z-index: 5;
  width: 268px; height: 274px;
  transform: translate(-50%, calc(-50% - 10px)) rotate(var(--rot-photo, -1.5deg));
  background: url("../assets/archive/paper-curl.png") center / 100% 100% no-repeat;
  filter: drop-shadow(0 14px 28px rgba(30,20,10,0.36));
  display: flex; align-items: center; justify-content: center;
}
.cc-mood-title {
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 2.1rem; font-weight: 600; letter-spacing: 0.14em; line-height: 1.1;
  color: #2f271d;
}
.cc-mood-lines { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; margin-top: 34px; }
.cc-mood-line {
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.8rem; font-weight: 400; line-height: 1.7; text-align: left;
  letter-spacing: 0.06em; color: var(--f-ink, #2c2119); opacity: 0.72;
  /* 允许换行：长句（如月夜银桂"茶刚沏好还烫着，把这一夜泡开了"）不撑出白纸
     （2026-09-04 用户 #12 反馈）。2026-09-06 改左对齐，跟地点名同一条左基线；
     限宽改成 100%＝白纸内宽，不再用固定 320px。 */
  max-width: 100%; white-space: normal;
}
/* .cc-mood-date 已不再生成（"MOOD · 日期"是第二次说类别），样式留着无害 */
.cc-mood-date { font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.6rem; letter-spacing: 0.16em; color: var(--f-sub, #5c4c3d); opacity: 0.5; }

/* 场景：挂牌（吊牌 + 绳 + 绳孔 + 时间）。挂牌是个悬挂的物件，横向居中比左对齐
   合理。位置放在图像区**上部**——原来压到 150px，白纸上半整片空着，跟身后那张
   背景卡的白纸连成一片，焦点卡的边界就读不出来了（三张卡的几何本来是一样的，
   ty = 32 - ad*58，问题不在位置在内容）。56px 是留给挂绳的（::before 在 top:-44px）。 */
.caro-card.choice.scene .cc-content { align-items: center; justify-content: center; padding: 58px 44px 46px; }
/* 场景卡：真实的**白吊牌**（tag-white.png，自带麻绳和铜孔，w/h 0.392），
   取代原来 CSS 画的挂牌。牌面在下方约 2/3，文字落在那儿。 */
.cc-scene-tag {
  position: absolute; left: 50%; top: 50%; z-index: 5;
  width: 122px; height: 311px;
  transform: translate(-50%, calc(-50% - 6px)) rotate(-3deg);
  background: url("../assets/archive/tag-white.png") center / 100% 100% no-repeat;
  filter: drop-shadow(0 12px 24px rgba(30,20,10,0.4));
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding-bottom: 46px; gap: 8px;
}
.cc-scene-tag .cc-scene-cn {
  writing-mode: vertical-rl; text-orientation: upright;
  font-size: 1.06rem; font-weight: 500; letter-spacing: 0.16em; color: #2f271d;
}
.cc-scene-tag .cc-scene-en {
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.42rem;
  letter-spacing: 0.18em; color: #6b5b45; opacity: 0.8; margin: 0;
}
.cc-hangtag {
  position: relative; width: 256px; padding: 56px 26px 22px;
  background: #e7dcc2; color: #3a2c1c; border-radius: 8px;
  box-shadow: 0 16px 32px -14px rgba(30,20,10,0.5);
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  transform: rotate(-2deg);
}
.cc-hangtag::before { /* 挂绳 */
  content: ''; position: absolute; top: -44px; left: 50%; width: 44px; height: 58px;
  transform: translateX(-50%); border: 2px solid rgba(120,95,60,0.55); border-bottom: none;
  border-radius: 22px 22px 0 0;
}
.cc-hang-hole {
  position: absolute; top: 16px; left: 50%; transform: translateX(-50%);
  width: 15px; height: 15px; border-radius: 50%; background: var(--f-bg, #d8ccb2);
  box-shadow: inset 0 0 0 2px rgba(80,60,40,0.5);
}
.cc-hangtag .cc-scene-cn { font-size: 1.5rem; font-weight: 500; letter-spacing: 0.14em; color: #3a2c1c; white-space: nowrap; line-height: 1.2; }
.cc-hangtag .cc-scene-en { font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.64rem; font-weight: 400; letter-spacing: 0.2em; color: #3a2c1c; opacity: 0.55; margin-top: 2px; }
.cc-scene-time {
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 0.58rem; letter-spacing: 0.08em; color: #3a2c1c; opacity: 0.5;
  margin-top: 12px; border-top: 1px dashed rgba(120,95,60,0.35); padding-top: 10px; width: 100%; text-align: center;
}

/* 文件卡从上方（衔接的档案夹）掉落进场 */
.caro-strip.dropin { animation: cardsDrop 760ms cubic-bezier(.22,.9,.26,1) both; }
@keyframes cardsDrop {
  0%   { transform: translateY(-720px) rotate(-2deg); opacity: 0; }
  55%  { opacity: 1; }
  100% { transform: translateY(0) rotate(0deg); opacity: 1; }
}

/* 2026-09-07 老板要求把选择屏的这几处 UI 全部去掉：进度 2/2、左右箭头、
   底部圆点、"挥手翻看 捏合选定"提示。画面只留香型名 + 引导句 + 卡片。
   ⚠️ 箭头**只能隐藏、不能删 DOM**：它们带 data-swipe-left/right，是挥手手势的
   落点，js/gestures.js 用 querySelector 找到后 dispatchEvent 派 click。
   dispatchEvent 不看元素可见性，所以 display:none 不影响手势；DOM 删了就找不到了。 */
#caro-progress,
.caro-dots,
.step-hint,
.caro-topbar .scent-tag { display: none; }

/* 打印按钮删掉（2026-09-07）：结果页捏三下就等于确认打印，合成完自动送印。
   DOM 留着——js/print.js 的 setupPrintActions 还在给它绑 onclick。 */
#do-print { display: none; }

/* ── 最后一屏（2026-09-18 老板）：跟前面几屏统一 ──────────────────
   1. 底也铺棕白竖条布，别再是一块淡绿色；
   2. 「长按图片保存到手机」垫上同一张撕边纸，跟前面那些指引一个做法
      （.sp-hint / #caro-hint 用的是同一张 strip-note.png）；
   3. 「重新漫游」原来是"细黑框 + 透明底"，压在布上读不出来，
      换成开屏那枚米白圆角牌（.enter-btn 的皮）。 */
#view-printing {
  background: var(--paper) url("../assets/poster/bg/sunday_afternoon.jpg") center / cover no-repeat;
  gap: 48px;
}
#print-status {
  width: 570px; height: 150px;
  display: flex; align-items: center; justify-content: center;
  padding-top: 22px;   /* 纸是撕边的，视觉中心比几何中心低一点 */
  background: url("../assets/guide/strip-note.png") center / 100% 100% no-repeat;
  font-size: 31px; letter-spacing: 0.1em; text-indent: 0.1em;
  color: #4b3a26; opacity: 1; white-space: nowrap;
  filter: drop-shadow(0 3px 7px rgba(32, 31, 29, .2));
}
/* 明信片压在布上，投影给深一点，才像一张纸真的放在织物上 */
#print-preview-img {
  box-shadow: 0 22px 38px -16px rgba(30, 18, 8, .45);
}
.print-actions button#restart-after-print {
  border: 0; border-radius: 999px;
  padding: 0; width: 420px; height: 104px;
  background: color-mix(in srgb, var(--paper) 72%, transparent);
  backdrop-filter: blur(7px);
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 38px; letter-spacing: 0.22em; text-indent: 0.22em;
  color: var(--ink);
  box-shadow: 0 12px 34px -24px rgba(26, 26, 26, .5);
}
.print-actions button#restart-after-print:active {
  transform: scale(0.97);
  background: color-mix(in srgb, var(--paper) 86%, transparent);
}

/* ⚠️ 箭头**不能用 display:none**：js/gestures.js 派挥手事件前有一道
   `if (!target || !target.getClientRects().length) return;`（防止点到不在当前
   屏上的箭头），而 display:none 的元素 getClientRects() 返回空数组，挥手会被
   这道检查直接挡掉、整个失效。改成留着盒子、只做视觉隐藏。 */
.caro-arrow { opacity: 0; pointer-events: none; }

/* ============================================================
   「漫游中」等待动画（2026-09-08）—— 规格见 Desktop/漫游一刻/等待动画.md
   舞台就是 #stage 的 1080×1920，坐标直接用文档里的绝对值，不再缩放。
   图层自下而上：布料底 → 写字板 → 散落字母 → 钟面组 → 环绕字幕。
   ============================================================ */
#view-identifying {
  padding: 0;
  background: #f7f2e6 var(--wander-cloth, url("../assets/poster/bg/sunday_afternoon.jpg")) center / 130% repeat;
}
.wc-stage { position: absolute; inset: 0; width: 1080px; height: 1920px; overflow: hidden; }
.wc-stage > * { position: absolute; }
/* 写字板。文档给的是 top:920 width:1624，但那是按它那张 4000×4000、板外透明的
   素材算的；我们这张 clipboard.png(1000×1413) 已经裁到板子本身，套同样的数值会
   被放到远超画布。改按文档给的**目标**反推：白纸区域要落在 x 53…1027 / y 460…1680，
   我们这张的金属夹在**板内顶端**、白纸从夹子下面才开始（约占全图 82%），
   所以要按白纸那一段去套：图高 = 1220/0.82 = 1488、宽 = 1488×0.708 = 1053、
   图顶 = 460 - 1488×0.18 = 192 → 中心 y 936。
   直接按整图套 460…1680 的话，夹子会压在 12 点数字上（12 点在 y=660）。 */
.wc-board {
  left: 50%; top: 936px; width: 1053px; max-width: none;
  transform: translate(-50%, -50%);
}
.wc-letters, .wc-face, .wc-nums, .wc-discs, .wc-label { position: absolute; inset: 0; }
.wc-svg { position: absolute; inset: 0; width: 1080px; height: 1920px; }
/* 钟面组整体呼吸缩放，原点＝时钟圆心 */
.wc-face { transform-origin: 540px 990px; }
.wc-disc {
  position: absolute; width: 160px; height: 160px; border-radius: 50%;
  background: rgb(91, 69, 44);
}
.wc-num {
  position: absolute; font-family: "Freud", "Source Han Sans CN", sans-serif; font-weight: 700;
  font-size: 150px; line-height: 1; letter-spacing: -0.04em;
  font-feature-settings: "tnum"; color: #f5b116; white-space: nowrap;
}
/* 散落字母：文档原本是 11 张烘好的 PNG（品牌窗贴上的描边字），素材没随文档给过来，
   这里用 text-stroke 还原（原稿是 Jost 700 描的）。
   2026-09-18 老板："英文字的线怎么成这样了"——真因不在这条规则，是上面那几条
   @font-face 被全局替换写坏、Freud 整个没加载，字母掉到系统兜底字上了。
   参数跟装置版保持一字不差，别在这儿调。 */
.wc-letter {
  position: absolute; font-family: "Freud", "Source Han Sans CN", sans-serif; font-weight: 700;
  font-size: 135px; line-height: 1; color: transparent; opacity: 0.8;
  -webkit-text-stroke: 3px #5b452c; white-space: nowrap;
}
.wc-glyph {
  position: absolute; font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-weight: 500; font-size: 48px; line-height: 1; color: #5b452c;
  white-space: nowrap;
}

/* ============================================================
   第一步选定 → 收进「漫游档案」的衔接动画（2026-09-08）
   牛皮纸文件夹照 交互素材/文件夹.md 的 1:1 规格：820×1040 舞台、#bd9868 盖面、
   左侧竖排标签向外伸 54px、前盖相对后盖右下各偏 150px。
   ⚠️ 规格第 1 节强调：**前盖必须排在内页之后**（DOM 顺序即层级，不用 z-index），
   这样卡片尾端才会被盖子压住，"夹住"的感觉全靠这一条。
   ============================================================ */
.fa-overlay {
  position: absolute; inset: 0; z-index: 900; display: none;
  background: #f4f1ea var(--wander-cloth, url("../assets/poster/bg/sunday_afternoon.jpg")) center / cover no-repeat;
  align-items: center; justify-content: center; flex-direction: column;
}
.fa-overlay.on { display: flex; }
/* 2026-09-20 老板"文件夹放大一些"：0.72 → 0.95 →（同日再提）1.06 */
.fa-stage { position: relative; width: 820px; height: 1040px; transform: scale(1.06); }
.fa-stage > * { position: absolute; }
/* 后盖 B 面 */
.fa-back {
  left: 0; top: 0; width: 760px; height: 1000px; border-radius: 10px;
  background: #bd9868; box-shadow: 0 14px 34px rgba(32,31,29,.18);
}
/* 侧边竖排标签：110 宽里有 56 被后盖盖住，只露 54 */
.fa-tab {
  left: -54px; top: 70px; width: 110px; height: 380px;
  border-radius: 10px 0 0 10px; background: #bd9868;
  display: flex; align-items: center; padding-left: 14px; box-sizing: border-box;
}
.fa-tab span {
  writing-mode: vertical-rl; font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 20px; letter-spacing: .22em; color: #4b3a26;
}
/* 内页：被收进去的那张卡落在这里 */
.fa-slot { left: 0; top: 0; width: 760px; height: 1000px; }
/* 收进去的不是一张裸图，而是**一块黑色文件板上贴着那张图**——参考图里
   夹在牛皮纸夹中的就是这种深色卡。#221c14 取自规格书 6.2 节占位卡用的那个色。
   下缘留厚一些（56px），像文件卡底部的标签条。 */
.fa-card {
  position: absolute; left: 79px; top: 60px; width: 600px;
  background: #221c14; padding: 22px 22px 56px; box-sizing: border-box;
  border-radius: 3px;
  filter: drop-shadow(0 8px 16px rgba(32,31,29,.34));
}
/* ⚠️ 必须限高。这张卡是 600 宽、上下 padding 22+56，图片 width:100% 之后高度完全
   由原图比例决定：**竖图**（心情图多数是 941×1672 这种 9:16）算下来 988px，
   卡片总高 1066，而档案袋内页（.fa-slot）只有 1000 高、卡片还从 top:60 起——
   底下要露出去 126px，看着就是"图片戳出了袋子下边缘"（2026-09-10 老板在月夜那款
   看到的就是这个，其实四款的竖图都一样）。
   840 是倒推的：60(top) + 22(padding) + 840 + 56(下缘标签条) = 978 < 1000，
   底边还能被袋口压住一点，像真的插进去了。横图（月夜那几张 2000×1124）高度只有
   312，压根碰不到这个上限，不受影响。 */
.fa-card img { display: block; width: 100%; max-height: 840px; object-fit: cover; }
/* 前盖 A 面：底板 + 内容层，同位同尺寸 */
.fa-front {
  left: 150px; top: 150px; width: 610px; height: 850px; box-sizing: border-box;
  border-radius: 0 10px 10px 0; background: #bd9868;
  border-top: 1px solid rgba(75,58,38,.26);
  border-left: 1px solid rgba(75,58,38,.18);
  box-shadow: -7px 0 16px rgba(32,31,29,.12);
}
.fa-front-in {
  left: 150px; top: 150px; width: 610px; height: 850px; box-sizing: border-box;
  /* 规格给的是 78/58，但相框 479 + 文字组约 243 = 722 已经超过内容高 714，
     space-between 分不出任何间距，图和字是贴着的。上下各收一点腾出空档。 */
  padding: 46px 46px 42px; display: flex; flex-direction: column; justify-content: space-between;
  align-items: center;
}
/* 删掉 Wander Hours / 漫游一刻 之后腾出的地方给相框（2026-09-20）：386×479 → 470×583 */
.fa-frame { position: relative; width: 470px; height: 583px; }
/* 窗口位置＝photo-frame.png 实测的镂空区（跟明信片那处同一组数） */
.fa-frame-win { position: absolute; left: 9.44%; top: 20.35%; width: 79.9%; height: 58.1%; overflow: hidden; }
.fa-frame-win img { display: block; width: 100%; height: 100%; object-fit: cover; }
.fa-frame-img { position: absolute; inset: 0; width: 100%; height: 100%;
  filter: drop-shadow(0 6px 14px rgba(32,31,29,.24)); }
.fa-txt { display: flex; flex-direction: column; align-items: center; gap: 13px; }
.fa-t1 { font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 36px; letter-spacing: .04em;
  line-height: 1; color: #4b3a26; }
.fa-t2 { font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 14px; letter-spacing: .42em;
  padding-left: .42em; color: #4b3a26; }
.fa-rule { width: 76px; height: 1px; background: rgba(75,58,38,.35); }
/* logo.png 本身是**纯白**的（实测不透明区平均色 255,255,255），直接贴在牛皮纸上
   看不见。用它当遮罩填成规格要求的 #4b3a26，跟标题同色。原图 1317×924（比例 1.43），
   规格给宽 210 → 高 147。 */
/* 2026-09-20 老板又把下面那枚 CS 字标删了，只留 COSMIC SPECULATION / 宇宙的猜想。
   原 logo.png 是四条横带（COSMIC / SPECULATION / 宇宙的猜想 / CS），按行方向的
   空白在 y=524 处断开，裁到 528 存成 logo-wordmark.png（1317×528，比例 2.494）。 */
.fa-logo {
  width: 152px; height: 61px;   /* 2026-09-20 老板连说两次"再小一点"：260×104 → 200×80 → 152×61 */
  background-color: #4b3a26;
  -webkit-mask: url("../assets/brand/logo-wordmark.png") center / contain no-repeat;
  mask: url("../assets/brand/logo-wordmark.png") center / contain no-repeat;
}
/* 底部文案：写在一条撕边纸上（沐果素材23，w/h 3.79）。
   最长那句是"我漫游在搭着毛毯的沙发，被记录到了漫游档案里"22 字，实测 765px；
   纸条 900 宽（内容宽 800）刚好一行装下。820 宽时它会折行，"里"掉到第二行。 */
/* 2026-09-20 老板"纸条可以往下移动一些"：26 → 96 →（又提一次）160 */
.fa-caption {
  margin-top: 160px; width: 900px; height: 237px;
  display: flex; align-items: center; justify-content: center;
  padding: 0 50px; box-sizing: border-box;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 1.15rem; letter-spacing: .08em; color: #4b3a26; text-align: center;
  white-space: nowrap;
  opacity: 0; transition: opacity 420ms ease;
  /* z-index:0 建一个层叠上下文，让下面 ::before 的 -1 只沉到文字后面，
     不会穿到整个 overlay 的背景后面去。 */
  position: relative; z-index: 0;
}
/* 纸单独转、字保持水平：这张素材自身的中心线是 -3.25°（右端翘起），
   所以把它顺时针转回 3.25°，纸的走向才和水平的文字平行。 */
.fa-caption::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: url("../assets/poster/note-strip.png") center / 100% 100% no-repeat;
  filter: drop-shadow(0 8px 16px rgba(40,28,14,.2));
  transform: rotate(3.25deg);
}
.fa-overlay.said .fa-caption { opacity: 1; }
/* 收卡：从屏幕上方飞进文件夹并被盖子压住 */
@keyframes faFileIn {
  0%   { transform: translate(120px, -760px) rotate(-9deg) scale(1.04); opacity: 0; }
  22%  { opacity: 1; }
  100% { transform: translate(0, 0) rotate(1deg) scale(1); opacity: 1; }
}
.fa-card.flying { animation: faFileIn 1100ms cubic-bezier(.22,.85,.28,1) both; }
/* 第二步收进去的就是第二步那张卡本身：米白纸 + 花体香型名 + 那整段诗
   （2026-09-08 老板指的是这张，不是线香色的卡）。 */
.fa-card.text-card { background: #f1ece3; padding: 40px 52px 58px; }
.fa-script {
  font-family: "Snell Roundhand", cursive; font-size: 52px; line-height: 1;
  color: #453521; margin-bottom: 30px; transform: rotate(-2deg);
  transform-origin: left center; white-space: nowrap;
}
.fa-lines { display: flex; flex-direction: column; gap: 16px; }
.fa-line {
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-weight: 300;
  font-size: 19px; line-height: 1.62; letter-spacing: .04em;
  color: #33302c; white-space: nowrap;
}


/* ---- 手势指南屏（js/guide.js + index.html 的 #view-guide）----
   2026-09-10 老板定的位置：刷卡 → 等待动画 → 这一屏 → 第一步。

   【原来叠着三张实物素材，已全删】clipboard 板 / Our Services 单据 / 撕边纸
   那一摞是 9/10 上午做的，同天下午老板说"教程下面的素材可以都删了，背景用
   这个就行了"，给的就是这张蓝白条纹布纹。所以现在整屏只铺布纹，三条手势
   直接写在上面。布纹用的是 **assets/poster/bg-stripe.jpg**——跟第一步、第二步
   整屏铺的是同一张（老板发的那张 4844×7157 的原图是同款、只是分辨率高，
   没必要再往包里塞 11MB），四屏背景因此完全连贯。
   写法也跟 #view-customizing 那条一致：布纹在上、香型氛围色垫底，
   布纹万一没加载出来也不会露出空白。 */
#view-guide {
  display: flex; align-items: center; justify-content: center;
  /* 布纹铺底，跟第一步、第二步整屏铺的是同一张 assets/poster/bg-stripe.jpg，
     四屏背景因此连贯。香型氛围色垫在后面，布纹万一没加载出来也不会露白。 */
  background: var(--wander-cloth, url("../assets/poster/bg/sunday_afternoon.jpg")) center / cover no-repeat,
              var(--scent-wash);
}
/* 撕边纸（2026-09-11 老板要求加回来的那一张，三层叠放里只留了它）。
   940 宽是按内容反推的：纸的可用区要装下三行图标+文字，
   高 = 940 × 905/1090 = 780，可用区 ≈ 771 × 554，内容实测约 390 × 550 刚好放下。
   纸再小就要动字号，再大会顶到屏幕上下边。 */
.guide-paper { position: relative; width: 940px;
  filter: drop-shadow(0 16px 30px rgba(32,31,29,.22)); }
.guide-paper > img { display: block; width: 100%; height: auto; }
/* 内容压在纸面上。纸素材**顶部有一截胶带**，内容要让开它，所以 top 从 20% 起；
   左右和底部留 9% 躲开撕边的毛口。 */
.guide-inner {
  position: absolute; left: 9%; right: 9%; top: 20%; bottom: 9%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 28px; color: #3b3229;
}
.gg-title {
  font-family: "Freud", "Source Han Sans CN", sans-serif; font-size: 44px; font-weight: 400;
  letter-spacing: .42em; text-indent: .42em; opacity: .72; margin-bottom: 2px;
}
.gg-rule { width: 128px; height: 1px; background: currentColor; opacity: .28; }
/* 三行**作为一组**居中：给一个统一宽度再 align-self:center。
   不能只写 align-self:center 让每行按自己的宽度居中——三行文字长短不一，
   那样图标的左缘会参差不齐。
   410 = 图标槽 150 + gap 28 + 最宽的一行文字（5 字 × (40px + .1em) ≈ 220）。
   2026-09-11 加回撕边纸之后整体缩了一档——没有纸的时候字号可以放肆，
   现在要塞进纸的可用区（约 771 × 554），图标 190→140、主文案 46→40。
   ⚠️ 算文字宽度要带上 letter-spacing，按 5×38 算会不够、第一行会折。 */
.gg-row { display: flex; align-items: center; gap: 28px; width: 410px; align-self: center; }
/* 三行的图标槽统一宽度，文字左缘才对得齐（挥手那个连箭头和动感线一起、比捏合宽） */
.gg-icon { width: 150px; height: 140px; flex: none;
  display: flex; align-items: center; justify-content: center; }
.gg-icon svg { width: 140px; height: 140px; display: block; }
.gg-txt { font-family: "Freud", "Source Han Sans CN", sans-serif; line-height: 1.4; }
.gg-txt b { display: block; font-weight: 400; font-size: 40px; letter-spacing: .1em; }
.gg-txt span { display: block; font-size: 27px; letter-spacing: .14em; opacity: .62; margin-top: 5px; }
.gg-txt b, .gg-txt span { white-space: nowrap; }

/* 挥手图标是**老板给的细线手绘去背图**（不是画的路径，详见 js/guide.js）。
   拆成两层：wv-hand 是手、wv-deco 是箭头和两道动感线。
   两张图尺寸相同（都按同一个 bbox 导出的 397×380），所以直接绝对定位叠死。 */
.gg-wave { position: relative; display: block; width: 117px; height: 112px; }
.gg-wave img { position: absolute; inset: 0; width: 100%; height: 100%; }
/* 只有手在动，绕**手腕**摆（转轴 75% 92%＝手绘里手腕的位置，量出来的）。
   幅度只有 +6°→-7°：图本身画的已经是"挥动中"的姿态，再摆大就成了甩胳膊。
   箭头和动感线**不动**——整张一起晃的话箭头也跟着摆，往哪边挥就读不出来了。 */
.gg-wave .wv-hand {
  transform-origin: 75% 92%;
  animation: gg-wave-swing 1.9s ease-in-out infinite;
}
@keyframes gg-wave-swing {
  0%, 100% { transform: rotate(6deg); }
  50%      { transform: rotate(-7deg); }
}

/* 捏住不放：合拢之后**保持**住很久再松开——这一屏要教的是"捏住别动"，
   不是旧的 hf-once（合一下就松，那个是给"捏一下即确定"那版画的）。
   合拢期间整只手轻微收一下，像真的在使劲捏住。 */
.anim-pinch-hold .hf-closed { animation: gg-hold 3.2s steps(1, end) infinite; }
@keyframes gg-hold {
  0%, 16%   { opacity: 0; }
  22%, 88%  { opacity: 1; }
  94%, 100% { opacity: 0; }
}
.anim-pinch-hold { animation: gg-hold-squeeze 3.2s ease-in-out infinite; }
@keyframes gg-hold-squeeze {
  0%, 16%   { transform: scale(1); }
  30%, 84%  { transform: scale(.965); }
  94%, 100% { transform: scale(1); }
}
/* ⚠️ 这里原来留着一截删剩的 @keyframes（只剩 `50% { opacity:.9 }` 和一个
   多余的 `}`）。它在装置版里正好落在文件末尾，后面没有东西，所以一直没出事；
   一旦后面再接规则，那个多余的右括号会把紧跟着的第一条规则整条吃掉。
   2026-09-16 分叉时删除。装置版那份也还留着，见交接说明。 */

/* ============================================================
   手机版覆盖（2026-09-16 从装置版分叉出来时新增）
   这一段**必须留在文件末尾**：上面那些隐藏规则是装置版按老板要求关掉的 UI，
   同特异性后写的赢，写在中段会被它们盖回去。
   ============================================================ */

/* ── 开屏：「开启漫游」──────────────────────────────────────
   装置上人把香盒放到感应处就开始了，手机上要有个明确的入口。
   2026-09-16 老板改了四处：往下挪到屏幕下方、圆边、底色再淡一点、
   去掉那圈黑框。现在它是压在片子上的一枚米白色圆角牌，靠后面那层
   模糊和一道极浅的投影浮起来，边界由底色自己收住。
   位置 bottom:240 → 牌子占 y 1560..1680，开屏动画正中间那组素材在
   y≈760..1010，下方留白够，两边不打架。 */
.enter-btn {
  position: absolute; z-index: 5;
  left: 50%; bottom: 240px; transform: translateX(-50%);
  /* 2026-09-18 文案加了「· 秋日特别企划」，牌子跟着加长：420 → 700，
     字号 44 → 40、字距 .3em → .2em，两边各留 77px 余量 */
  width: 700px; height: 120px;
  display: flex; align-items: center; justify-content: center;
  /* 58% 是量出来的：再淡片子的深色帧会透上来把字吃掉，再浓就又像贴了张标签 */
  background: color-mix(in srgb, var(--paper) 58%, transparent);
  border: 0;
  border-radius: 999px;
  backdrop-filter: blur(7px);
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 40px; letter-spacing: 0.2em;
  /* 字距会把整行往右推半格，用等量 text-indent 补回来，字才是真居中 */
  text-indent: 0.2em;
  color: var(--ink);
  box-shadow: 0 12px 34px -24px rgba(26, 26, 26, .5);
  cursor: pointer;
  animation: enterBreath 3.6s ease-in-out infinite;
}
.enter-btn:active {
  transform: translateX(-50%) scale(0.97);
  background: color-mix(in srgb, var(--paper) 76%, transparent);
  animation: none;
}
/* 呼吸放在底色的浓度上：牌子自己一明一暗，轮廓不动 */
@keyframes enterBreath {
  0%, 100% { background: color-mix(in srgb, var(--paper) 58%, transparent); }
  50%      { background: color-mix(in srgb, var(--paper) 72%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .enter-btn { animation: none; }
}

/* ── 选择屏：把翻页的可见标识放回来 ──────────────────────────
   装置版 2026-09-07 关掉了箭头和圆点，因为挥手不需要瞄准任何东西。
   手机上人得先知道「这里可以左右翻」，所以箭头常驻、圆点常驻。
   箭头从 opacity:0 改回实体，并且能点。 */
.caro-arrow {
  opacity: 1;
  pointer-events: auto;
  /* 2026-09-18 老板：手机上太小、容易点偏 → 84→116，箭头本身 38→52 */
  width: 116px; height: 116px;
}
.caro-arrow svg { width: 52px; height: 52px; }
.caro-arrow.left  { left: 10px; }
.caro-arrow.right { right: 10px; }

/* 返回上一步（2026-09-18 老板）：屏幕左上角，跟左右翻页箭头同一枚白圆点。
   .caro-arrow 本身是 top:50% + translateY(-50%) 定在容器竖中，这里要钉在顶上，
   所以 top 和 transform 都得压掉。平时藏着，由 js/state.js 的 syncBackBtn 挂 .on。 */
.back-btn {
  position: absolute; left: 30px; top: 56px; transform: none;
  z-index: 500; display: none;
}
.back-btn.on { display: flex; }
.back-btn:active { transform: scale(0.92); }

/* 圆点：装置上的 9px 是给一米开外看的，手机上按屏幕比例放大一档（2026-09-18 再放大一档） */
.caro-dots { display: flex; margin-top: 26px; gap: 26px; }
.caro-dot  { width: 22px; height: 22px; }

/* ── 选香屏（2026-09-16）──────────────────────────────────────
   四份档案夹摞在一起翻。封面 1:1 照老板给的四张设计稿，颜色是从稿子上
   取的像素：外夹 / 内页 / 字 / 标签舌上的字，四支色写在 js/scent-pick.js
   的 SCENT_FOLDERS 里，每张卡自己挂 CSS 变量。
   版式坐标全部按 1080×1920 的设计分辨率写死，跟后面两步一个规矩。 */
#view-scent {
  position: relative;
  flex-direction: column;
  padding: 0;
  /* 2026-09-17 跟后面几屏统一铺棕白竖条布（老板） */
  background: var(--paper) url("../assets/poster/bg/sunday_afternoon.jpg") center / cover no-repeat;
}
/* 一层极浅的暗角，把摞在中间的那叠托起来 */
#view-scent::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 70% 46% at 50% 44%, transparent 60%, rgba(36, 30, 24, .07) 100%);
}
.sp-lead {
  position: absolute; left: 0; right: 0; top: 140px; text-align: center;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 34px; letter-spacing: 0.25em; text-indent: 0.25em;
  color: color-mix(in srgb, var(--ink) 72%, var(--paper));
}
.sp-viewport { position: absolute; left: 0; right: 0; top: 250px; height: 1180px; }
.sp-strip { position: absolute; inset: 0; }

.sp-card {
  position: absolute; left: 50%; top: 50%;
  width: 660px; height: 980px;
  transform: translate(-50%, -50%);
  transition: transform 420ms cubic-bezier(.22, .61, .36, 1);
  cursor: pointer;
  filter: drop-shadow(0 22px 34px rgba(40, 32, 24, .18));
}
/* 标签舌：上窄下宽的小梯形，四款的左右位置错开（--tab-left），
   摞起来时四个舌全露在外面，一眼看得出后面还有几份 */
.sp-tab {
  position: absolute; top: 0; left: var(--tab-left); width: 190px; height: 62px;
  background: var(--fd);
  clip-path: polygon(7% 0, 93% 0, 100% 100%, 0 100%);
  display: flex; align-items: center; justify-content: center;
}
.sp-tab-text {
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 23px; letter-spacing: 0.18em; text-indent: 0.18em;   /* 2026-09-20 换成中文名，字放大 */
  color: var(--tab-ink);
}
/* ── 让它更像一个文件夹（2026-09-20 老板）──────────────────────────
   原来就是一块纯色圆角方块。真文件夹是一张卡纸对折的，所以补三样：
     ① 左边那道**折脊**——一条窄的明暗渐变，表示对折处；
     ② 右下**开口那边的厚度**——内阴影，越靠开口越深，像两层纸之间的缝；
     ③ 前盖压在内页上那道极浅的高光。
   都是画上去的，不加素材。 */
.sp-body {
  position: absolute; top: 60px; left: 0; width: 660px; height: 920px;
  background: var(--fd); border-radius: 5px 8px 8px 5px;
  box-shadow:
    inset -10px 0 22px -12px rgba(0, 0, 0, .34),
    inset 0 -12px 24px -14px rgba(0, 0, 0, .30);
}
.sp-body::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 26px;
  border-radius: 5px 0 0 5px;
  background: linear-gradient(90deg,
    rgba(0, 0, 0, .16) 0%, rgba(0, 0, 0, .05) 42%,
    rgba(255, 255, 255, .13) 72%, rgba(0, 0, 0, .07) 100%);
  pointer-events: none;
}
.sp-body::after {
  content: ''; position: absolute; left: 38px; top: 37px; right: 0; bottom: 0;
  box-shadow: -1px -1px 0 rgba(255, 255, 255, .16);
  pointer-events: none;
}
/* 内页：往右和往下都齐到夹子边，只在左上角留出夹子那道 L 形边 */
.sp-sheet {
  position: absolute; left: 41px; top: 40px; width: 619px; height: 876px;
  background: var(--sheet); color: var(--sp-ink);
  box-shadow: -1px -1px 2px rgba(0, 0, 0, .06);
}
.sp-row {
  position: absolute; top: 42px; left: 40px; right: 40px;
  display: flex; justify-content: space-between;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 15px; letter-spacing: 0.3em;
  opacity: 0.86;
}
/* 相框：纸框那张 PNG 中间是透空的，照片铺在窗口那块矩形上直接露出来，
   顶上那截胶带压在照片外面。窗口的位置是从 PNG 的 alpha 上量的：
   x 7.89%..92.22%、y 15.57%..88.13%。 */
/* 尺寸跟着照片的比例走：四张产品图底下那条香型名（中文一行 + 英文一行，量出来
   落在 0.844~0.93 那一段）已经在导出时切掉，只切底边，左右一点不动，上面两角的
   CS 和 ELSEWHERE INCENSE 都留着。现在是 800×896、比 0.8929。
   窗口占框的 84.33%×72.56%，反推框 W/H = 0.8929×0.7256÷0.8433 = 0.7683，
   所以 380 宽配 495 高。换图要重新算这个高度。 */
/* 2026-09-20 老板"图片和框都可以放大一些"：380×495 → 470×612（×1.236），
   比例 0.7683 不动（反推见上面那段）。底部那块字跟着让到 top:770。 */
.sp-frame {
  position: absolute; left: 50%; top: 118px;
  width: 470px; height: 612px; transform: translateX(-50%);
}
.sp-photo {
  position: absolute; left: 7.89%; top: 15.57%; width: 84.33%; height: 72.56%;
  object-fit: cover; display: block;
}
.sp-mat { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* 2026-09-18 改版：中文名主（大）、英文名副（小）、底下一行时间戳。
   原来的「Wander Hours / 漫游一刻 / 细线 / COSMIC SPECULATION」整块换掉。 */
/* 2026-09-20：中文名挪到标签舌上了，这儿只剩英文名 + 时间戳（.sp-cn 已删） */
.sp-foot { position: absolute; left: 0; right: 0; top: 770px; text-align: center; }
.sp-en {
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 18px; letter-spacing: 0.24em; text-indent: 0.24em;
  text-transform: uppercase; opacity: 0.72;
}
.sp-stamp {
  margin-top: 20px; font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 16px; letter-spacing: 0.1em; text-indent: 0.1em; opacity: 0.6;
  white-space: nowrap;
}

/* 底部圆点和那张纸条，跟后面两步同一套 */
#view-scent .caro-dots {
  position: absolute; left: 0; right: 0; top: 1500px;
  justify-content: center; margin-top: 0;
}
.sp-hint {
  position: absolute; left: 50%; top: 1590px; transform: translateX(-50%);
  width: 570px; height: 150px;
  background: url("../assets/guide/strip-note.png") center / 100% 100% no-repeat;
  display: flex; align-items: center; justify-content: center;
  padding-top: 22px;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 31px; letter-spacing: 0.1em; text-indent: 0.1em;
  color: #4b3a26; white-space: nowrap;
  filter: drop-shadow(0 3px 7px rgba(32, 31, 29, .2));
}

/* 香型名＝老板本人的手写扫描件，抠成透明 PNG（2026-09-17）。
   四张统一按宽 640 导出，高度各随其字（223 到 320 不等），所以这里只定宽，
   高度交给图自己。纸框下沿那条米白边在框里占 y 88.13%..100%，
   折合 59px；「午后客厅」那个「厅」的竖钩拖得长，会探出纸框落到内页上，
   手写本来就不该被框框住，留着。 */
.sp-name {
  position: absolute; left: 50%; top: 88.2%;
  width: 148px; transform: translateX(-50%);   /* 随相框一起放大（2026-09-20） */
  display: block;
}

/* 压花（2026-09-17 老板给的素材，一款一朵）：向左斜，骑在文案卡片右下角，
   往下伸出卡片、压住右下角那张纸条（#caro-recap.at-mood）。
   纸条 z-index 300 比卡片高，所以卡片里这块只是**隐形定位块**（舞台坐标），
   花本体是 #view-customizing 下的 #mood-bloom-float，由 placeMoodBloom 按
   .mp-bloom-pin 的位置对上。要挪花就改这里的 left/top/width/rotate。
   文案最长那行右缘在 stage x≈627，花盒从 650 起；转过角度后实际花枝离字还有一截，改大角度要截图看。 */
.mp-bloom-wrap {
  left: 655px; top: 780px; width: 230px;   /* 文案卡片右侧那一竖条：照片下沿到卡片下沿之间、骑在纸右边缘上（老板红框 2026-09-17） */
  visibility: hidden; pointer-events: none;
}
.mp-bloom { position: relative; display: block; width: 100%; }
.mp-bloom-pin { position: absolute; left: 50%; top: 0; width: 0; height: 0; }
#mood-bloom-float {
  position: absolute; z-index: 310; pointer-events: none;
  transform: rotate(-16deg); transform-origin: 50% 50%;
  filter: drop-shadow(0 6px 10px rgba(40, 26, 20, .22));
  opacity: 0; visibility: hidden; transition: opacity .35s, visibility 0s .35s;
}
#mood-bloom-float.on { opacity: 1; visibility: visible; transition: opacity .35s; }
/* 午后客厅那朵在默认 -16° 上再顺时针转 30°（老板 2026-09-17） */
#mood-bloom-float[data-scent="sunday_afternoon"] { transform: rotate(14deg); }
/* 阳台的夜那朵在默认 -16° 上顺时针转 60°（老板 2026-09-17） */
#mood-bloom-float[data-scent="balcony_night"] { transform: translate(0, 85px) scale(1.15) rotate(44deg); }  /* 放大一点、往下让花茎接上下面的指引纸条 */
/* 月夜银桂那朵在默认 -16° 上顺时针转 30°（老板 2026-09-17） */
#mood-bloom-float[data-scent="moonlit_osmanthus"] { transform: rotate(14deg); }

/* 围巾（2026-09-17 老板给的素材 + 摆放参考图）：布纹和档案夹之间。
   原图竖放、流苏在下；转 -58° 后从左上斜到右下，流苏伸出屏幕右边。
   坐标是 #view-customizing 的 1080×1920 设计坐标。 */
/* 外面套一层跟整屏一样大的框，超出屏幕边缘的部分裁掉（老板 2026-09-17） */
#caro-scarf-clip { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
#caro-scarf {
  position: absolute; pointer-events: none;
  left: 60px; top: 180px; width: 1120px;
  transform: rotate(-25deg);   /* -55° → -40° → -25°，往下挪 200 再 160、又提回 80、再提 60（老板） */ transform-origin: 50% 50%;
  filter: drop-shadow(0 26px 40px rgba(30, 18, 8, .38));
}
/* 第一步卡片里地点中文名纸条（.ps-strip-note，stage 120,656 300×79）底下压的叶子，
   一款一片（老板 2026-09-17）。在海报舞台里、排在纸条前面，跟着卡片翻。 */
.ps-leaf {
  left: 165px; top: 490px; width: 190px;   /* 往右挪 115，叶尖搭到上面的浅蓝横线卡（老板） */
  transform: rotate(-43deg);   /* -28° 再逆时针 15°（老板） */ transform-origin: 50% 50%;
  filter: drop-shadow(0 6px 10px rgba(30, 18, 8, .35));
  pointer-events: none;
}

/* 2026-09-17 全部屏都铺棕白竖条布之后，深色小圆点和选香屏标题在布上看不见，统一换米白 */
.caro-dot { background: rgba(245, 238, 224, .45); box-shadow: 0 1px 3px rgba(30, 18, 8, .35); }
.caro-dot.on { background: #f5eee0; }
/* 选香屏标题：细宋体压在白条纹上读不出来，垫一张跟底部提示同款的撕边纸 */
.sp-lead {
  left: 50%; right: auto; top: 100px; transform: translateX(-50%) rotate(-1.5deg);
  width: 480px; height: 118px; padding-top: 16px;
  display: flex; align-items: center; justify-content: center;
  background: url("../assets/guide/strip-note.png") center / 100% 100% no-repeat;
  color: #4b3a26; white-space: nowrap;
  filter: drop-shadow(0 3px 7px rgba(32, 31, 29, .2));
}

/* ── 引子屏（2026-09-18 老板，2026-09-20 换素材）──────────────────
   老板："有线的太丑了，换个素材，把字放上面"。现在这张是无横线的活页纸
   （2730×3815，左边一列活页孔），所以：
     · 文字不再需要跟横线对齐，行距按读着舒服定（52px），也不用套两层旋转了；
     · 纸本身是正的，只给 -2° 的轻微手放感——老板嫌上一张"太斜"，别再加大；
     · 活页孔占图宽 0..6.4%，文案块从 13.3% 起，给孔让开一段空白。
   舞台 980×1369 ＝ 素材 1100×1537 等比缩到宽 980。 */
#view-intro {
  position: relative; align-items: center; justify-content: center;
  background: var(--paper) url("../assets/poster/bg/sunday_afternoon.jpg") center / cover no-repeat;
}
.intro-stage {
  position: relative; width: 980px; height: 1369px;
  transform: rotate(-2deg);
  filter: drop-shadow(0 26px 44px rgba(30, 18, 8, .34));
}
.intro-paper { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.intro-lines {
  position: absolute; left: 130px; right: 78px; top: 50%;
  transform: translateY(-50%);
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 30px; line-height: 52px; letter-spacing: .02em;
  color: #3a3228;
}
/* 淡入慢一点（2026-09-20 老板："字出现的太快了"）：单行 1.15s，间隔见 js/intro.js */
.intro-line {
  opacity: 0; transition: opacity 1.15s ease;
  white-space: nowrap;
}
.intro-line.on { opacity: 1; }
.intro-line.blank { opacity: 0 !important; }   /* 空行只占一行的位置 */
.intro-line.title { font-weight: 700; font-size: 38px; letter-spacing: .1em; }
.intro-line.sub   { font-size: 26px; letter-spacing: .34em; opacity: 0; color: #6a5a45; }
.intro-line.sub.on { opacity: 1; }
.intro-line.en    { font-size: 22px; letter-spacing: .01em; color: #6a5a45; }
.intro-line.scents { font-size: 25px; letter-spacing: .06em; color: #6a5a45; }
/* 右下角「点击继续」（2026-09-20）：这一屏不自动跳转了，得有个东西告诉人该点了。
   空心小圆一明一暗地闪，别用实心——实心在这张纸上太像个按钮。 */
.intro-more {
  position: absolute; right: 84px; bottom: 104px;
  display: flex; align-items: center; gap: 14px;
  font-family: "Freud", "Source Han Sans CN", sans-serif;
  font-size: 22px; letter-spacing: .14em; color: #6a5a45;
  opacity: 0; transition: opacity .8s ease; pointer-events: none;
}
.intro-more.on { opacity: 1; }
.intro-dot {
  width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid currentColor;
  animation: introBlink 1.7s ease-in-out infinite;
}
@keyframes introBlink { 0%, 100% { opacity: .22; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .intro-dot { animation: none; opacity: .7; } }

/* 开盒定格（js/unbox.js）：整屏同一块棕白竖条布，盒子居中。
   素材已逆时针转 90°（盒子横放、字是正的）+ 提亮（gamma .68、×1.12、饱和 ×1.12），
   宽 1200、高 763~813；这里铺到宽 960，高度随图。 */
#view-unbox {
  position: relative; align-items: center; justify-content: center;
  background: #6b4a33 url("../assets/poster/bg/sunday_afternoon.jpg") center / cover no-repeat;
}
#unbox-img {
  width: 960px; height: auto;
  filter: drop-shadow(0 30px 44px rgba(30, 18, 8, .45));
  user-select: none; -webkit-user-drag: none; pointer-events: none;
}
