/* ── loop.css ── */
/* loop.css — 单屏、不滚动、场景即首页。
 * 原则:功能尽量做成浮在世界上的东西,不做成占版面的界面。 */

/* hidden 属性靠 UA 的 [hidden]{display:none} 生效,权重只有 (0,1,0),
 * 下面很多类写了 display,同权重下作者样式会赢 → 必须显式压回去。 */
[hidden] { display: none !important; }

* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }

:root {
  /* 色板对齐 petdex.cc（同一个品牌）。实测那边：
       底 #f2ede4 / 主墨 #2c2016 / 次文 #7a6e5a / 纸白 #faf7f2 / 强调 #c4783a
     我们原来的 --ink 是 #453a2e —— 比品牌墨浅一大截，整屏字都发灰，
     这就是「土灰土灰、暗沉」的来源。品牌是**亮底 + 高对比墨**，不是闷棕。 */
  --paper: #f2ede4;
  --paper-2: #e9e1d2;
  --card:   #faf7f2;   /* 纸白：卡片、浮层、底栏 */
  --ink:    #2c2016;
  --ink-2:  #7a6e5a;
  --muted:  #9a8e78;
  --line:   #e0d6c3;
  /* 强调 = 品牌的暖橙。绿色留给三叶草，那是货币的语义色，不是品牌色。 */
  --accent: #c4783a;
  --leaf: #6d9a5e;
  --leaf-d: #547c47;
  --alert: #cf6a4f;
  /* 抽屉/面板的高度。留出大约三分之一的场景 ——
     游戏里的底部面板要让人始终看得见自己在哪。
     70vh 那版只剩一条缝，91% 还留着 10px 边更怪：既不像卡片，也不像整屏。 */
  --sheet-h: 62vh;
  --dock-h: 58px;
  /* 底栏离屏幕边多远。0 = 通栏贴边（原来的样子）。
     给了边距之后底栏就是「浮在场景里的一块」而不是「横切画面的一条」——
     景色从它四周透出来，硬边那道分割线就没了。
     其它元素避让底栏时要算上它，所以抽成变量。 */
  --dock-m: 10px;
  --dock-gap: calc(var(--dock-h) + var(--dock-m) + var(--safe-b));
  --safe-b: env(safe-area-inset-bottom, 0px);

  /* ── 尺度 ──────────────────────────────────────────
     原来圆角用了 20 种（1,2,3,…,20,999）、字号 26 种、阴影 23 处各写各的。
     每个元素都是手调的，所以整体看起来是「拼出来的」而不是一套东西。
     下面这三组是全部可用的档位，新写样式只许从这里取。

     圆角按「这东西有多大」分档，不按好看程度： */
  --r-xs:  5px;    /* 贴纸、照片边、小标记 */
  --r-sm: 10px;    /* 输入框、chip、小按钮 */
  --r-md: 14px;    /* 卡片、面板、大按钮 */
  --r-lg: 20px;    /* 抽屉、整屏纸 */
  --r-pill: 999px;

  /* 字号：1.125 左右的比例，够用又不至于每处都不一样。
     行高跟着字号走，不单独调。 */
  --t-xs:   11px;  /* 角标、眉题 */
  --t-sm:   12.5px;/* 辅助说明 */
  --t-base: 14px;  /* 正文 */
  --t-md:   15.5px;/* 强调正文、主按钮 */
  --t-lg:   17px;  /* 小标题 */
  --t-xl:   21px;  /* 屏标题 */
  --t-2xl:  25px;  /* 大数字、结果页 */

  /* HUD 的材质。走过两版弯路：先是中性深灰玻璃（iOS 语言），
     然后我改成了房间的闷棕木色 —— 方向正好反了。
     品牌（petdex.cc）里**根本没有深色 chrome**：亮纸底 + 高对比墨，
     选中的那一项才是深色药丸。HUD 照这个来。 */
  --hud:      rgba(250, 247, 242, .93);
  --hud-edge: rgba(44, 32, 22, .08);
  --hud-ink:  var(--ink);

  /* 高度：只有三级。浮起来多少由「它离用户多近」决定，不由它多重要决定。 */
  /* 标题用衬线。petdex 的 h1 是 `Lora, Georgia, serif` —— Lora 不含汉字，
     中文实际落到系统宋体。所以这个性格**不用引 web font 就能复制**：
     直接写系统宋，一个字节都不下载。正文仍然是系统 sans，和那边一致。 */
  --font-title: Georgia, "Songti SC", "STSong", "SimSun", serif;

  --e-1: 0 1px 3px rgba(70, 52, 26, .10);                    /* 贴在纸上 */
  --e-2: 0 3px 12px rgba(70, 52, 26, .16);                   /* 卡片、浮层 */
  --e-3: 0 -10px 30px rgba(44, 32, 22, .20);                 /* 抽屉、遮罩之上 */
}

html, body { height: 100%; overflow: hidden; overscroll-behavior: none; }

body {
  background: #211d19;
  color: var(--ink);
  font: 15px/1.6 -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* 开门那一下的遮罩（loop.html #bootCover），屋子装好后 body 加 .home-ready 淡出 */
#bootCover {
  position: fixed; inset: 0; z-index: 90; background: var(--paper);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  color: var(--ink-2); font-size: 14px; letter-spacing: .2em;
  transition: opacity .45s ease, visibility 0s linear .45s;
}
body.home-ready #bootCover { opacity: 0; visibility: hidden; }
#bootCover .bc-dots { display: flex; gap: 8px; }
#bootCover .bc-dots i { width: 8px; height: 8px; border-radius: 50%; background: #c9b48f; animation: bcdot 1.2s ease-in-out infinite; }
#bootCover .bc-dots i:nth-child(2) { animation-delay: .15s; } #bootCover .bc-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes bcdot { 0%, 80%, 100% { opacity: .3; transform: translateY(0); } 40% { opacity: 1; transform: translateY(-4px); } }
@media (prefers-reduced-motion: reduce) { #bootCover .bc-dots i { animation: none; opacity: .7; } }

.app {
  position: relative;
  width: 100%; height: 100dvh; max-width: 520px;
  margin: 0 auto;
  overflow: hidden;
  background: #dfd0ad;
}

/* ── 场景 ── */
#room {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center 42%;
  display: block;
}

/* ── 三叶草药丸 ── */
.clover {
  position: absolute; z-index: 6;
  top: calc(12px + env(safe-area-inset-top, 0px)); right: 12px;
  display: flex; align-items: center; gap: 5px;
  padding: 6px 13px 6px 10px; border: 0; border-radius: var(--r-pill);
  background: var(--hud);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  box-shadow: var(--e-1);
  color: var(--hud-ink); font: inherit; font-size: var(--t-base); font-weight: 700;
  font-variant-numeric: tabular-nums; cursor: pointer;
}
.clover-leaf { font-size: var(--t-md); }
.clover-ready {
  width: 7px; height: 7px; border-radius: 50%; background: #8fd07a;
  animation: breathe 2.2s ease-in-out infinite;
}
@keyframes breathe { 0%,100% { opacity: .45; transform: scale(.85); } 50% { opacity: 1; transform: scale(1.15); } }

/* ── 屋里 ⇄ 院子:门本身就是按钮 ──
   之前是屏幕左上角一颗「🌿 去院子」的悬浮药丸,和场景是两层皮。
   现在热区贴在院子那扇红门 / 屋里那个沙地洞口上,
   只留一圈很轻的暖光和一个小标签,让人知道那儿能点,但不抢戏。 */
.door-spot {
  position: absolute; z-index: 5;
  transform: translate(-50%, -50%);
  padding: 0; border: 0; background: none; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.door-spot .ds-glow {
  position: absolute; inset: -6%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 236, 189, .62), rgba(255, 226, 160, .16) 62%, transparent 78%);
  animation: doorbreathe 3.8s ease-in-out infinite;
}
.door-spot .ds-tag {
  position: absolute; left: 50%; bottom: -9px;
  transform: translateX(-50%);
  padding: 3px 10px; border-radius: var(--r-pill);
  background: var(--hud);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  box-shadow: var(--e-1);
  color: var(--hud-ink);
  font: inherit; font-size: var(--t-sm); font-weight: 600; white-space: nowrap;
  letter-spacing: .3px;
}
.door-spot:active .ds-glow { animation: none; opacity: 1; transform: scale(1.06); }
@keyframes doorbreathe {
  0%, 100% { opacity: .42; transform: scale(.94); }
  50%      { opacity: .92; transform: scale(1.04); }
}
@media (prefers-reduced-motion: reduce) {
  .door-spot .ds-glow { animation: none; opacity: .6; }
}

/* ── 点猫冒出的一句话 ── */
.whisper {
  position: absolute; z-index: 6; left: 50%; bottom: calc(var(--dock-gap) + 22px);
  transform: translateX(-50%);
  max-width: 78%; padding: 9px 17px; border-radius: var(--r-pill);
  background: var(--hud);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  box-shadow: var(--e-2);
  color: var(--hud-ink); font-size: var(--t-base); text-align: center; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  animation: rise .34s ease-out;
}
@keyframes rise { from { opacity: 0; transform: translate(-50%, 9px); } to { opacity: 1; transform: translate(-50%, 0); } }
/* 贴在猫头顶:top/left 由 TF.ui.whisper 算,气泡底边落在那一点上方,尾巴朝下指着猫。
   --tail 是猫和气泡中心的横向差(气泡被夹回屏内时尾巴不跟着跑)。 */
.whisper.at {
  bottom: auto; overflow: visible;
  transform: translate(-50%, calc(-100% - 12px));
  background: var(--card);
  animation: riseAt .3s ease-out;
}
.whisper.at::after {
  content: ""; position: absolute; left: calc(50% + var(--tail, 0px)); bottom: -6px;
  width: 12px; height: 12px; margin-left: -6px;
  background: var(--card); transform: rotate(45deg);
  box-shadow: 3px 3px 5px rgba(70, 52, 26, .10);
}
@keyframes riseAt {
  from { opacity: 0; transform: translate(-50%, calc(-100% - 4px)); }
  to   { opacity: 1; transform: translate(-50%, calc(-100% - 12px)); }
}

/* ── 出门在外 ── */
.away {
  position: absolute; z-index: 5; left: 0; right: 0;
  /* 渐变铺到屏幕最底下，字靠内边距抬到底栏之上。
     原来是 bottom:--dock-gap，底边正好压在底栏顶边上 ——
     渐变在最黑的那一端被切断，看着是一块深色方块顶着底栏。
     底栏是浮在上面的、自带模糊底，让渐变从它下面穿过去才连得上。 */
  bottom: 0;
  display: flex; align-items: flex-end; gap: 12px;
  padding: 52px 16px calc(var(--dock-gap) + 12px);
  background: linear-gradient(to top, rgba(24,20,16,.9), rgba(24,20,16,0));
  pointer-events: none;
}
.away-thumb {
  flex: none; width: 76px; height: 76px; border-radius: var(--r-sm);
  background-size: cover; background-position: center;
  border: 2px solid rgba(255,255,255,.9);
  box-shadow: var(--e-2);
}
.away-txt { flex: 1; min-width: 0; color: #fff; }
.away-txt b { display: block; font-size: var(--t-lg); text-shadow: 0 1px 5px rgba(0,0,0,.55); }
.away-txt span { font-size: var(--t-sm); color: rgba(255,255,255,.78); }

/* ── 悬浮底栏 ──
 * z 必须高于遮罩(8)和抽屉(9):抽屉开着时底栏仍要亮着、可点,才能直接互切面板。 */
/* 浮在场景里的一块，不是横切画面的一条。
   通栏贴边 + 1px 描边 = 一道硬分割线，底栏和世界成了两层皮。
   留边、给圆角、让景色从四周透出来，它就落回世界里了。 */
.dock {
  position: absolute; z-index: 11;
  left: var(--dock-m); right: var(--dock-m);
  bottom: calc(var(--dock-m) + var(--safe-b));
  height: var(--dock-h);
  display: flex;
  background: var(--hud);
  backdrop-filter: blur(16px) saturate(1.1); -webkit-backdrop-filter: blur(16px) saturate(1.1);
  border-radius: var(--r-md);
  box-shadow: 0 4px 18px rgba(44, 32, 22, .16), 0 0 0 1px var(--hud-edge);
}
.dk {
  flex: 1; position: relative; border: 0; background: none; cursor: pointer;
  color: var(--ink-2); font: inherit; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 1px;
  transition: color .15s, transform .12s;
}
.dk:active { transform: scale(.93); }

/* 选中态：一团很浅的暖光，不是深色药丸。
   深色药丸是网页导航的做法（照抄 petdex 那版），放进游戏里就成了四不像。
   这里要的是「这一格亮着」的感觉 —— 暖、轻，不切断底栏。
   原来只有 opacity .82 → 1，几乎看不出来。 */
.dk.on { color: var(--accent); }
.dk.on::before {
  content: ""; position: absolute; z-index: -1;
  left: 6px; right: 6px; top: 6px; bottom: 6px;
  background: rgba(196, 120, 58, .14);
  border-radius: var(--r-sm);
}
.dk.on .dk-t { font-weight: 700; }
.dk-i { font-size: var(--t-xl); line-height: 1; }
/* 画好的图标。和 emoji 占同样的高度,换过去布局不跳。 */
.dk-i.img {
  display: block; width: 26px; height: 24px;
  background-size: contain; background-position: center bottom; background-repeat: no-repeat;
}
.dk-t { font-size: var(--t-xs); letter-spacing: .04em; }
.dot {
  position: absolute; top: 7px; right: 50%; margin-right: -19px;
  width: 7px; height: 7px; border-radius: 50%; background: var(--alert);
  box-shadow: var(--e-1);
}

/* ── 上滑抽屉 ── */
.scrim {
  position: absolute; inset: 0; z-index: 8;
  background: rgba(44, 32, 22, .32);
  animation: fade .2s ease-out;
}
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

/* 抽屉停在底栏之上,底栏始终可点 → 三个面板之间可以直接互切,不用先关再开 */
/* 三种呈现，按任务深度分，不强求统一：
     整页  .sheet.is-full   信箱、足迹 —— 要沉下去读的东西，直接翻到另一页
     抽屉  .sheet           小卖部、菜地 —— 随手翻一翻，场景留三分之一
     弹窗  .panel           行李 —— 一个集中的决定，小而居中
   几何全在这里，各模块的 DOM 一行都不用改（shell 只加一个 full 标志）。 */
.sheet {
  position: absolute; z-index: 9;
  left: var(--dock-m); right: var(--dock-m);
  bottom: calc(var(--dock-gap) + 6px);
  height: var(--sheet-h);
  display: flex; flex-direction: column;
  background: var(--paper);
  border-radius: var(--r-lg);
  box-shadow: 0 6px 26px rgba(44, 32, 22, .22), 0 0 0 1px var(--hud-edge);
  overflow: hidden;
  animation: slideup .26s cubic-bezier(.22,.9,.3,1);
}
@keyframes slideup { from { transform: translateY(100%); } to { transform: translateY(0); } }

/* 整页：信箱和足迹是「翻进去读」的，不是「拉出来看一眼」的。
   盖住底栏也没关系 —— 它自带返回，而且读的时候不该被别的入口分心。 */
.sheet.is-full {
  left: 0; right: 0; top: 0; bottom: 0;
  height: auto; border-radius: 0;
  box-shadow: none;
  animation: pagein .24s cubic-bezier(.22,.9,.3,1);
}
.sheet.is-full .sheet-h {
  padding-top: calc(10px + env(safe-area-inset-top, 0px));
}
.sheet.is-full .sheet-b { padding-bottom: calc(28px + var(--safe-b)); }
/* 整页时那根拖拽条没有意义 —— 它不是拉出来的。 */
.sheet.is-full .grab { display: none; }
@keyframes pagein { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

.sheet-h {
  flex: none; position: relative;
  padding: 8px 52px 12px; text-align: center;
  border-bottom: 1px solid var(--line);
}
/* 拖拽条原来只是装饰。做成真的能拉下去 —— 手指放上去往下拖就收起来,
   这是移动端抽屉的默认预期,没有它就只剩「点叉」一条路。
   热区比看得见的那根横条大得多,不然拖不住。 */
.grab {
  display: block; width: 100%; padding: 6px 0 9px;
  background: none; border: 0; cursor: grab; touch-action: none;
}
.grab::before {
  content: ""; display: block; width: 38px; height: 4px; margin: 0 auto;
  border-radius: var(--r-xs); background: var(--line);
}
.sheet.dragging { animation: none; transition: none; }
.sheet.closing { animation: none; transition: transform .2s ease-in; transform: translateY(110%); }
.sheet-h h2 { font-size: var(--t-md); font-weight: 700; }
.sheet-x {
  position: absolute; right: 10px; top: 12px;
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: var(--paper-2); color: var(--ink-2);
  font-size: var(--t-lg); line-height: 1; cursor: pointer;
}
.sheet-b {
  flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: 14px 16px 24px;
  overscroll-behavior: contain;
}

/* ── 抽屉内通用件 ── */
.muted { color: var(--muted); }
.grp { font-size: var(--t-sm); font-weight: 700; color: var(--muted); letter-spacing: .05em; margin: 18px 0 8px; }
.grp:first-child { margin-top: 0; }

.btn {
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  padding: 7px 13px; border-radius: var(--r-sm); font: inherit; font-size: var(--t-sm); cursor: pointer;
}
.btn:active { transform: scale(.97); }
.btn.on { background: var(--leaf); border-color: var(--leaf-d); color: #fff; }
.btn.off, .btn:disabled { opacity: .42; }
.btn.go {
  display: block; width: 100%; margin-top: 12px; padding: 13px;
  background: var(--leaf); border-color: var(--leaf-d); color: #fff;
  font-weight: 700; font-size: var(--t-md); border-radius: var(--r-sm);
}

.bagcard { background: #fff; border: 1px solid var(--line); border-radius: var(--r-md); padding: 14px 16px; }
.bagrow { display: flex; justify-content: space-between; gap: 12px; padding: 3px 0; font-size: var(--t-base); }
.bagnote { font-size: var(--t-sm); color: var(--muted); margin-top: 9px; }

.item { display: flex; gap: 11px; align-items: center; padding: 11px 2px; border-bottom: 1px solid var(--line); }
.item:last-child { border-bottom: 0; }
.item-e { font-size: var(--t-2xl); flex: none; width: 32px; text-align: center; }
.item-m { flex: 1; min-width: 0; }
.item-n { font-weight: 600; font-size: var(--t-base); }
.item-d { font-size: var(--t-sm); color: var(--muted); }
.item-a { display: flex; gap: 6px; flex: none; }

/* 信箱:大图 feed */

/* ── 信箱：按「一趟」分组 ──
 * 地名由分组标题给一次,不再压在每张图上——一趟四张会重复四次。 */
.trip { margin-bottom: 28px; }
.trip-h { display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 0 2px 9px; margin-bottom: 13px; border-bottom: 1px solid var(--line); }
.trip-h b { font-size: var(--t-lg); }
.trip-h span { font-size: var(--t-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
.ml-new { width: 8px; height: 8px; border-radius: 50%; background: var(--alert); flex: none; }

.mc { margin-bottom: 15px; cursor: pointer; }
.mc-img {
  position: relative; width: 100%; aspect-ratio: 4/3; border-radius: var(--r-md);
  background-size: cover; background-position: center;
  box-shadow: var(--e-2);
}
.mc-place {
  position: absolute; left: 12px; bottom: 10px; color: #fff; font-weight: 700; font-size: var(--t-md);
  text-shadow: 0 1px 6px rgba(0,0,0,.65);
}
.mc-new { position: absolute; top: 10px; right: 10px; width: 9px; height: 9px;
  border-radius: 50%; background: var(--alert); box-shadow: var(--e-1); }
.mc-t { font-size: var(--t-sm); color: var(--muted); margin-top: 6px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

.ml { display: flex; gap: 11px; align-items: center; background: #fff;
  border: 1px solid var(--line); border-radius: var(--r-md); padding: 13px; margin-bottom: 15px; cursor: pointer; }
.ml-e { font-size: var(--t-xl); flex: none; }
.ml-t { flex: 1; min-width: 0; font-size: var(--t-base); }
.ml-t b { display: block; }
.ml-t span { font-size: var(--t-sm); color: var(--muted);
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }

.empty { text-align: center; padding: 44px 20px; }
.empty-e { font-size: 34px; }
.empty p { color: var(--muted); font-size: var(--t-base); margin-top: 10px; }

.dexgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 9px; }
.dx { background: #fff; border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 10px 4px; text-align: center; opacity: .45; }
.dx.got { opacity: 1; }
.dx-e { font-size: var(--t-2xl); line-height: 1.25; }
.dx-e.img { width: 40px; height: 40px; margin: 0 auto; background-size: contain; background-position: center; background-repeat: no-repeat; }
/* 图鉴格子：统一高度,内容垂直居中。
   原来未解锁的格子里多一段提示文字,行高参差,是排版乱的主因。 */
.dx { display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 92px; }
.dx-n { font-size: var(--t-xs); margin-top: 5px; line-height: 1.3; }
/* 未解锁画剪影:看得见轮廓、看不清细节,才有「还差这一件」的收藏感 */
.dx-e.silhouette { filter: brightness(0) saturate(0); opacity: .17; }
.dx.got .dx-e.img { filter: none; opacity: 1; }
.collect-group-head span { font-variant-numeric: tabular-nums; }

.dx-n { font-size: var(--t-xs); margin-top: 3px; }

/* ── 自绘图标 ──
 * 有图用图、没图退回 emoji,两种占位尺寸一致,补图标的过程中布局不会跳。 */
.ico {
  display: inline-block; width: 1.55em; height: 1.55em; vertical-align: -.35em;
  background-size: contain; background-position: center; background-repeat: no-repeat;
}
.ico-emoji { line-height: 1.55em; text-align: center; font-size: .95em; background: none; }
.slot-face .ico { width: 88%; height: 88%; vertical-align: 0; }
.slot.multi .slot-face .ico { width: 46%; height: 46%; }
.own-i-e.ico { width: 34px; height: 34px; margin: 0 auto; display: block; }
.own-i-e.ico-emoji { font-size: var(--t-2xl); line-height: 1.2; }
.item-e .ico { width: 30px; height: 30px; vertical-align: -.2em; }

/* ── 行李桌:整屏仪式 ──
 * 打包是玩家在这个游戏里唯一的杠杆,所以它拿一整屏、有自己的节奏,
 * 而不是和买东西挤在同一个列表里。 */
/* 面板（现在只有「行李」用）和抽屉**长得一模一样**，只是内部结构不同
   （它自带返回键和钉在底部的主按钮）。
   走过两版弯路：原来 inset:0 整屏接管 —— 同一排 tab 点第一个整个盖住、
   点后四个是抽屉，所以「行李跳出来很奇怪」，而且盖住底栏出不来；
   然后我改成 91% 高还留 10px 边 —— 既不像卡片也不像整屏，更怪。
   现在和抽屉同高同宽同圆角：从外面看它就是第五个抽屉。 */
/* 弹窗：装包是一个集中的决定（挑三样，交给它），不是一屏要浏览的东西。
   所以小、居中、有遮罩。走过两版弯路都记在这儿：
     ① inset:0 整屏接管 —— 同一排 tab 点第一个盖住一切，还把底栏一起盖了
     ② 91% 高还留 10px 边 —— 既不像卡片也不像整屏，最怪的那种比例 */
.panel {
  position: absolute; z-index: 12;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: calc(100% - 2 * var(--dock-m)); max-width: 380px;
  max-height: min(74vh, 560px);
  display: flex; flex-direction: column;
  background: var(--paper);
  border-radius: var(--r-lg);
  box-shadow: 0 10px 34px rgba(44, 32, 22, .26), 0 0 0 1px var(--hud-edge);
  overflow: hidden;
  animation: popin .22s cubic-bezier(.22, .9, .3, 1);
}
@keyframes popin {
  from { opacity: 0; transform: translate(-50%, -50%) scale(.94); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

.panel-h {
  flex: none; position: relative; display: flex; align-items: center;
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--line);
}
.panel-h h2 { flex: 1; text-align: center; font-size: var(--t-md); font-weight: 700; }
.panel-back {
  width: 34px; height: 34px; border: 0; border-radius: 50%;
  background: var(--paper-2); color: var(--ink); font-size: var(--t-xl); line-height: 1;
  cursor: pointer; flex: none;
}
.panel-clover { flex: none; min-width: 34px; text-align: right; font-size: var(--t-base); font-weight: 700; }

.panel-b { flex: 1; overflow-y: auto; padding: 20px 16px 8px; overscroll-behavior: contain; }
.panel-f {
  flex: none; padding: 12px 16px calc(14px + var(--safe-b));
  border-top: 1px solid var(--line); background: var(--paper);
}
.panel-note { font-size: var(--t-sm); color: var(--muted); min-height: 1.5em; text-align: center; }
.panel-f .btn.go { margin-top: 8px; }

/* 包 */
/* 底框回来了，但只有一层。原来是 .bag + .bag-flap（翻盖）+ .bag-mouth（包口）
   三层叠出来的「包」，格子在最里面 —— 那是「层级太多」的来源。
   现在一个容器同时装下三个格子和那句后果，它们本来就是一件事：
   「包里现在是什么，会带来什么」。 */
.pack-bag {
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 14px 14px 13px;
  margin: 0 0 12px;
}
.pack-slots {
  display: flex; gap: 10px; justify-content: space-between;
  margin: 0 0 12px;
}
.slot {
  flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 6px;
  border: 0; background: none; font: inherit; cursor: pointer; padding: 0;
}
.slot-face {
  width: 100%; aspect-ratio: 1; max-width: 62px; border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-2xl); line-height: 1;
  /* 底框是米色,空格子要比它更暗一点才看得出是「凹进去的位置」 */
  background: rgba(124,106,78,.07);
  border: 2px dashed var(--line); color: var(--muted);
  transition: background .15s, border-color .15s;
}
.slot.filled .slot-face { border-style: solid; border-color: var(--line); background: #fff; color: var(--ink); }
.slot-tag { font-size: var(--t-xs); color: var(--muted);
  max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.slot.multi .slot-face { font-size: var(--t-xl); letter-spacing: -2px; }

/* 后果那句：一行字，不套框。原来是白底 + 描边的一个独立卡片，
   在弹窗里又多一层。 */
.fore {
  /* 在 .pack-bag 里,外边距交给底框 */
  margin: 0; font-size: var(--t-sm); line-height: 1.75; color: var(--ink-2);
}
.fore-x { color: var(--ink); font-weight: 600; }
.fore-q { color: var(--muted); }
.fore-t { font-size: var(--t-xs); color: var(--muted); letter-spacing: .05em; }
.fore-l { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 7px; }
.fore-c {
  font-size: var(--t-sm); padding: 4px 11px; border-radius: var(--r-pill);
  background: var(--paper-2); border: 1px solid var(--line);
}
.fore-c.on { background: #e7f0e2; border-color: #b6cfa9; color: #3f6c33; }
.fore-x { font-size: var(--t-base); color: var(--ink-2); line-height: 1.8; }
/* 固定两行,每行单行省略 —— 高度不随内容变,下面的格子才不会跳(见 ui-pack.js bagNote) */
.fore-x span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 留白的那句：不剧透会发生什么，只提醒你决定权不在你手里 */
.fore-q { font-size: var(--t-sm); color: var(--muted); margin-top: 8px;
  padding-top: 8px; border-top: 1px dashed var(--line); }

.btn.wide { display: block; width: 100%; margin: 18px 0 4px; padding: 11px;
  font-size: var(--t-base); border-radius: var(--r-sm); background: var(--paper-2); }

/* 你有的东西 */
.own-t { margin: 24px 0 10px; font-size: var(--t-sm); font-weight: 700; color: var(--muted); letter-spacing: .05em; }
.own-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); gap: 9px; }
.own-i {
  position: relative; background: #fff; border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 10px 4px 8px; text-align: center; cursor: pointer; font: inherit;
  transition: transform .1s, border-color .15s;
}
.own-i:active { transform: scale(.94); }
.own-i.in { border-color: var(--leaf); background: #f2f8ef; }
.own-i-e { font-size: var(--t-2xl); line-height: 1.2; }
.own-i-n { font-size: var(--t-xs); margin-top: 2px; }
.own-i-c {
  position: absolute; top: 5px; right: 6px; font-size: var(--t-xs); color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.own-empty { grid-column: 1/-1; text-align: center; color: var(--muted); font-size: var(--t-base); padding: 20px 0; }

/* 飞进包里的那一下 */
.fly {
  position: fixed; z-index: 20; pointer-events: none;
  font-size: var(--t-2xl); line-height: 1;
  transition: transform .42s cubic-bezier(.35,.7,.4,1), opacity .42s ease-in;
}
.fly .ico { display: block; width: 34px; height: 34px; }

/* ── dev ── */
.devbar {
  position: absolute; z-index: 10; left: 0; right: 0;
  bottom: var(--dock-gap);
  display: flex; gap: 5px; padding: 6px 8px;
  background: var(--hud);
}
.mini { flex: 1; border: 1px solid #4b433b; background: #332d27; color: #ddd4c6;
  border-radius: var(--r-xs); padding: 5px 2px; font: inherit; font-size: var(--t-xs); cursor: pointer; }

/* ── 明信片:满屏沉浸 ── */
.modal { position: fixed; inset: 0; z-index: 40; background: rgba(18,15,12,.94);
  display: flex; justify-content: center; }
.modal-in { position: relative; width: 100%; max-width: 520px; }

.pv { position: absolute; inset: 0; overflow: hidden; }
.pv-bg { position: absolute; inset: -34px; background-size: cover; background-position: center;
  filter: blur(30px) brightness(.6); }
.pv-in { position: absolute; inset: 0; display: flex; flex-direction: column; }

/* ── 收到的明信片:满屏沉浸,不要任何框 ──
   这一刻要的是心流。踩过两次:先是图库布局(底部 caption + ‹ › 箭头 + N/M 计数),
   后来我给图包了一层纸卡 —— 框把图挤小了,形式大于内容。
   现在回到满屏:图铺满宽度、完整不裁、上下留模糊背景,文字直接压在渐变上。
   「有形式感的那一份」放到信箱和足迹里去做手账,那儿才需要形式。 */
.pc { position: absolute; inset: 0; display: flex; flex-direction: column;
  animation: pcIn .4s ease-out; }
@keyframes pcIn { from { opacity: 0; } to { opacity: 1; } }
.pc-photo {
  flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center;
  padding: calc(46px + env(safe-area-inset-top, 0px)) 0 0;
}
/* contain 不裁:整张图必须看得全 */
.pc-photo img, .pc-photo .pv-ph {
  display: block; max-width: 100%; max-height: 100%; width: auto; height: auto;
  object-fit: contain;
}
.pc-body {
  flex: none; padding: 46px 20px calc(16px + var(--safe-b));
  background: linear-gradient(to top, rgba(10,8,6,.94) 40%, rgba(10,8,6,0));
  color: rgba(255, 250, 240, .96);
  margin-top: -46px;                       /* 渐变压在图的下缘上,不额外占高 */
}
.pc-arc { font-size: var(--t-xs); color: rgba(255,248,236,.52); letter-spacing: 1.2px; }
.pc-place { margin-top: 4px; font-size: var(--t-xl); font-weight: 700; letter-spacing: .3px; }
.pc-place i { font-style: normal; opacity: .7; font-size: .72em; font-weight: 400; }
.pc-place i::before { content: "·"; opacity: .5; margin: 0 7px; }
/* 归到足迹「地方」的那张:地名能点,去那个地方的页面。和旁边的 i 同一个分量,只多一条虚下划线 */
.pc-spot {
  border: 0; background: none; padding: 0; cursor: pointer;
  font: inherit; font-size: .72em; font-weight: 400; color: inherit; opacity: .85;
  text-decoration: underline dotted; text-underline-offset: 4px;
}
.pc-spot::before { content: "·"; opacity: .5; margin: 0 7px; display: inline-block; text-decoration: none; }
.pc-text { margin: 8px 0 0; font-size: var(--t-base); line-height: 1.85; color: rgba(255,250,240,.92); }
.pc-from { margin-top: 11px; font-size: var(--t-xs); color: rgba(255,248,236,.4); letter-spacing: .5px; }

/* 翻页只留一排小圆点 + 两个极轻的字。
   不回退成 ‹ › 箭头和「1 / 14」—— 那是相册控件,收信的人不数第几张之几。 */
.pc-turn {
  flex: none; display: flex; align-items: center; justify-content: center; gap: 18px;
  padding: 0 20px calc(14px + var(--safe-b));
  background: rgba(10,8,6,.94);
}
.pc-t {
  border: 0; background: none; color: rgba(255,248,236,.5);
  font: inherit; font-size: var(--t-sm); padding: 6px 4px; cursor: pointer;
}
.pc-t:active { color: rgba(255,248,236,.95); }
.pc-t.off { opacity: .18; pointer-events: none; }
/* 最后一张、它已经到家:往下走就是那封归来信,比翻页重一点,但仍是一行字 */
.pc-t.home { color: #f3d9a4; font-weight: 600; }
.pc-dots { display: flex; gap: 6px; }
.pc-dots i {
  width: 5px; height: 5px; border-radius: 50%;
  background: rgba(255,248,236,.28); transition: background .2s, transform .2s;
}
.pc-dots i.on { background: rgba(255,248,236,.9); transform: scale(1.3); }
/* 本阶段不做图：没有真图时用稳定的渐变占位，尺寸和真图一致，将来直接替换 */
.pv-ph {
  width: min(88%, 420px); aspect-ratio: 4/3; border-radius: var(--r-sm);
  display: flex; align-items: flex-end; padding: 16px;
  box-shadow: var(--e-3);
}
.pv-ph span { color: #fff; font-size: var(--t-md); opacity: .82; text-shadow: 0 1px 5px rgba(0,0,0,.5); }
/* 遇见谁那一行,和正文同在暗底上 */
.pv-friend { font-size: var(--t-sm); margin-top: 10px; color: rgba(255,248,236,.62); }
.pv-x {
  position: absolute; z-index: 3; border: 0; cursor: pointer;
  background: rgba(0,0,0,.4); color: #fff;
  top: calc(12px + env(safe-area-inset-top, 0px)); right: 13px;
  width: 36px; height: 36px; border-radius: 50%; font-size: var(--t-xl); line-height: 1;
}
/* .pv-cap / .pv-nav / .pv-count 已删:那套是图库布局(底部 caption + ‹ › 箭头 + 4/4 计数),
   最出戏的东西。现在明信片是实物,见 .pc。 */

/* ── 信箱第一层:时间脉络 ──
   不是一列卡片,是一条走下来的线。左边一条虚线贯穿,每一趟是线上的一个站点。
   参照旅行手帐 DAY1→DAY7 顺着虚线串下来的排版:
   一眼看得出它什么时候去了哪、先后顺序是什么。 */
.tl { position: relative; padding: 6px 2px 14px 30px; }
/* 贯穿的那条虚线 */
.tl::before {
  content: ""; position: absolute; left: 9px; top: 14px; bottom: 22px; width: 0;
  border-left: 2px dashed rgba(150, 124, 84, .42);
}
.tl-stop { position: relative; margin-bottom: 16px; cursor: pointer; }
.tl-stop:last-child { margin-bottom: 0; }
/* 线上的节点 */
.tl-node {
  position: absolute; left: -30px; top: 15px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--paper); border: 2px solid rgba(150, 124, 84, .5);
  display: flex; align-items: center; justify-content: center;
}
.tl-node i { width: 7px; height: 7px; border-radius: 50%; background: rgba(150, 124, 84, .65); }
.tl-stop.has-new .tl-node { border-color: var(--alert); }
.tl-stop.has-new .tl-node i { background: var(--alert); }

.tl-card {
  background: #fdf8ec; border-radius: var(--r-sm); padding: 12px 14px 13px;
  box-shadow: 0 2px 8px rgba(70, 52, 26, .14), inset 0 0 0 1px rgba(150, 124, 84, .18);
  transition: transform .15s ease;
}
.tl-stop:active .tl-card { transform: scale(.985); }
/* 「第 N 趟 · 今天 15:16」做成手帐上那种圆角标签 */
.tl-day {
  display: inline-block; padding: 3px 10px; border-radius: var(--r-pill);
  background: rgba(150, 124, 84, .14); color: var(--ink-2);
  font-size: var(--t-xs); letter-spacing: .3px;
}
.tl-where { margin-top: 8px; display: flex; align-items: baseline; gap: 8px; }
.tl-where b { font-size: var(--t-lg); letter-spacing: .5px; }
.tl-where span { font-size: var(--t-sm); color: var(--ink-2); }
/* 两张小照片露一角,够暗示「这趟有东西可看」 */
.tl-shots { display: flex; align-items: center; gap: 7px; margin-top: 9px; }
.tl-c {
  width: 52px; height: 40px; flex: none; border-radius: var(--r-xs);
  background-size: cover; background-position: center;
  border: 2px solid #fff; box-shadow: var(--e-1);
  transform: rotate(calc((var(--k) - 0.5) * 3deg));
}
.tl-n { font-size: var(--t-xs); color: var(--muted); margin-left: 2px; }
.tl-gifts { display: flex; gap: 6px; margin-top: 9px; padding-top: 9px;
  border-top: 1px dashed rgba(150, 124, 84, .28); }
.tl-g {
  width: 22px; height: 22px; flex: none;
  background-size: contain; background-position: center; background-repeat: no-repeat;
}
.tl-g.e { font-size: var(--t-md); font-style: normal; line-height: 22px; text-align: center; }
.tl-badge {
  position: absolute; right: 10px; top: 10px;
  min-width: 19px; height: 19px; padding: 0 5px; border-radius: var(--r-sm);
  background: var(--alert); color: #fff;
  font: 700 11px/19px sans-serif; font-style: normal; text-align: center;
}

/* 返回目录 */
.jn-back {
  border: 0; background: none; color: var(--ink-2); cursor: pointer;
  font: inherit; font-size: var(--t-sm); padding: 2px 4px 12px; margin-left: -4px;
}
.jn-back:active { color: var(--ink); }

/* ── 信箱第二层:某一趟的手账页 ──
   收信那一刻是心流(满屏、无框);回看是**记录**,记录需要形式感,
   也才有得分享。所以这里和明信片查看器刻意是相反的两套语言。
   照片斜着贴、和纸胶带压角、手写感的标签 —— 参照旅行手帐。 */
.jn-page { margin-bottom: 26px; }
.jn-h {
  display: flex; align-items: baseline; gap: 9px; margin: 0 2px 14px;
  padding-bottom: 7px; border-bottom: 1.5px dashed rgba(120, 98, 66, .32);
}
.jn-h b { font-size: var(--t-md); letter-spacing: .5px; }
.jn-h span { font-size: var(--t-xs); color: var(--muted); }
.jn-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 14px; padding: 4px 2px 8px; }

.jn-photo, .jn-note {
  position: relative; cursor: pointer;
  transform: rotate(var(--tilt, 0deg));
  transition: transform .18s ease;
}
.jn-photo:active, .jn-note:active { transform: rotate(0deg) scale(.98); }

/* 照片:白边 + 一点厚度,像真的相纸贴上去 */
.jn-photo {
  background: #fff; padding: 7px 7px 0; border-radius: var(--r-xs);
  box-shadow: var(--e-2);
}
.jn-img {
  aspect-ratio: 4/3; border-radius: var(--r-xs);
  background-size: cover; background-position: center;
}
.jn-photo figcaption {
  padding: 7px 2px 9px; font-size: var(--t-xs); line-height: 1.5; color: #6b5a44;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

/* 归来信:一张便签,跨两列 */
.jn-note {
  grid-column: 1 / -1;
  background: #fdf6e3; border-radius: var(--r-xs);
  padding: 13px 15px 15px;
  box-shadow: var(--e-2);
}
.jn-note b { display: block; font-size: var(--t-base); margin-bottom: 5px; }
.jn-note span {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font-size: var(--t-sm); line-height: 1.65; color: var(--ink-2);
}

/* 和纸胶带:半透明的一小条,压在角上 */
.jn-tape {
  position: absolute; z-index: 2; width: 46px; height: 17px;
  background: rgba(196, 176, 132, .5);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.25);
}
.jn-tape.t0 { top: -7px; left: 12px; transform: rotate(-7deg); }
.jn-tape.t1 { top: -7px; right: 12px; transform: rotate(6deg); }
.jn-tape.t2 { top: -8px; left: 50%; margin-left: -23px; transform: rotate(2deg); }

.jn-new {
  position: absolute; z-index: 3; right: -5px; top: -5px;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--alert); box-shadow: var(--e-3);
}

/* ── 归来 ── */
.letter { position: absolute; inset: 0; overflow-y: auto; background: var(--paper); }
.letter-hero { position: relative; width: 100%; aspect-ratio: 4/3;
  background-size: cover; background-position: center; }
.letter-hero span { position: absolute; left: 15px; bottom: 12px; color: #fff; font-size: var(--t-sm);
  text-shadow: 0 1px 6px rgba(0,0,0,.7); }
.letter-b { padding: 20px 20px calc(30px + var(--safe-b)); }
.letter-t { font-size: var(--t-xl); font-weight: 700; }
.letter-x { font-size: var(--t-md); line-height: 1.9; margin-top: 11px; color: var(--ink-2); }
.letter-s { margin-top: 22px; padding-top: 17px; border-top: 1px dashed var(--line); }
/* 带回来的东西：一件一段来历，不是一排标签 */
.gifts { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; }
.gift { display: flex; gap: 12px; align-items: flex-start; }
.gift-e { flex: none; width: 42px; height: 42px; border-radius: var(--r-sm);
  background: #fff; border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center; font-size: var(--t-xl); }
.gift-i { flex: none; width: 42px; height: 42px; border-radius: var(--r-sm);
  background-size: cover; background-position: center; border: 1px solid var(--line); }
.gift-t { flex: 1; min-width: 0; }
.gift-t b { display: block; font-size: var(--t-md); }
.gift-t span { display: block; font-size: var(--t-base); line-height: 1.75;
  color: var(--ink-2); margin-top: 2px; }

.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.chip { display: inline-flex; align-items: center; gap: 7px; background: #fff;
  border: 1px solid var(--line); border-radius: var(--r-pill); padding: 6px 14px; font-size: var(--t-base); }
.chip-i { width: 22px; height: 22px; border-radius: var(--r-xs); display: inline-block;
  background-size: cover; background-position: center; }

/* ── toast ── */
/* 提示条。--hud 在换品牌色那一轮从深色变成了 rgba(250,247,242,.93)，
   这里的 color:#fff 没跟着改 —— 白字压在近白底上，等于什么都没显示。
   它自己拿深墨底，不跟 HUD 共用一个变量，以后 HUD 再变也不会又哑掉。 */
.toast {
  position: fixed; z-index: 30; left: 50%;
  bottom: calc(var(--dock-gap) + 18px);
  transform: translateX(-50%);
  background: rgba(44, 32, 22, .92); color: #faf7f2;
  padding: 10px 18px; border-radius: var(--r-pill); font-size: var(--t-base);
  max-width: 86%; text-align: center;
  box-shadow: 0 4px 16px rgba(44, 32, 22, .28);
  animation: rise .3s ease-out;
}
/* 抽屉开着的时候，底部这个位置是抽屉自己的内容（小卖部末尾那个
   「回去装包」就在这儿）。提示条浮到抽屉上沿之上，压在场景上说话。 */
body:has(#sheet:not([hidden]):not(.is-full)) .toast {
  bottom: calc(var(--dock-gap) + 6px + var(--sheet-h) + 12px);
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* 场景气泡：最新进展。之前只有底部一行小字，玩家不点进信箱根本不知道有新消息。 */
/* 主场景里那叠没拆的信 —— 不是一条横幅,是几张摞着的信封,
   坐在场景里而不是压在场景上。原来这里会把正文前 20 字剧透出来,
   拆信就没意义了;现在它只说明「有几封没看」。 */
.bubble {
  position: absolute; z-index: 7; right: 16px;
  top: calc(62px + env(safe-area-inset-top, 0px));
  width: 62px; height: 54px;
  padding: 0; border: 0; background: none;
  font: inherit; color: var(--ink); cursor: pointer;
  animation: bubIn .38s cubic-bezier(.22,.9,.3,1);
  -webkit-tap-highlight-color: transparent;
  filter: drop-shadow(0 4px 10px rgba(40, 30, 18, .38));
}
.bubble:active { transform: scale(.95); }
@keyframes bubIn { from { opacity: 0; transform: translateY(-10px) rotate(-6deg); } to { opacity: 1; transform: none; } }

/* 底下那几张,只露一个边,做出「摞着」的厚度 */
.env-s, .env-top {
  position: absolute; left: 50%; top: 50%;
  width: 46px; height: 33px; margin: -17px 0 0 -23px;
  border-radius: var(--r-xs); border: 1.5px solid #b39a72;
  background: linear-gradient(#fdf6e6, #f2e6cd);
}
.env-s { transform: translate(calc(var(--i) * 3px), calc(var(--i) * -3.5px)) rotate(calc(var(--i) * -3deg)); }
.env-top { animation: envNudge 3.4s ease-in-out infinite; }
/* 信封盖:从两个上角折下来的那条 V */
.env-top::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 62%;
  background: linear-gradient(#f7ecd7, #efe0c2);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  border-bottom: 1.5px solid #b39a72;
}
/* 封口那颗火漆 —— 和拆信弹窗上是同一颗,不是一个通用信封 emoji */
.env-dot {
  position: absolute; z-index: 3; left: 50%; top: 50%;
  width: 24px; height: 24px; margin: -8px 0 0 -12px;
  background-size: contain; background-position: center; background-repeat: no-repeat;
  filter: drop-shadow(0 1px 2px rgba(70, 24, 12, .5));
  animation: envNudge 3.4s ease-in-out infinite;
}
.env-dot.plain {
  background: radial-gradient(circle at 38% 32%, #d4614a, #9e3524 70%);
  border-radius: 48% 52% 46% 54% / 52% 46% 54% 48%;
}
@keyframes envNudge {
  0%, 88%, 100% { transform: none; }
  92% { transform: rotate(-5deg); }
  96% { transform: rotate(4deg); }
}
.bub-n {
  position: absolute; right: -4px; top: -6px; z-index: 2;
  min-width: 19px; height: 19px; border-radius: var(--r-sm);
  background: var(--alert); color: #fff; font-size: var(--t-xs); font-style: normal;
  font-weight: 700; line-height: 19px; text-align: center; padding: 0 5px;
  box-shadow: var(--e-1);
}
@media (prefers-reduced-motion: reduce) { .env-top { animation: none; } }
/* 信封底下的小牌子,和门上「去院子」同一种(.door-spot .ds-tag) */
.bub-l {
  position: absolute; left: 50%; bottom: -14px; z-index: 4;
  transform: translateX(-50%);
  padding: 2px 9px; border-radius: var(--r-pill);
  background: var(--hud); box-shadow: var(--e-1);
  color: var(--hud-ink); font-size: var(--t-xs); font-weight: 600; font-style: normal;
  white-space: nowrap; letter-spacing: .3px; line-height: 1.6;
}
.bub-i { font-size: var(--t-xl); flex: none; }
.bub-t { flex: 1; min-width: 0; line-height: 1.35; }
.bub-t b { display: block; font-size: var(--t-base); }
.bub-t span { display: block; font-size: var(--t-sm); color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bub-n { flex: none; min-width: 20px; height: 20px; border-radius: var(--r-sm);
  background: var(--alert); color: #fff; font-size: var(--t-xs); font-style: normal;
  line-height: 20px; text-align: center; padding: 0 6px; }

/* ── 收到明信片:先看背面,翻过来才是画面 ──
   明信片不装信封。背面有邮票、邮戳、写过字的痕迹 —— 它真的从某地寄来了。
   但**不剧透画面**:一趟的第一张邮戳是「？」,翻过来才知道去了哪。
   期待感来自这里,不是来自一个「拆开」按钮。 */
.cb-wrap {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 22px; padding: 24px;
  perspective: 1400px;
  animation: cbIn .5s cubic-bezier(.22,.9,.3,1);
}
@keyframes cbIn { from { opacity: 0; transform: translateY(22px) rotate(-2deg); } to { opacity: 1; transform: none; } }
.cb-hint { font-size: var(--t-base); color: rgba(240, 232, 216, .82); letter-spacing: 1px; }
/* 卡面是画出来的资产,不是 CSS 拼的矩形和直线 ——
   分隔线、写字横线、地址线、邮票框全在图里(card-back.png,比例 496:321)。
   CSS 只负责把邮票和邮戳摆到图上对应的位置,位置用百分比,跟着卡一起缩放。 */
.cb {
  width: min(320px, 86vw); aspect-ratio: 496 / 321;
  transform-style: preserve-3d;
  transition: transform .5s cubic-bezier(.4, 0, .35, 1);
  cursor: pointer;
  filter: drop-shadow(0 16px 30px rgba(20, 14, 6, .55));
}
.cb-face {
  position: absolute; inset: 0; backface-visibility: hidden;
  background-size: contain; background-position: center; background-repeat: no-repeat;
}
/* 没生成出图时的退路,不至于开天窗 */
.cb-face.plain { background: #fbf3e2; border-radius: var(--r-xs);
  box-shadow: inset 0 0 0 1.5px rgba(150, 124, 84, .45); }
/* 邮票正好贴进图里那个方框 */
.cb-stamp {
  position: absolute; right: 5.5%; top: 8%; width: 15%; height: 22%;
  background-size: contain; background-position: center; background-repeat: no-repeat;
  transform: rotate(2deg);
}
.cb-stamp.box { border: 2px dashed rgba(150,124,84,.5); border-radius: var(--r-xs); }
/* 邮戳压在邮票左边,盖歪一点 */
.cb-mark {
  position: absolute; right: 20%; top: 5%; width: 22%; aspect-ratio: 1;
  background-size: contain; background-position: center; background-repeat: no-repeat;
  opacity: .4; transform: rotate(-13deg);
}
/* 「寄自 ？」是悬念的载体:一趟的第一张不告诉你去了哪,翻过来才知道 */
.cb-post {
  position: absolute; right: 17%; top: 38%;
  padding: 2px 8px; border-radius: var(--r-xs);
  border: 1.5px solid rgba(140, 92, 58, .35);
  color: rgba(130, 86, 54, .66);
  font-size: var(--t-sm); font-weight: 700; letter-spacing: 1.5px;
  transform: rotate(-9deg);
}
.cb-post::before { content: "寄自 "; font-weight: 400; opacity: .7; letter-spacing: 0; }

.cb-tip {
  font-size: var(--t-sm); color: rgba(230, 220, 202, .55); letter-spacing: 1.5px;
  animation: tipFade 2.8s ease-in-out infinite;
}
/* 翻:卡片转过去,同时整体轻轻推远一点,像被拿起来翻面 */
.cb-wrap.flipping .cb { transform: rotateY(-88deg) scale(1.04); }
.cb-wrap.flipping .cb-hint,
.cb-wrap.flipping .cb-tip { opacity: 0; transition: opacity .25s; }
@media (prefers-reduced-motion: reduce) {
  .cb-tip { animation: none; }
  .cb { transition: none; }
}

/* ── 没拆的信(只剩归来信在用) ──
   收信不能等于「一张图直接糊到脸上」。中间要有「你去把它拆开」这个动作,
   信才像信。第一封的邮戳是「？」—— 它去了哪要拆开才知道,那是悬念本身。 */
/* .modal 只有 justify-content,没有 align-items —— 子元素被拉满高之后
   内容就顶在最上面。.pv 用 absolute inset:0 自己撑开,信封这里同样处理。 */
.env {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 22px; padding: 24px;
  animation: envIn .42s cubic-bezier(.22,.9,.3,1);
}
@keyframes envIn { from { opacity: 0; transform: translateY(16px) scale(.94); } to { opacity: 1; transform: none; } }
.env-hint { font-size: var(--t-base); color: rgba(240, 232, 216, .8); letter-spacing: 1px; }

/* 照定稿样板画:干净的奶油纸 + 一条暖褐描边 + 一张贴纸。就这些。
   之前我自己加了红蓝航空条、虚线邮票框、斜向纸纹 —— 样板里一个都没有,
   加上去就成了另一个东西。gameflat 本来也禁纸纹和渐变。 */
.env-paper {
  position: relative; width: 272px; height: 184px;
  border-radius: var(--r-xs); cursor: pointer;
  background: #fbf3e4;
  box-shadow: 0 16px 34px rgba(30, 20, 8, .42), inset 0 0 0 2.5px #8a7355;
  transition: transform .18s ease;
}
.env-paper:active { transform: scale(.985); }
/* 信封盖:两条对角线折下来交在中间,和样板一样只有线,没有色块 */
/* 封盖:那条 V 必须看得清,否则整张就是一块平方纸。
   clip-path 剪出来的边没法描边,所以用一个略大的深色底垫在下面当描边。 */
.env-flap {
  position: absolute; left: 0; right: 0; top: 0; height: 58%;
  transform-origin: top center;
  background: #8a7355;                       /* 这层露出来的部分就是折线 */
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  border-radius: var(--r-xs) 6px 0 0;
  transition: transform .42s cubic-bezier(.5,-0.3,.6,1);
}
.env-flap::before {
  content: ""; position: absolute; inset: 0; bottom: 2.5px;
  background: #fdf7ea;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  border-radius: var(--r-xs) 6px 0 0;
}
/* 邮票用生成图;没有图时整个不出现,不用虚线框占位 —— 占位框最像草稿 */
.env-stamp.img {
  position: absolute; right: 13px; top: 12px; z-index: 3;
  width: 44px; height: 52px;
  background-size: contain; background-position: center; background-repeat: no-repeat;
  transform: rotate(3deg);
  filter: drop-shadow(0 2px 3px rgba(80, 60, 30, .3));
}
.env-stamp:not(.img) { display: none; }
.env-lines { display: none; }

/* 火漆印:压在信封盖的尖上,正好封住封口 —— 真的火漆就是这么封的。
   它自己就是「拆开」这个按钮,底下不再压一个大方块。 */
.env-wax {
  position: absolute; z-index: 4; left: 50%; top: 56%;
  width: 62px; height: 62px; margin: -31px 0 0 -31px;
  background-size: contain; background-position: center; background-repeat: no-repeat;
  filter: drop-shadow(0 3px 5px rgba(60, 20, 10, .45));
  animation: waxPulse 2.8s ease-in-out infinite;
  transition: transform .3s cubic-bezier(.3,-0.6,.7,1.5), opacity .3s;
}
/* 图没生成出来时的退路:一颗手捏形状的蜡 + 两只耳朵 */
.env-wax.plain {
  background: radial-gradient(circle at 38% 32%, #d4614a, #9e3524 70%);
  border-radius: 48% 52% 46% 54% / 52% 46% 54% 48%;
  box-shadow: inset -3px -4px 7px rgba(80,20,10,.5), inset 3px 4px 7px rgba(255,180,160,.28);
}
.env-wax.plain::before, .env-wax.plain::after {
  content: ""; position: absolute; top: 12px; width: 0; height: 0;
  border-left: 9px solid transparent; border-right: 9px solid transparent;
  border-bottom: 13px solid rgba(150, 46, 30, .85);
}
.env-wax.plain::before { left: 10px; transform: rotate(-16deg); }
.env-wax.plain::after { right: 10px; transform: rotate(16deg); }
@keyframes waxPulse {
  0%, 100% { transform: scale(1) rotate(-2deg); }
  50%      { transform: scale(1.06) rotate(2deg); }
}
.env-tip {
  font-size: var(--t-sm); color: rgba(230, 220, 202, .55); letter-spacing: 1.5px;
  animation: tipFade 2.8s ease-in-out infinite;
}
@keyframes tipFade { 0%,100% { opacity: .45; } 50% { opacity: .95; } }

/* 拆开的那一下:火漆崩开弹走,信封盖翻起来 */
.env.opening .env-wax {
  animation: none;
  transform: scale(1.35) rotate(28deg) translate(26px, -18px);
  opacity: 0;
}
.env.opening .env-flap { transform: rotateX(-168deg); }
.env.opening .env-tip { opacity: 0; transition: opacity .2s; }
.env.opening .env-hint { opacity: 0; transition: opacity .3s; }
@media (prefers-reduced-motion: reduce) {
  .env-wax, .env-tip { animation: none; }
}

/* 明信片上的「刚到 / 旅途中 · 第 N 天 / 要走了」,让时间线读得懂 */
.pv-arc {
  font-size: var(--t-xs); letter-spacing: 1.5px; color: rgba(255,255,255,.72);
  margin-bottom: 5px;
}
.pv-place i { font-style: normal; opacity: .8; font-size: .76em; }
.pv-place i::before { content: "·"; opacity: .55; margin: 0 7px; }

/* 带回来的东西：逐件亮出来。「获得」需要一个专门的瞬间。 */
.reveal { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 14px; padding: 24px; }
.rv-head { color: rgba(255,255,255,.86); font-size: var(--t-base); letter-spacing: .1em; }
.rv-list { display: flex; flex-direction: column; gap: 11px; width: 100%; max-width: 340px; }
.rv-card { display: flex; align-items: center; gap: 13px;
  background: var(--paper); border-radius: var(--r-md); padding: 14px 16px;
  box-shadow: var(--e-3);
  opacity: 0; animation: rvIn .5s cubic-bezier(.2,1.2,.35,1) forwards; }
@keyframes rvIn { from { opacity: 0; transform: translateY(16px) scale(.92); }
  to { opacity: 1; transform: none; } }
.rv-i { flex: none; width: 46px; height: 46px; background-size: contain;
  background-position: center; background-repeat: no-repeat; }
.rv-e { flex: none; width: 46px; text-align: center; font-size: 32px; }
.rv-t { flex: 1; min-width: 0; }
.rv-t b { display: block; font-size: var(--t-md); }
.rv-t span { display: block; font-size: var(--t-sm); color: var(--ink-2); line-height: 1.65; margin-top: 3px; }
.rv-ok { max-width: 340px; opacity: 0; animation: rvIn .4s ease-out forwards; }

/* 手绘旅行地图。底图是一整幅真画出来的水墨地图(art-direction/travel-map-web.jpg),
   不是几条 CSS 曲线凑的假手绘。上面只叠去过的地方那几面小旗,没去过的完全不出现。 */
.mp { position: relative; width: 100%; aspect-ratio: 3/2; border-radius: var(--r-sm);
  overflow: hidden; background: #e9dcbe;
  border: 1px solid var(--line);
  box-shadow: inset 0 0 26px rgba(96, 74, 44, .18); }
.mp-bg { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; }
.mp.is-blank .mp-bg { filter: saturate(.55) brightness(1.06); opacity: .5; }

.mp-route-svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.mp-route { fill: none; stroke: #8c5a3c; stroke-width: 1.6;
  stroke-dasharray: 3 3.2; stroke-linecap: round; stroke-linejoin: round;
  opacity: .8; vector-effect: non-scaling-stroke; }

.mp-flag { position: absolute; transform: translate(-50%, -100%);
  display: flex; flex-direction: column; align-items: center;
  filter: drop-shadow(0 2px 3px rgba(70, 50, 26, .38)); }
.mp-pole { width: 2px; height: 22px; background: #55402c; border-radius: var(--r-xs);
  order: 2; margin-top: -1px; }
.mp-cloth { width: 15px; height: 11px; background: var(--mp-c, #4f7f45);
  order: 1; margin-left: 15px;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 34% 50%); border-radius: var(--r-xs); }
.mp-name { order: 3; margin-top: 4px; font-size: var(--t-xs); font-weight: 700;
  color: #3d2f1e; background: rgba(255, 250, 236, .92); padding: 1px 7px;
  border: 1px solid rgba(90, 68, 40, .28);
  border-radius: var(--r-pill); white-space: nowrap; }

.mp-empty { position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; text-align: center; font-size: var(--t-sm); color: #6b5b45;
  line-height: 1.9; background: rgba(248, 243, 230, .55); }

/* ── 标题的性格 ──
   原来所有标题都是系统 sans 加粗，和正文只差个字重，整屏没有层次。
   品牌的标题是衬线（见 --font-title 那条注释）。 */
/* 衬线只给「写出来的东西」：信、明信片、一趟的抬头。
   界面控件（抽屉标题、空状态）保持系统 sans —— 全用衬线就成了另一种风格，
   不是这个游戏。 */
.trip-h b, .pc-head b, .letter-card h3 {
  font-family: var(--font-title);
  font-weight: 600;
  letter-spacing: .01em;
}


/* ── 行李（抽屉）──
   用户定的：和菜地、小卖部一样是抽屉。
   主操作区是「你有的东西」—— 点它才会发生事情，所以它要占主要位置，
   上面那三个格子只是「已经装了什么」的显示。 */
.own-t {
  display: flex; align-items: baseline; gap: 8px;
  font-size: var(--t-sm); font-weight: 700; color: var(--ink-2);
  margin: 0 0 9px;
}
.own-more {
  margin-left: auto; border: 0; background: none; padding: 0;
  color: var(--accent); font: inherit; font-size: var(--t-sm); font-weight: 600;
  cursor: pointer; white-space: nowrap;
}
.own-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(82px, 1fr));
  gap: 8px;
}
.own-empty { font-size: var(--t-sm); color: var(--muted); padding: 10px 0; }

/* 按钮区是固定的一条，不是跟着内容走的一段。
   root 撑满抽屉高度 + footer 靠 margin-top:auto，东西少时它也在底,
   东西多时 sticky 让它浮在滚动内容之上 —— 两种情况下按钮都在同一个位置。 */
/* 行李比菜地、小卖部要装的多一截：底框 + 三个格子 + 后果那几行，
   再按 62vh 开，「你有的东西」只能露出一条边。这一屉单独高一点。 */
.sheet:has([data-sheet-body="pack"]) { height: 74vh; }

/* 只有行李这一屉要「底部定一条」，别的屉照旧。
   padding-bottom 归零 —— 按钮条自己带内边距，再叠一层抽屉的 24px 会多出一截。 */
.sheet-b:has([data-sheet-body="pack"]) { display: flex; flex-direction: column; padding-bottom: 0; }
[data-sheet-body="pack"] { display: flex; flex-direction: column; flex: 1 0 auto; }
/* 底边不再加 --safe-b（10/19）：抽屉浮在底栏上面，Home 条的位置底栏已经让过了，
   这里再让一次，全面屏 iPhone 上按钮条凭空高出 34px，把「你有的东西」压下去。 */
.pack-f {
  position: sticky; bottom: 0; z-index: 1;
  margin: 18px -16px 0; padding: 10px 16px 12px;
  margin-top: auto;
  background: var(--paper);
  border-top: 1px solid var(--line);
}
/* 这一行的高度是写死的：提示时有时无（能出发时只有「交出去之后就不管了」，
   装不够时是「至少装一份吃的」），不占位的话按钮会上下跳。 */
.pack-note {
  font-size: var(--t-sm); color: var(--muted); text-align: center;
  height: 20px; line-height: 20px; margin-bottom: 8px;
}
/* 主按钮：比通用 .btn.go 收一点，抽屉本来就只有 62% 高，
   13px padding + t-md 在这里显得过胖。给死高度，文字居中。 */
.pack-f .btn.go {
  margin-top: 0; padding: 0; height: 46px; line-height: 46px;
  font-size: var(--t-base); border-radius: var(--r-md);
  box-shadow: 0 2px 0 var(--leaf-d);
}
.pack-f .btn.go:active { box-shadow: none; transform: translateY(2px); }
.pack-f .btn.go:disabled { box-shadow: none; }

/* ── ui-pet.css ── */
/* ui-pet.css — 认识宠物这一段。
 *
 * 这一段的设计口径就是 loop.css 开头那句:
 *   「功能尽量做成浮在世界上的东西,不做成占版面的界面。」
 * 所以背景是那个**还空着的家**,内容浮在上面,用游戏自己的抽屉语言
 * (从下方滑上来、上圆角、纸色、投影)。之前整屏米黄 + 一格格表单框,
 * 看着像后台管理页,不像这个产品。
 *
 * 颜色全部取 loop.css 的变量,不另立一套。版心和 .app 一样 520px。
 * 不引入 web font —— 游戏本身就用系统栈。
 */

body:not(.pet-ready) .app { visibility: hidden; }

#pet-onboarding { position: fixed; inset: 0; z-index: 100; background: #211d19; }
#pet-onboarding[hidden], #pet-onboarding [hidden] { display: none !important; }

/* 竖屏列,和游戏同宽 */
.pet-stage {
  position: relative; width: 100%; max-width: 520px; height: 100dvh;
  margin: 0 auto; overflow: hidden; background: #dfd0ad;
}

/* ── 那个还空着的家 ── */
.pet-world { position: absolute; inset: 0; }
.pet-world img {
  width: 100%; height: 100%; object-fit: cover; object-position: center 38%;
  display: block;
}
/* 压一层暖色罩:抽屉上方那截要能看清是个家,又不能跟纸色抢。 */
.pet-world::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(33,29,25,.34) 0%, rgba(33,29,25,.12) 30%, rgba(33,29,25,.5) 100%);
}

/* 右上角回去 */
.pet-stage .pet-x {
  position: absolute; z-index: 3; right: 14px; top: calc(14px + env(safe-area-inset-top, 0px));
  width: 36px; height: 36px; min-height: 0; min-width: 0; box-sizing: border-box; border: 0; border-radius: 50%; padding: 0;
  background: rgba(255, 250, 240, .92); color: #5c4b3a; font: inherit; font-size: 20px; line-height: 36px;
  box-shadow: 0 3px 10px rgba(28, 22, 16, .18); cursor: pointer;
}

/* 抽屉上方那句话,浮在世界里 */
.pet-hello {
  position: absolute; left: 0; right: 0; top: calc(26px + env(safe-area-inset-top, 0px));
  z-index: 2; padding: 0 24px; text-align: center;
  display: flex; flex-direction: column; gap: 5px;
  text-shadow: 0 1px 12px rgba(28, 22, 16, .55);
}
/* 原来 11px + 淡米色 + .9 透明,压在亮墙上几乎看不见(UI-AUDIT #19)。字号提一档、不再透明、加深投影。 */
.pet-hello .pet-eyebrow {
  font-size: var(--t-sm); letter-spacing: .18em; color: #fbf3e2; font-weight: 600;
  text-shadow: 0 1px 3px rgba(28, 22, 16, .6), 0 1px 12px rgba(28, 22, 16, .55);
}
.pet-hello h1 { font-size: var(--t-xl); line-height: 1.4; font-weight: 700; color: #fffaf0; }

/* ── 抽屉 ── */
.pet-sheet {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  max-height: 78dvh; display: flex; flex-direction: column;
  background: var(--paper);
  border-radius: var(--r-lg) 20px 0 0;
  box-shadow: var(--e-3);
  animation: pet-slideup .3s cubic-bezier(.22, .9, .3, 1);
}
@keyframes pet-slideup { from { transform: translateY(14%); opacity: .4; } to { transform: none; opacity: 1; } }
.pet-grab {
  flex: none; width: 38px; height: 4px; border-radius: var(--r-xs);
  background: var(--line); margin: 9px auto 0;
}
.pet-body {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 16px 20px 4px;
  display: flex; flex-direction: column; gap: 15px;
}
/* 底部动作区常驻:主按钮永远够得着,不用滚到底去找。
   不画分割线 —— 加一条就又回到「一格格的界面」了;用一层渐变把
   滚上来的内容托住就够。 */
.pet-foot {
  flex: none; position: relative;
  padding: 12px 20px calc(16px + env(safe-area-inset-bottom, 0px));
  display: flex; flex-direction: column; gap: 8px;
  background: var(--paper);
}
.pet-foot::before {
  content: ""; position: absolute; left: 0; right: 0; top: -18px; height: 18px;
  background: linear-gradient(180deg, rgba(244,239,227,0), var(--paper));
  pointer-events: none;
}

/* 四屏都是抽屉里的一块内容。[hidden] 由上面的 !important 压掉,这里只管布局。 */
#pet-step1, #pet-step2, #pet-result { display: flex; flex-direction: column; gap: 15px; }
#pet-progress { display: flex; flex-direction: column; }

.pet-lead { font-size: var(--t-base); line-height: 1.72; color: var(--ink-2); }
.pet-note { font-size: var(--t-sm); line-height: 1.7; color: var(--muted); }

/* ── 已有的宠物 ── */
#pet-library:empty { display: none; }
/* flex:none 不能省。.pet-body 是纵向 flex,而这一行自己带 overflow-x:auto ——
   带 overflow 的 flex 子项自动最小尺寸是 0,内容一多就被压成只剩 padding。 */
#pet-library { flex: none; display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; }
#pet-library::-webkit-scrollbar { display: none; }
.pet-library-item {
  flex: none; display: flex; align-items: center; gap: 8px;
  padding: 6px 13px 6px 7px; border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--paper-2); color: var(--ink-2);
  font: inherit; font-size: var(--t-sm); cursor: pointer; white-space: nowrap;
}
.pet-library-item img { width: 28px; height: 28px; object-fit: contain; }

/* ── 选照片:整块就是主角,不做成表单控件 ── */
.pet-upload {
  display: grid; place-items: center; min-height: 176px;
  background: var(--paper-2); border: 1.5px dashed var(--line); border-radius: var(--r-md);
  cursor: pointer; text-align: center; padding: 14px; overflow: hidden;
  transition: border-color .18s, background .18s;
}
.pet-upload:hover, .pet-upload:focus-within { border-color: var(--leaf); background: #eee9d7; }
.pet-upload.has-photo { border-style: solid; padding: 8px; }
#pet-upload-text { font-size: var(--t-base); color: var(--ink-2); font-weight: 600; }
#pet-upload-text small { display: block; color: var(--muted); margin-top: 6px; font-size: var(--t-sm); font-weight: 400; }
.pet-upload img { max-height: 232px; max-width: 100%; border-radius: var(--r-sm); object-fit: contain; }
#pet-photo { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* ── 字段:写字条的感觉,不是输入框阵列 ── */
.pet-field { display: flex; flex-direction: column; gap: 5px; }
.pet-field > span { font-size: var(--t-sm); font-weight: 600; color: var(--ink); }
.pet-field > small { font-size: var(--t-sm); color: var(--muted); line-height: 1.62; }
.pet-row { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: end; }

.pet-stage input, .pet-stage select, .pet-stage textarea {
  display: block; width: 100%; font: inherit; font-size: var(--t-base); color: var(--ink);
  background: #fffdf7; border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 11px 12px;
}
.pet-stage select { min-width: 104px; }
.pet-stage textarea { min-height: 78px; resize: vertical; line-height: 1.7; }
.pet-stage input:focus, .pet-stage select:focus, .pet-stage textarea:focus {
  outline: 2px solid var(--leaf); outline-offset: -1px; border-color: var(--leaf);
}

/* ── 按钮 ── */
.pet-stage button {
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 12px 16px;
  background: var(--paper-2); color: var(--ink-2);
  font: inherit; font-size: var(--t-base); cursor: pointer; min-height: 48px;
  transition: transform .12s;
}
.pet-stage button:active { transform: scale(.975); }
.pet-stage button:disabled { opacity: .45; cursor: wait; }
.pet-stage button.pet-primary {
  background: var(--leaf); border-color: var(--leaf-d); color: #fffdf4;
  font-weight: 700; font-size: var(--t-md);
  box-shadow: var(--e-3);
}
.pet-stage button.pet-primary:active { box-shadow: var(--e-3); }
.pet-stage button.pet-quiet {
  border: 0; background: none; color: var(--muted); font-size: var(--t-sm);
  min-height: 34px; padding: 4px;
}
.pet-stage button.pet-quiet:active { transform: none; opacity: .6; }
/* 次级动作并排一行:竖着堆会把抽屉顶掉半屏,正文看起来像被切断。 */
.pet-foot-quiet { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; }
.pet-foot-quiet:has(> button:not([hidden])) { margin-top: 2px; }

/* ── 等待 ── */
/* 等待是这一段的主要体验,不是装饰:身份板 ~50 秒,四套动作要一轮。
   抽屉上方那个空房间一直在,等的时候看着它,比看转圈舒服。 */
#pet-progress { align-items: center; text-align: center; padding-top: 8px; gap: 12px; }
.pet-loading {
  width: 26px; height: 26px; border: 2.5px solid var(--line);
  border-top-color: var(--leaf); border-radius: 50%;
  animation: pet-turn 1.1s linear infinite;
}
@keyframes pet-turn { to { transform: rotate(360deg); } }
#pet-progress h2 { font-size: var(--t-lg); font-weight: 700; }
#pet-progress p { font-size: var(--t-base); line-height: 1.75; color: var(--ink-2); max-width: 32ch; }
.pet-elapsed { font-size: var(--t-sm); color: var(--muted); font-variant-numeric: tabular-nums; text-wrap: pretty; }

/* 备齐动作时,让它本人站在中间,一样样亮起来 */
.pet-becoming { width: 96px; height: 96px; object-fit: contain; }
.pet-chips { display: flex; flex-wrap: wrap; gap: 7px; justify-content: center; }
.pet-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px; border-radius: var(--r-pill); font-size: var(--t-sm);
  background: var(--paper-2); color: var(--muted); border: 1px solid var(--line);
  transition: background .3s, color .3s, border-color .3s;
}
.pet-chip .pet-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--line); }
.pet-chip.is-running { color: var(--ink-2); border-color: var(--leaf); }
.pet-chip.is-running .pet-dot { background: var(--leaf); animation: pet-pulse 1.3s ease-in-out infinite; }
.pet-chip.is-done { background: var(--leaf); border-color: var(--leaf-d); color: #fffdf4; font-weight: 600; }
.pet-chip.is-done .pet-dot { background: #fffdf4; }
.pet-chip.is-failed { border-color: var(--alert); color: var(--alert); }
.pet-chip.is-failed .pet-dot { background: var(--alert); }
@keyframes pet-pulse { 50% { opacity: .25; } }

/* ── 身份板确认 ── */
#pet-result { gap: 14px; }
.pet-board { margin: 0; display: flex; flex-direction: column; gap: 7px; }
.pet-board figcaption { font-size: var(--t-xs); letter-spacing: .16em; color: var(--muted); }
/* 身份板是去背的透明 PNG。垫一层比纸略深的底,黑毛白毛都看得清 ——
   纯白底上白猫会糊,洋红底(抠图用的工作图)又太吵,不该给用户看。 */
.pet-board a { display: block; background: var(--paper-2); border-radius: var(--r-md); padding: 10px; }
.pet-board img { display: block; width: 100%; height: auto; }

#pet-result-name { font-size: var(--t-lg); font-weight: 700; }
.pet-check { font-size: var(--t-base); line-height: 1.75; color: var(--ink-2); }

.pet-comparison { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.pet-comparison figure {
  margin: 0; display: flex; flex-direction: column; gap: 5px;
  background: var(--paper-2); border-radius: var(--r-sm); padding: 8px;
}
.pet-comparison figcaption { font-size: var(--t-xs); color: var(--muted); }
.pet-comparison img { display: block; width: 100%; height: 96px; object-fit: contain; border-radius: var(--r-xs); }

/* 改一处:折叠起来,不跟「就是它」抢。展开才是要改的人。 */
.pet-redo-box { border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--paper-2); overflow: hidden; }
.pet-redo-box > summary {
  list-style: none; cursor: pointer; padding: 12px 14px;
  font-size: var(--t-base); color: var(--ink-2); font-weight: 600;
}
.pet-redo-box > summary::-webkit-details-marker { display: none; }
.pet-redo-box > summary::after { content: " ›"; color: var(--muted); }
.pet-redo-box[open] > summary::after { content: " ⌄"; }
.pet-redo-inner { padding: 0 14px 14px; display: flex; flex-direction: column; gap: 9px; }
.pet-redo-inner textarea { background: #fffdf7; min-height: 62px; }

/* ── 出错 ── */
#pet-error {
  font-size: var(--t-sm); line-height: 1.7; color: #7e3f28;
  background: #f6e3d8; border-radius: var(--r-sm); padding: 11px 13px;
}

/* ── 游戏里的入口按钮 ── */
#personal-pet-button {
  /* z-index 跟 .dock 同级(11),必须低于 .panel(12)。
     原来是 12,和面板同级、靠 DOM 顺序压在上面,位置又正好是
     .panel-back 那个返回键(14,10) —— 于是进了任何子页面都点不到返回，
     点下去反而跳到宠物页。面板是全屏纸,本来就该把它一起盖住。 */
  position: absolute; z-index: 11;
  top: calc(12px + env(safe-area-inset-top, 0px)); left: 14px;
  padding: 7px 14px; border: 1px solid rgba(222, 210, 187, .6); border-radius: var(--r-pill);
  background: rgba(255, 253, 244, .86);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  color: var(--ink-2); font: inherit; font-size: var(--t-sm);
  max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 整屏抽屉(信箱、足迹)z-index 是 9,比它低 —— 打开时名牌浮在标题栏上(UI-AUDIT #12)。
   整屏的纸本来就该把场景上的东西一起盖住。 */
body:has(#sheet.is-full:not([hidden])) #personal-pet-button { display: none; }

/* ── 旅行图还没画好时,明信片里的占位 ── */
.pet-image-status {
  padding: 22px; text-align: center; color: #e7dcc6; font-size: var(--t-base);
  display: flex; flex-direction: column; align-items: center; gap: 12px;
}
.pet-image-status button {
  border: 1px solid var(--line); background: var(--paper-2); color: var(--ink-2);
  border-radius: var(--r-sm); padding: 10px 16px; min-height: 44px; font: inherit; font-size: var(--t-sm);
}

@media (max-height: 700px) {
  .pet-sheet { max-height: 84dvh; }
  .pet-hello h1 { font-size: var(--t-lg); }
  .pet-upload { min-height: 140px; }
}
@media (prefers-reduced-motion: reduce) {
  .pet-sheet { animation: none; }
  .pet-loading, .pet-chip.is-running .pet-dot { animation: none; }
  .pet-stage button:active { transform: none; }
}

/* ── 账号 ──
   安静一点:这一条是保险,不是主角。主角是「给它一张照片」。 */
.pet-account{flex:none;margin:0 0 14px}
.pet-account-line{margin:0;font-size: var(--t-sm);line-height:1.6;color:#8a7f72}
/* 要压过 .pet-stage button(0,1,1),否则「我还没有账号」「先不管」被画成两个灰按钮 */
.pet-linkish, .pet-stage button.pet-linkish{border:0;background:none;padding:4px 0;font:inherit;color:#b4653a;
  text-decoration:underline;text-underline-offset:2px;cursor:pointer}
.pet-linkish:hover{color:#8f4a26}
.pet-auth{flex:none;margin:0 0 16px;padding:14px;border:1px solid #e3d8c9;border-radius: var(--r-sm);background:#fbf7f0}
.pet-auth-lead{margin:0 0 12px;font-size: var(--t-sm);line-height:1.6;color:#6f6459}
.pet-auth-error{margin:10px 0 0;font-size: var(--t-sm);color:#b03c2e}
/* 用户名、密码原来并排挤在一行(.pet-row 是给「名字 + 按钮」那种两栏用的),
   三个按钮也挤一行,切到注册时「先不管」被挤到第二行(UI-AUDIT #13)。
   现在:两个框上下排;提交按钮独占一行;两个次要链接在下面一行左右分开。 */
.pet-auth .pet-row{grid-template-columns:1fr;gap:10px}
.pet-auth input{width:100%}
.pet-auth-actions{display:flex;align-items:center;justify-content:space-between;gap:10px 14px;margin-top:14px;flex-wrap:wrap}
.pet-auth-actions button[type=submit]{flex:1 0 100%;padding:10px 16px;border:0;border-radius: var(--r-pill);
  background:#b4653a;color:#fff;font:inherit;font-weight:600;cursor:pointer}
.pet-auth-actions button[type=submit]:disabled{opacity:.55;cursor:default}


/* ── 选谁去旅行 ──
   第一屏只做这一件事，所以它就是一组卡片，没有别的语言混进来。
   纸感沿用抽屉那套（纸色、细描边、圆角），不引入新的视觉。 */
#pet-choose { display: flex; flex-direction: column; gap: 13px; }
#pet-choose .pet-lead { font-size: var(--t-md); font-weight: 700; color: var(--ink); }

.pet-cards {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;
}
.pet-card {
  position: relative; display: flex; flex-direction: column;
  align-items: center; gap: 4px; text-align: center;
  padding: 14px 10px 13px !important;
  border: 1px solid var(--line) !important; border-radius: var(--r-md) !important;
  background: #fffdf7 !important; color: var(--ink) !important;
  min-height: 0 !important;
}
/* 「画一只你自己的」是还没发生的事，用虚线和淡一点的纸区分开 —— 
   但字号和布局保持一致，它仍然是一条并列的路。 */
.pet-card.is-new {
  border-style: dashed !important; background: var(--paper-2) !important;
}
.pet-card-face {
  width: 62px; height: 62px; display: grid; place-items: center;
  border-radius: 50%; background: var(--paper-2);
  font-size: var(--t-2xl); color: var(--muted); overflow: hidden;
}
.pet-card.is-new .pet-card-face { background: #fffdf7; }
.pet-card-face img { width: 100%; height: 100%; object-fit: contain; }
.pet-card b { font-size: var(--t-base); font-weight: 700; line-height: 1.4; }
.pet-card small {
  font-size: var(--t-xs); line-height: 1.55; color: var(--muted);
  font-weight: 400; text-wrap: balance;
}
/* 「免费」不是装饰：它是这个产品的核心设计（案例猫免费，自定义付费）。 */
.pet-card-tag {
  position: absolute; top: 8px; right: 8px;
  font-style: normal; font-size: var(--t-xs); font-weight: 700; letter-spacing: .04em;
  padding: 2px 7px; border-radius: var(--r-pill);
  background: rgba(109, 154, 94, .16); color: #4e6f41;
}

/* 账号那一条是次要动作：不抢「谁去旅行？」的位置，也不长得像主按钮。 */
.pet-account {
  margin-top: 4px; padding-top: 13px;
  border-top: 1px solid var(--line);
  font-size: var(--t-sm); color: var(--muted); line-height: 1.7;
}
.pet-account button {
  min-height: 0 !important; padding: 0 !important;
  border: 0 !important; background: none !important;
  color: var(--leaf-d) !important; font-size: var(--t-sm) !important;
  text-decoration: underline; text-underline-offset: 3px;
}

/* 标题跟着品牌走：衬线。 */
/* 只有开场那句大标题用衬线 —— 那是品牌的一个瞬间。
   卡片名、进度标题都是界面标签，保持系统 sans。 */
.pet-hello h1 {
  font-family: var(--font-title);
  font-weight: 600;
}
.pet-hello h1 { letter-spacing: .02em; }

/* ── ui-wash.css ── */
/* ui-wash.css — 底栏、信箱、点开一封（沉浸）、足迹（地图 / 一个地方 / 经历 / 收集）
 *
 * 照 10/15 暖色版概念图：docs/project/evidence/UI-CONCEPT-20261015-warm.html（用户：「就按照这个版本改造吧」）。
 * 底色是偏黄的纸（原游戏 paper #f2ede4 再偏一点黄），卡片奶油色，投影带一点暖棕；
 * 不用粗深描边，水彩晕染只留在小标签上，不铺整页。字号照 C 水彩绘本那一套。
 * 只管上面这几处；行李、菜地、小卖部还是 loop.css 原来的样子（没出过示意图，先不动）。
 * 排在 loop.css 后面加载，同名的规则以这里为准。
 */

:root {
  --w-bg: #f4ecdc;
  --w-card: #fcf7ee;
  --w-ink2: #7a6a52;
  --w-muted: #a3916f;
  --w-hair: #eadfcb;
  --w-sage: #4f7d64;
  --w-sage-btn: #6f9d83;
  --w-new: #e9967c;
  --w-sh: 0 6px 20px rgba(110, 78, 36, .10);
  --w-sh2: 0 3px 10px rgba(110, 78, 36, .12);
  --w-safe-t: env(safe-area-inset-top, 0px);
  /* 水彩晕染：中间浓、边上化开，只给小标签用 */
  --w-sage-w: radial-gradient(closest-side, rgba(168, 210, 180, .75), rgba(168, 210, 180, .18));
  --w-sky-w: radial-gradient(closest-side, rgba(181, 219, 232, .85), rgba(181, 219, 232, .2));
  --w-peach-w: radial-gradient(closest-side, rgba(246, 199, 158, .75), rgba(246, 199, 158, .2));
  --w-butter-w: radial-gradient(closest-side, rgba(245, 227, 166, .85), rgba(245, 227, 166, .2));
}

/* ── 底栏：奶油色的一块，选中的那格底下晕开一团浅绿 ── */
.dock { background: rgba(252, 247, 238, .97); border-radius: 22px; box-shadow: 0 6px 22px rgba(110, 78, 36, .14); }
.dk.on { color: var(--w-sage); }
.dk.on::before {
  left: 4px; right: 4px; top: 0; bottom: 0; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(168, 210, 180, .75), rgba(168, 210, 180, 0));
}
.dot { background: var(--w-new); box-shadow: none; }

/* ── 信箱、足迹这两页：纸色的底，抬头不压线 ── */
.sheet.is-full[data-mod="mail"], .sheet.is-full[data-mod="collect"] { background: var(--w-bg); }
.sheet.is-full[data-mod="mail"] .sheet-h, .sheet.is-full[data-mod="collect"] .sheet-h { border-bottom: 0; padding-bottom: 6px; background: var(--w-bg); }
.sheet.is-full[data-mod="mail"] .sheet-h h2, .sheet.is-full[data-mod="collect"] .sheet-h h2 {
  font-size: 19px; font-weight: 600; letter-spacing: .1em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sheet.is-full[data-mod="mail"] .sheet-x, .sheet.is-full[data-mod="collect"] .sheet-x { background: var(--w-card); box-shadow: var(--w-sh2); }
/* 子页面的「‹ 信箱 / ‹ 足迹」：借外壳抬头的左边 */
.sh-back {
  position: absolute; left: 10px; top: calc(12px + var(--w-safe-t)); height: 32px; padding: 0 6px;
  border: 0; background: none; cursor: pointer; font: inherit; font-size: 14px; color: var(--w-ink2);
}
/* 底栏浮在整页上面，最后一行要能滚到它上面来；电脑上不露那条灰滚动条 */
.sheet.is-full[data-mod="mail"] .sheet-b, .sheet.is-full[data-mod="collect"] .sheet-b {
  padding-bottom: calc(var(--dock-gap) + 20px); scrollbar-width: none;
}
.sheet.is-full[data-mod="mail"] .sheet-b::-webkit-scrollbar, .sheet.is-full[data-mod="collect"] .sheet-b::-webkit-scrollbar { display: none; }

/* ── ① 信箱：一封封往下读 ── */
.ml-h { display: flex; justify-content: space-between; align-items: flex-end; gap: 10px; margin: 2px 2px 14px; }
.ml-h b { display: block; font-size: 17px; }
.ml-h span { display: block; font-size: 12.5px; color: var(--w-ink2); }
.ml-out {
  flex: none; font-style: normal; font-size: 12.5px; font-weight: 600; white-space: nowrap;
  color: var(--w-sage); padding: 2px 12px; border-radius: 99px; background: var(--w-sage-w);
}
.ml-card { position: relative; background: var(--w-card); border-radius: 20px; box-shadow: var(--w-sh); overflow: hidden; margin-bottom: 16px; }
.ml-pic {
  position: relative; display: block; width: 100%; aspect-ratio: 3 / 2; padding: 0; border: 0; cursor: pointer;
  background-color: #efe5d3; background-size: cover; background-position: center;
}
.ml-new {
  position: absolute; left: 12px; top: 12px; text-decoration: none;
  font-size: 11.5px; font-weight: 600; color: #fff; background: var(--w-new);
  padding: 1px 9px; border-radius: 99px; box-shadow: 0 2px 6px rgba(233, 150, 124, .35);
}
.ml-b { padding: 12px 16px 16px; }
.ml-w { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; font-size: 12.5px; color: var(--w-muted); }
.ml-w b { min-width: 0; font-size: 14px; font-weight: 600; color: var(--ink); }
.ml-w span { flex: none; }
.ml-card p { margin: 6px 0 0; font-size: 16px; line-height: 1.85; }
.ml-card.is-letter .ml-w b { font-size: 16px; letter-spacing: .06em; }
/* 归来信：信纸色、左边一张封口贴纸，不放照片（照片就是上面那封明信片） */
.ml-card.is-letter { display: flex; align-items: flex-start; gap: 4px; background: #fbf5e8; box-shadow: var(--w-sh), inset 0 0 0 1.5px #ece0c8; }
.ml-card.is-letter .ml-b { flex: 1; min-width: 0; padding-left: 4px; }
.ml-lt { position: relative; flex: none; width: 64px; height: 64px; margin: 14px 0 0 14px; padding: 0; border: 0; background: none; cursor: pointer; }
.ml-lt .ml-new { left: auto; right: -6px; top: -6px; }
.ml-seal { display: block; width: 100%; height: 100%; background: center / contain no-repeat; filter: drop-shadow(0 3px 6px rgba(90, 60, 25, .18)); }
.ml-seal.plain { border-radius: 50%; background: #e9967c; }
.wh-spot { border: 0; background: none; padding: 0; cursor: pointer; font: inherit; font-weight: 600; color: var(--w-sage); }
.ml-acts { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.ml-go, .fm-back {
  border: 0; cursor: pointer; font: inherit; font-size: 14px; font-weight: 600; color: #fff;
  padding: 9px 20px; border-radius: 99px; background: var(--w-sage-btn); box-shadow: 0 6px 16px rgba(79, 125, 100, .28);
}
.ml-none { font-size: 13px; color: var(--w-muted); }
.ml-clover { font-size: 12.5px; padding: 3px 12px; border-radius: 99px; background: var(--w-sage-w); }
.ml-sec { font-size: 13px; font-weight: 600; color: var(--w-ink2); margin: 26px 2px 10px; }
.ml-rows { background: var(--w-card); border-radius: 20px; box-shadow: var(--w-sh); padding: 4px 14px; }
.ml-row {
  display: flex; align-items: center; gap: 12px; width: 100%; padding: 11px 0;
  border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.ml-row + .ml-row { border-top: 1px solid var(--w-hair); }
.ml-row i { flex: none; width: 58px; height: 58px; border-radius: 14px; background-size: cover; background-position: center; background-color: #efe5d3; }
.ml-row span { flex: 1; min-width: 0; }
.ml-row b { display: block; font-size: 14.5px; }
.ml-row em { display: block; font-style: normal; font-size: 12.5px; color: var(--w-ink2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ml-row time { flex: none; font-size: 12px; color: var(--w-muted); }

/* ── ④ 点开一封：沉浸 ──
   整屏是这张图放大后的虚影，清楚的那张铺满宽、整张看得全；字写在下面的暗处 */
.iv { position: absolute; inset: 0; overflow: hidden; background: #1d1813; display: flex; flex-direction: column; animation: pcIn .35s ease-out; }
.iv-bg { position: absolute; inset: -50px; background-size: cover; background-position: center; filter: blur(30px) brightness(.58) saturate(1.1); }
.iv-top {
  position: relative; z-index: 2; flex: none; height: calc(56px + var(--w-safe-t)); padding-top: var(--w-safe-t);
  display: flex; align-items: center; justify-content: center;
  color: rgba(255, 250, 240, .88); font-size: 14px; font-weight: 600; letter-spacing: .08em;
}
.iv-x {
  position: absolute; right: 14px; top: calc(11px + var(--w-safe-t)); width: 34px; height: 34px;
  border: 0; border-radius: 50%; background: rgba(0, 0, 0, .3); color: #fff; font-size: 18px; line-height: 1; cursor: pointer;
}
.iv-mid { position: relative; z-index: 1; flex: 1; min-height: 0; display: flex; flex-direction: column; justify-content: center; overflow-y: auto; scrollbar-width: none; }
.iv-mid::-webkit-scrollbar { display: none; }
.iv-pic { flex: none; }
.iv-pic img, .iv-ph { display: block; width: 100%; height: auto; box-shadow: 0 16px 44px rgba(0, 0, 0, .4); }
.iv-ph { aspect-ratio: 3 / 2; }
.iv-txt { flex: none; padding: 24px 24px 12px; }
.iv-w { display: flex; align-items: baseline; gap: 8px; color: rgba(255, 248, 236, .6); font-size: 12.5px; }
.iv-w b { font-size: 22px; font-weight: 700; color: #fffaf0; letter-spacing: .02em; }
.iv-w span { font-size: 15px; color: rgba(255, 250, 240, .88); }
.iv-w span::before { content: "·"; opacity: .45; margin-right: 8px; }
.iv-w em { margin-left: auto; font-style: normal; white-space: nowrap; }
.iv .wh-spot { color: rgba(255, 250, 240, .9); font-weight: 500; text-decoration: underline dotted; text-underline-offset: 5px; }
.iv-txt p { margin: 12px 0 0; font-size: 17px; line-height: 1.95; color: rgba(255, 250, 240, .95); }
.iv-txt p.iv-friend { font-size: 13px; color: rgba(255, 248, 236, .7); }
.iv-txt p.iv-none { font-size: 13.5px; color: rgba(255, 248, 236, .6); }
.iv-go {
  margin-top: 16px; border: 0; border-radius: 99px; padding: 10px 22px; cursor: pointer;
  background: rgba(255, 250, 240, .92); color: #2c2016; font: inherit; font-weight: 600; font-size: 14px;
}
.iv-nav {
  position: relative; z-index: 2; flex: none; display: flex; justify-content: space-between; align-items: center;
  padding: 12px 30px calc(24px + var(--safe-b));
}
.iv-t { border: 0; background: none; color: rgba(255, 248, 236, .62); font: inherit; font-size: 13.5px; padding: 6px 2px; cursor: pointer; }
.iv-t.off { opacity: .25; pointer-events: none; }
.iv-t.home { color: #f3d9a4; font-weight: 600; }
.iv-dots { display: flex; gap: 7px; }
.iv-dots i { width: 6px; height: 6px; border-radius: 50%; background: rgba(255, 248, 236, .3); }
.iv-dots i.on { background: rgba(255, 248, 236, .95); transform: scale(1.35); }

/* ── 收信的那几步：明信片背面、归来信的信封、带回来的东西亮出来 ──
   屋子压暗、但看得见：信是寄到这个家里来的（10/19 用户：「背景变成全黄的了」，
   10/15 那版换成了不透明的纸色底，家整个看不见了）。提示字浅色；卡面、信封、贴纸都是画好的图，不动 */
.modal { background: rgba(33, 27, 21, .82); }
.cb-hint, .env-hint, .rv-head { color: rgba(255, 248, 236, .95); text-shadow: 0 1px 8px rgba(0, 0, 0, .45); }
.cb-tip, .env-tip { color: rgba(255, 248, 236, .62); }
.cb { filter: drop-shadow(0 14px 28px rgba(0, 0, 0, .35)); }
.env-paper { box-shadow: 0 14px 30px rgba(0, 0, 0, .3), inset 0 0 0 2.5px #8a7355; }
/* 带回来的东西亮出来：9/04 那版（用户 10/19 选的）—— 更暗的底、纸色卡片、方角绿按钮，用 loop.css 原来那套，这里不再覆盖 */
.modal:has(.reveal) { background: rgba(18, 15, 12, .94); }
/* 点开一张明信片：9/04 的字号（正文 14.5、出处 11.5），loop.css 后来换成了变量 14 / 11 */
.pc-text { font-size: 14.5px; }
.pc-from { font-size: 11.5px; }

/* ── 足迹的三页签：选中的那个底下晕开一团浅桃色 ── */
.ft-tabs { display: flex; justify-content: center; gap: 18px; margin: -4px 0 12px; }
.ft-tabs button { border: 0; background: none; cursor: pointer; font: inherit; font-size: 14.5px; font-weight: 600; color: var(--w-muted); padding: 3px 10px; }
.ft-tabs button.on { color: var(--ink); background: radial-gradient(closest-side, rgba(246, 199, 158, .75), rgba(246, 199, 158, 0)); }

/* ── ⑤ 地图 ──
   地图从最顶上铺下来，「足迹」和 × 浮在地图上；页签是浮在地图上的药丸；下面一个地方一张卡 */
.sheet.is-full[data-mod="collect"]:has(.fm) .sheet-h { position: absolute; z-index: 6; left: 0; right: 0; top: 0; background: transparent; }
.sheet.is-full[data-mod="collect"]:has(.fm) .sheet-b { padding-top: 0; padding-left: 0; padding-right: 0; }
.fm { position: relative; }
.fm-map { position: relative; height: clamp(380px, 60vh, 560px); overflow: hidden; background: var(--w-bg); }
/* 上沿化进纸色托住标题，下沿化进下面的卡片 */
.fm-map::after {
  content: ""; position: absolute; z-index: 2; inset: 0; pointer-events: none;
  background: linear-gradient(rgba(244, 236, 220, .9), rgba(244, 236, 220, 0) 20%, rgba(244, 236, 220, 0) 84%, var(--w-bg));
}
/* 能拖：底图 + 路线一层，图钉一层（压在渐变上面），两层一起平移。
   中国这屏手指按在地图上就是拖，不让页面跟着上下滚；全世界那屏还是原生横滑。 */
.fm:not(.is-world) .fm-map { touch-action: none; cursor: grab; }
.fm-map.is-drag { cursor: grabbing; }
.fm-pan { position: absolute; inset: 0; will-change: transform; }
.fm-pan.pins { z-index: 3; pointer-events: none; }
.fm-pan.pins .fm-pin { pointer-events: auto; }
.fm-w, .fm-cn { position: absolute; display: block; max-width: none; pointer-events: none; -webkit-user-drag: none; user-select: none; }
/* 中国这张高清图的四边化进底下的世界地图，看不出接缝 */
.fm-cn {
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 46px, #000 calc(100% - 30px), transparent), linear-gradient(to right, transparent, #000 30px, #000 calc(100% - 30px), transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to bottom, transparent, #000 46px, #000 calc(100% - 30px), transparent), linear-gradient(to right, transparent, #000 30px, #000 calc(100% - 30px), transparent);
  mask-composite: intersect;
}
.fm-route { position: absolute; z-index: 1; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.fm-route path { fill: none; stroke: #c9784a; stroke-width: 2px; stroke-dasharray: 6 6; stroke-linecap: round; opacity: .8; }
.ft-tabs.pill {
  position: absolute; z-index: 5; left: 50%; top: calc(52px + var(--w-safe-t)); transform: translateX(-50%);
  margin: 0; gap: 4px; padding: 3px 6px; border-radius: 99px; white-space: nowrap;
  background: rgba(252, 247, 238, .94); box-shadow: var(--w-sh2);
}
.ft-tabs.pill button { font-size: 13.5px; padding: 3px 12px; }
/* 图钉：一个点落在真地方，照片立在点上方（角上是去过几趟），地名在点下方 */
.fm-pin { position: absolute; z-index: 3; width: 0; height: 0; padding: 0; border: 0; background: none; cursor: pointer; font: inherit; color: var(--ink); }
.fm-pin .dot { position: absolute; left: -5px; top: -5px; width: 10px; height: 10px; border-radius: 50%; background: #cf8f66; border: 2px solid #fff; box-shadow: var(--w-sh2); }
.fm-pin .pf {
  position: absolute; left: -27px; bottom: 12px; width: 54px; height: 54px; padding: 3px;
  background: var(--w-card); border-radius: 15px; box-shadow: 0 4px 12px rgba(44, 32, 22, .22);
}
.fm-pin .pf i { display: block; width: 100%; height: 100%; border-radius: 12px; background-size: cover; background-position: center; }
.fm-pin .pf::after { content: ""; position: absolute; left: 50%; bottom: -7px; margin-left: -7px; border: 7px solid transparent; border-bottom: 0; border-top-color: var(--w-card); }
.fm-pin u {
  position: absolute; right: -8px; top: -8px; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 99px;
  background: var(--ink); color: #fff; font-size: 11px; font-weight: 700; line-height: 20px; text-align: center; text-decoration: none;
}
.fm-pin em {
  position: absolute; left: 0; top: 9px; transform: translateX(-50%);
  font-style: normal; font-size: 12px; font-weight: 600; white-space: nowrap;
  background: rgba(252, 247, 238, .96); padding: 1px 10px; border-radius: 99px; box-shadow: var(--w-sh2);
}
.fm-pin em.hr { color: var(--w-sage); }
/* 它现在在这儿：地名旁挂它的头像 */
.fm-pin em .av {
  display: inline-block; width: 22px; height: 22px; margin: -3px 5px -6px -8px; border-radius: 50%;
  border: 2px solid #fff; background: #fff3d6 center/cover no-repeat; box-shadow: 0 0 0 3px rgba(168, 210, 180, .7);
  font-style: normal; font-size: 11px; line-height: 18px; text-align: center; vertical-align: 0;
}
/* 左下角的小世界图：框出现在看的是哪一块，点它拉远 */
.fm-mini {
  position: absolute; z-index: 4; left: 14px; bottom: 34px; padding: 4px 4px 2px; cursor: pointer;
  border: 0; border-radius: 12px; background: var(--w-card); box-shadow: var(--w-sh2); font: inherit;
}
.fm-mini i { position: relative; display: block; width: 96px; height: 44.6px; border-radius: 8px; overflow: hidden; background-size: cover; background-position: center; }
.fm-mini u { position: absolute; border: 1.5px solid #c9784a; border-radius: 2px; background: rgba(201, 120, 74, .2); }
.fm-mini em { display: block; font-style: normal; font-size: 11px; font-weight: 600; color: var(--w-ink2); line-height: 1.5; }
/* ⑤b 全世界：横着能拖，中国那块虚线框出来 */
.fw-scroll { position: absolute; inset: 0; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; overscroll-behavior-x: contain; }
.fw-scroll::-webkit-scrollbar { display: none; }
.fw-canvas { position: relative; }
.fw-canvas img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; -webkit-user-drag: none; user-select: none; }
.fm.is-world .fm-map { cursor: grab; }
.fw-cn { position: absolute; z-index: 1; padding: 0; cursor: pointer; border: 2px dashed rgba(201, 120, 74, .85); border-radius: 12px; background: rgba(255, 236, 205, .16); }
.fw-pin { position: absolute; z-index: 3; width: 13px; height: 13px; margin: -6.5px 0 0 -6.5px; border-radius: 50%; background: #cf8f66; border: 2px solid #fff; box-shadow: var(--w-sh2); }
.fw-pin.here { width: 22px; height: 22px; margin: -11px 0 0 -11px; background-color: #fff3d6; background-size: cover; background-position: center; box-shadow: 0 0 0 4px rgba(168, 210, 180, .7), var(--w-sh2); }
.fm-list { position: relative; z-index: 5; margin-top: -6px; padding: 0 16px; }
.fm-pl {
  display: flex; gap: 12px; align-items: center; width: 100%; margin-bottom: 12px; padding: 10px;
  border: 0; border-radius: 20px; background: var(--w-card); box-shadow: var(--w-sh);
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.fm-pl > i:first-child { flex: none; width: 76px; height: 76px; border-radius: 14px; background-size: cover; background-position: center; }
.fm-pl span { flex: 1; min-width: 0; }
.fm-pl b { display: block; font-size: 16px; }
.fm-pl em { display: block; font-style: normal; font-size: 12.5px; color: var(--w-ink2); }
.fm-pl s { display: block; text-decoration: none; font-size: 13px; margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fm-pl .go { flex: none; font-style: normal; color: #c9bca8; font-size: 18px; padding-right: 4px; }
.fm-wl { background: var(--w-card); border-radius: 20px; box-shadow: var(--w-sh); padding: 14px 16px; }
.fm-wl b { display: block; font-size: 16px; }
.fm-wl span { display: block; font-size: 12.5px; color: var(--w-ink2); margin: 2px 0 12px; }
.fm-back { font-size: 13px; padding: 6px 16px; }
.fm-empty { text-align: center; color: var(--w-ink2); font-size: 13px; line-height: 1.9; margin: 18px 0; }

/* ── ⑥⑦ 一个地方 ── */
.pp-sum { font-size: 13px; color: var(--w-ink2); margin: -6px 2px 14px; text-align: center; }
.pp-trip { background: var(--w-card); border-radius: 20px; box-shadow: var(--w-sh); padding: 14px 14px 12px; margin-bottom: 14px; }
.pp-th { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.pp-th b { font-size: 15.5px; }
.pp-th span { font-size: 12.5px; color: var(--w-muted); white-space: nowrap; }
.pp-out { font-size: 12.5px; font-weight: 600; color: var(--w-sage); margin-top: 1px; }
.pp-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 12px 0 10px; }
.pp-grid button { aspect-ratio: 1; padding: 0; border: 0; border-radius: 14px; background-size: cover; background-position: center; cursor: pointer; }
.pp-nt { position: relative; padding-left: 13px; font-size: 14px; line-height: 1.8; }
.pp-nt::before { content: ""; position: absolute; left: 1px; top: .78em; width: 5px; height: 5px; border-radius: 50%; background: #a8d2b4; }
.pp-spot { display: flex; gap: 10px; align-items: flex-start; background: #f1e6d2; border-radius: 16px; padding: 10px 12px; margin: 10px 0 2px; }
.pp-spot b { flex: none; font-size: 13.5px; }
.pp-spot span { font-size: 12.5px; color: var(--w-ink2); line-height: 1.6; }
.pp-mo { display: flex; gap: 12px; align-items: center; width: 100%; margin-top: 10px; padding: 0; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.pp-mo > i { flex: none; width: 84px; height: 56px; border-radius: 12px; background-size: cover; background-position: center; }
.pp-mo span { min-width: 0; }
.pp-mo span > em:first-child { display: block; font-style: normal; font-size: 12px; color: var(--w-muted); }
.pp-mo b { font-size: 14px; font-weight: 500; }
.pp-bring { display: inline-block; margin-top: 10px; font-size: 12.5px; font-weight: 600; color: #a7643f; background: var(--w-peach-w); padding: 3px 14px; border-radius: 99px; }
.pp-none { margin-top: 8px; font-size: 12.5px; color: var(--w-muted); }
/* 学会 / 第一次 / 吃过：一团小晕染当标签 */
.wt { display: inline-block; font-style: normal; font-size: 11px; font-weight: 600; line-height: 1.6; padding: 0 7px; border-radius: 99px; margin-left: 6px; vertical-align: 1px; color: #5c4b3a; }
.wt.l { background: var(--w-peach-w); }
.wt.f { background: var(--w-sky-w); }
.wt.e { background: var(--w-butter-w); }
.wt.m { background: #ece4ea; }

/* ── ⑧ 经历：每一样都是那张信的照片 ── */
.fx-me { display: flex; align-items: center; gap: 12px; margin: 0 2px 14px; }
.fx-av {
  flex: none; width: 54px; height: 54px; border-radius: 50%; background: #fff3d6 center/cover no-repeat; box-shadow: var(--w-sh2);
  font-style: normal; font-weight: 700; font-size: 20px; line-height: 54px; text-align: center; color: var(--w-ink2);
}
.fx-me b { display: block; font-size: 17px; }
.fx-me span { font-size: 12.5px; color: var(--w-ink2); }
.fx-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 6px; }
.fx-stats span { text-align: center; border-radius: 16px; padding: 9px 0 7px; font-size: 12px; color: var(--w-ink2); }
.fx-stats b { display: block; font-size: 20px; color: var(--ink); line-height: 1.2; }
.fx-stats .a { background: #f9e3cf; } .fx-stats .b { background: #e2ecec; } .fx-stats .c { background: #f6e8bf; } .fx-stats .d { background: #ece4ea; }
.fx-sec { font-size: 13px; font-weight: 600; color: var(--w-ink2); margin: 24px 2px 10px; }
.fx-tile { display: block; padding: 0; border: 0; border-radius: 18px; overflow: hidden; background: var(--w-card); box-shadow: var(--w-sh); font: inherit; color: inherit; text-align: left; cursor: pointer; }
.fx-tile > i { display: block; aspect-ratio: 4 / 3; background-size: cover; background-position: center; }
.fx-tile span { display: block; padding: 8px 11px 10px; }
.fx-tile b { display: block; font-size: 14px; }
.fx-tile em { font-style: normal; font-size: 12px; color: var(--w-muted); }
.fx-duo { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.fx-strip { display: flex; gap: 10px; overflow-x: auto; scrollbar-width: none; margin: 0 -16px; padding: 2px 16px 8px; }
.fx-strip::-webkit-scrollbar { display: none; }
.fx-strip .fx-tile { flex: none; width: 128px; }
.fx-strip .fx-tile > i { aspect-ratio: 1; }
.fx-none { margin: 4px 2px 0; font-size: 13px; color: var(--w-muted); }
.fx-empty { background: rgba(252, 247, 238, .6); border-radius: 18px; padding: 14px; font-size: 13px; color: var(--w-muted); text-align: center; }

/* ── ⑨ 收集：上面看、下面选（10/16 用户选的 B）──
   页签 + 展示位贴在上面不动，下面一个地方一行小格子往下滑；地方再多也只是多几行 */
/* 抽屉正文四周有留白（上 14、左右 16），贴住的这块要把留白也盖上，不然滑下去的格子会从页签上面露出来 */
.kb-fix { position: sticky; top: -14px; z-index: 3; margin: -14px -16px 0; padding: 14px 16px 8px; background: var(--w-bg); }
.kb-show { display: flex; gap: 14px; align-items: flex-start; min-height: 124px; background: var(--w-card); border-radius: 22px; box-shadow: var(--w-sh); padding: 14px; }
.kb-pl {
  flex: none; display: flex; align-items: center; justify-content: center; width: 96px; height: 96px; border-radius: 28px;
  background: radial-gradient(circle at 50% 42%, #fffaf1 0, #f8ecd8 60%, #ecd9b9 100%); box-shadow: 0 8px 18px rgba(110, 78, 36, .18), 0 0 0 5px var(--w-card);
}
.kb-pl.ph { background-size: cover; background-position: center; background-repeat: no-repeat; }
.kb-pl u { display: block; width: 74px; height: 74px; background-size: contain; background-position: center; background-repeat: no-repeat; text-decoration: none; }
.kb-pl u.e { font-size: 44px; line-height: 74px; text-align: center; }
.kb-pl.q { background: #f3e9d6; box-shadow: 0 0 0 5px var(--w-card); }
.kb-pl.q::before { content: "?"; font: 700 40px/1 Georgia, "Songti SC", serif; color: #cdb48c; }
.kb-tx { flex: 1; min-width: 0; }
.kb-tx b { display: block; font-size: 18px; letter-spacing: .06em; }
.kb-tx b.q { color: var(--w-ink2); letter-spacing: .16em; }
.kb-tx em { display: block; font-style: normal; font-size: 11.5px; color: var(--w-muted); }
.kb-tx p { margin: 6px 0 0; font-size: 13px; line-height: 1.7; }
.kb-go { margin-top: 4px; padding: 0; border: 0; background: none; cursor: pointer; font: inherit; font-size: 12.5px; font-weight: 600; color: var(--w-sage); }
.kb-row { margin-top: 10px; }
.kb-row.off { opacity: .6; }
.kb-h { display: flex; justify-content: space-between; align-items: baseline; margin: 0 4px 6px; }
.kb-h b { font-size: 13px; color: var(--w-ink2); }
.kb-h em { font-style: normal; font-size: 12px; font-weight: 600; color: var(--w-muted); }
.kb-g { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 5px; }
.kb-c {
  position: relative; display: flex; align-items: center; justify-content: center; aspect-ratio: 1; padding: 0; border: 0; border-radius: 11px; cursor: pointer; font: inherit;
  background: radial-gradient(circle at 50% 42%, #fffaf1 0, #f8ecd8 62%, #efdfc4 100%); box-shadow: 0 2px 6px rgba(110, 78, 36, .13);
}
.kb-c.ph { background-size: cover; background-position: center; background-repeat: no-repeat; }
.kb-c u { display: block; width: 76%; height: 76%; background-size: contain; background-position: center; background-repeat: no-repeat; text-decoration: none; }
.kb-c u.e { width: auto; height: auto; font-size: 20px; line-height: 1; }
.kb-c.q { background: #f3e9d6; box-shadow: none; }
.kb-c.q::before { content: "?"; font: 700 13px/1 Georgia, "Songti SC", serif; color: #cdb48c; }
.kb-c.sel { box-shadow: 0 0 0 2.5px #6f9d83, 0 3px 8px rgba(79, 125, 100, .25); }
