/* ============================================================
   苏格拉底-夏 · 个人空间 —— 视觉系统
   风格：iOS 液态玻璃 / 流体光带 / 胶片颗粒
   设计原则：
   1. 玻璃要有物理感（高光边缘 + 跟随光标的镜面扫光）
   2. 只在一处用力：入场（照片流动墙）是全站唯一的"炫技"，其余安静
   3. 内容即主角：照片与作品被陈列，装饰让路
   ============================================================ */

:root{
  --ink: #EDF2FF;              /* 晨雾白 · 底色 */
  --ink-2: #FFFFFF;
  --text: #101B36;
  --text-2: rgba(22,36,66,.68);
  --text-3: rgba(22,36,66,.45);

  --aqua: #10B98C;             /* 薄荷绿 · 主色 */
  --aqua-bright: #45E0B5;      /* 亮薄荷（渐变 / 光斑用） */
  --iris: #6C5CE7;             /* 鸢尾紫 · 过渡 */
  --coral: #FF6B4A;            /* 珊瑚 · 温度 */
  --amber: #F0A400;            /* 琥珀 · 点缀 */

  --edge: rgba(255,255,255,.85);
  --edge-strong: rgba(255,255,255,.98);

  --r-lg: 28px; --r-md: 20px; --r-sm: 14px;
  --blur: 26px;

  --font-sans: -apple-system, BlinkMacSystemFont, "PingFang SC", "HarmonyOS Sans SC", "MiSans", "Source Han Sans SC", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", "JetBrains Mono", Consolas, "Courier New", monospace;
  --font-serif: "Songti SC", "STSong", "Source Han Serif SC", "Noto Serif SC", Georgia, "SimSun", serif;

  --ease-out: cubic-bezier(.22,1,.36,1);
  --ease-spring: cubic-bezier(.22,1.2,.36,1);

  --page-x: clamp(18px, 4vw, 48px);
  --dock-space: 56px;   /* 原来给底部 Dock 留的 132px；Dock 已换成左上角返回按钮，收回多余留白 */
}

*,*::before,*::after{ box-sizing: border-box; }
html{
  -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scrollbar-gutter: stable;
  /* 禁止 iOS/安卓的下拉刷新与橡皮筋回弹：
     手机上放大看照片再缩回去时，很容易把"缩放回弹"误判成下拉，
     触发整页刷新（等于重新进站，体验极差）。 */
  overscroll-behavior-y: none;
}
body{
  margin: 0;
  background: var(--ink);
  color: var(--text);
  /* manipulation = 允许滚动与双指缩放，但禁用双击放大和下拉刷新 */
  touch-action: manipulation;
  overscroll-behavior-y: none;
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  min-height: 100vh;
}
/* 浮层打开时锁滚：iOS Safari 光 overflow:hidden 挡不住橡皮筋滚动，
   还要把 body 定位固定（配合 JS 记录/恢复 scrollY）。 */
html.lock{ overflow: hidden; height: 100%; }
body.lock{ overflow: hidden; position: fixed; left: 0; right: 0; width: 100%; }
/* 笔记本/桌面滚轮在浮层里也不该带动背景 */
.overlay{ overscroll-behavior: contain; }
img{ max-width: 100%; display: block; }
button{ font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
a{ color: var(--aqua); text-decoration: none; }
a:hover{ text-decoration: underline; text-underline-offset: 3px; }
[hidden]{ display: none !important; }
::selection{ background: rgba(69,224,181,.4); }
:focus-visible{ outline: 2px solid var(--aqua); outline-offset: 3px; border-radius: 6px; }
.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
.skip-link{ position:fixed; top:-60px; left:16px; z-index:200; padding:10px 16px; border-radius:999px; background:var(--ink-2); border:1px solid var(--edge); box-shadow:0 10px 30px -14px rgba(31,47,92,.4); transition:top .3s; }
.skip-link:focus{ top:16px; }

::-webkit-scrollbar{ width: 10px; height: 10px; }
::-webkit-scrollbar-thumb{ background: rgba(22,36,66,.18); border-radius: 99px; border: 2px solid var(--ink); }
::-webkit-scrollbar-track{ background: transparent; }

/* ---------- 背景：流彩光斑 ---------- */
.aurora{ position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
  background:
    radial-gradient(130% 90% at 50% -20%, rgba(108,92,231,.16), transparent 60%),
    radial-gradient(100% 70% at 88% 110%, rgba(255,107,74,.14), transparent 60%),
    linear-gradient(180deg, #F2F6FF, #E9F0FF 55%, #EAF7F2);
}
.aurora__blob{ position: absolute; border-radius: 50%; filter: blur(60px); will-change: transform; }
.b1{ width: 62vmax; height: 62vmax; left: -16vmax; top: -18vmax; opacity: .9;
  background: radial-gradient(circle at 35% 35%, rgba(69,224,181,.62), transparent 62%);
  animation: drift1 26s ease-in-out infinite alternate; }
.b2{ width: 56vmax; height: 56vmax; right: -14vmax; top: 4vmax; opacity: .85;
  background: radial-gradient(circle at 60% 40%, rgba(108,92,231,.55), transparent 62%);
  animation: drift2 32s ease-in-out infinite alternate; }
.b3{ width: 52vmax; height: 52vmax; left: 12vmax; bottom: -24vmax; opacity: .75;
  background: radial-gradient(circle at 50% 50%, rgba(255,107,74,.5), transparent 64%);
  animation: drift3 38s ease-in-out infinite alternate; }
@keyframes drift1{ from{ transform: translate3d(0,0,0) scale(1); } to{ transform: translate3d(10vmax,7vmax,0) scale(1.16); } }
@keyframes drift2{ from{ transform: translate3d(0,0,0) scale(1.08); } to{ transform: translate3d(-9vmax,5vmax,0) scale(.94); } }
@keyframes drift3{ from{ transform: translate3d(0,0,0) scale(.96); } to{ transform: translate3d(6vmax,-8vmax,0) scale(1.12); } }

.vignette{ position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(120% 100% at 50% 8%, transparent 60%, rgba(150,170,220,.2) 100%); }
.grain{ position: fixed; inset: -60%; z-index: 72; pointer-events: none; opacity: .025;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grainShift 9s steps(10) infinite; }
@keyframes grainShift{
  0%,100%{ transform: translate(0,0); } 20%{ transform: translate(-3%,2%); }
  40%{ transform: translate(2%,-3%); } 60%{ transform: translate(-2%,-2%); } 80%{ transform: translate(3%,3%); }
}

/* ---------- 玻璃材质 ---------- */
.glass{
  background: linear-gradient(135deg, rgba(255,255,255,.78), rgba(255,255,255,.5) 46%, rgba(255,255,255,.7));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(180%);
  backdrop-filter: blur(var(--blur)) saturate(180%);
  border: 1px solid var(--edge);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.95), 0 16px 40px -26px rgba(31,47,92,.32), 0 1px 3px rgba(31,47,92,.06);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){
  .glass{ background: rgba(255,255,255,.92); }
}
.tint{ background: rgba(255,255,255,.6); border: 1px solid rgba(255,255,255,.9); }
.tilt{ position: relative; transform-style: preserve-3d; transform: perspective(900px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)); transition: transform .3s var(--ease-out); }
.tilt::after{
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity .3s;
  background: radial-gradient(340px circle at var(--mx,50%) var(--my,50%), rgba(255,255,255,.85), transparent 62%);
}
.tilt:hover::after{ opacity: 1; }
.tilt{ position: relative; transform-style: preserve-3d; transform: perspective(900px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)); transition: transform .3s var(--ease-out); }
.tilt::after{
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity .3s;
  background: radial-gradient(340px circle at var(--mx,50%) var(--my,50%), rgba(255,255,255,.55), transparent 62%);
}
.tilt:hover::after{ opacity: 1; }

/* ---------- 载入页：等入场照片墙准备好再露面 ----------
   设计取舍：全站只在「照片流动墙」一处用力，所以载入页刻意安静——
   不用进度条数字、不用 loading 文案堆砌，只给一枚会呼吸的玻璃水滴 + 一圈进度环，
   与入场按钮同一种材质（白磨砂 + 薄荷辉光），换场时像同一件东西在变。 */
#bootloader{
  position: fixed; inset: 0; z-index: 60; display: grid; place-items: center;
  background: var(--ink); overflow: hidden;
  transition: opacity .62s var(--ease-out), transform .62s var(--ease-out), filter .62s var(--ease-out);
}
#bootloader.is-out{ opacity: 0; transform: scale(1.04); filter: blur(14px); pointer-events: none; }
.bootload__glow{ position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(38% 32% at 32% 30%, rgba(69,224,181,.30), transparent 70%),
    radial-gradient(34% 30% at 70% 66%, rgba(108,92,231,.20), transparent 72%),
    radial-gradient(40% 34% at 62% 22%, rgba(255,107,74,.12), transparent 74%);
  animation: bootGlow 7s ease-in-out infinite; }
@keyframes bootGlow{ 0%,100%{ opacity: .78; } 50%{ opacity: 1; } }

.bootload__core{ position: relative; display: grid; place-items: center; gap: 22px; text-align: center; }
.bootload__avatar{
  position: relative; width: clamp(104px, 16vw, 148px); aspect-ratio: 1; border-radius: 50%;
  display: block;
  animation: dropBreathe 4.2s ease-in-out infinite;
}
/* 头像本体：圆形裁切 + 白色玻璃描边，和站点的液态玻璃同一材质 */
.bootload__avatar img{
  width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block;
  border: 2px solid rgba(255,255,255,.95);
  box-shadow: 0 22px 52px -24px rgba(31,47,92,.45), 0 0 0 6px rgba(255,255,255,.55), 0 0 62px -12px rgba(69,224,181,.55);
}
@keyframes dropBreathe{
  0%,100%{ transform: translateY(0) scale(1); }
  50%{ transform: translateY(-5px) scale(1.028); }
}
/* 水滴：与站点 favicon 同一枚形（心形叶片），用渐变描边呼应玻璃高光 */
.bootload__ring{
  position: absolute; left: 50%; top: 50%; width: calc(100% + 26px); height: calc(100% + 26px);
  transform: translate(-50%, -50%) rotate(-90deg); overflow: visible;
}
.bootload__ring circle{ fill: none; stroke-width: 2.4; stroke-linecap: round; }
.bootload__ring .track{ stroke: rgba(255,255,255,.72); }
.bootload__ring .bar{
  stroke: url(#bootGrad);
  stroke-dashoffset: 289;      /* 起始为空环 */
  /* 交接瞬间不能有过渡，否则 CSS 动画值 → JS 值之间会插值出一个"回退"帧 */
  transition: none;
  /* 纯 CSS 开场动画：HTML 一解析就开始跑，不依赖 app.v2.js 是否下载完。
     否则慢网下会看到"进度条一直空着"（脚本还没到）。
     JS 接管后会把 animation 关掉，改用更精细的随机节奏。 */
  animation: bootIdle 1.6s cubic-bezier(.3,.6,.3,1) forwards;
}
/* 从 0 爬到约 62%：给人"在加载"的即时反馈 */
@keyframes bootIdle{
  0%   { stroke-dashoffset: 289; }
  18%  { stroke-dashoffset: 236; }
  40%  { stroke-dashoffset: 176; }
  68%  { stroke-dashoffset: 132; }
  100% { stroke-dashoffset: 110; }
}
/* JS 接管后停用 CSS 动画，避免和脚本控制的数值打架 */
#bootloader.js-ready .bootload__ring .bar{
  animation: none;
  /* JS 接管后再开启过渡，让每帧变化更顺滑 */
  transition: stroke-dashoffset .18s linear;
}

.bootload__name{ font-family: var(--font-serif); font-size: clamp(19px, 2.4vw, 25px); letter-spacing: .16em; color: var(--text); opacity: 0; animation: bootFade .9s var(--ease-out) .12s forwards; }
@keyframes bootFade{ to{ opacity: 1; } }

@media (prefers-reduced-motion: reduce){
  .bootload__glow, .bootload__avatar{ animation: none !important; }
  .bootload__name{ animation: none !important; opacity: 1; }
}

/* ---------- 入场：照片流动墙 + 进入按钮 ---------- */
.intro{
  position: fixed; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center;
  overflow: hidden; user-select: none; -webkit-user-select: none;
  transition: transform .55s var(--ease-out), opacity .5s var(--ease-out);
}
/* 不要对整屏做 filter:blur —— 逐帧重绘，低端机直接掉帧（2026-10-21 建议） */
.intro.is-leaving{ transform: scale(1.12); opacity: 0; }

.wall{ position: absolute; inset: -24%; display: flex; flex-direction: column; gap: clamp(10px, 1.4vh, 18px);
  transform: rotate(-10deg); pointer-events: none; }
/* 行高由 flex 分配，track 用绝对定位撑满这一行。
   以前写 height:100%，父级高度来自 flex:1 1 0，链式百分比解析不可靠，
   结果 track 按图片原始高度撑成 4288px、而行只有 544px ——
   大量图片落在可视区之外，看起来就是"一大片空白格子"。 */
.wall__row{ flex: 1 1 0; min-height: 0; overflow: hidden; position: relative; }
.wall__track{ position: absolute; inset: 0; display: flex; gap: clamp(10px, 1.4vh, 18px);
  width: max-content; will-change: transform;
  animation: wallSlide linear infinite; }
.wall__row.rev .wall__track{ animation-direction: reverse; }
/* 保持照片原始比例：height 撑满行高、宽度按自身比例走（竖屏也不裁）。
   能安全用 width:auto 的关键是 <img> 上带了真实 width/height 属性
   （由 tools/wall_thumbs.py 的 sizes.json 提供）——浏览器插入 DOM 时
   就已知道每张图的比例，轨道总宽一次定型，不会随图片陆续解码而变化，
   因此动画时长只需标定一次，画面不再出现"一卡一卡的鬼畜"。 */
.wall__track img{ height: 100%; width: auto; max-height: 100%; border-radius: 14px; flex: 0 0 auto;
  /* 图片没到之前给一个淡色底：慢网下整面墙不会"全白一块" */
  background: linear-gradient(135deg, #E8EEFB, #EDE9F8);
  /* ★ 不要在这里加 filter（曾写 saturate(1) brightness(.95)）：
     旋转 + 动画中的元素一旦带 filter，Chromium/X5 会按低分辨率栅格化再放大，
     微信里看着就是"糊的"，而 Safari 正常（2026-10-20 用户反馈）。
     需要压暗/降饱和请用覆盖层，不要动图片滤镜。 */
  box-shadow: 0 14px 30px -22px rgba(31,47,92,.45); }
@keyframes wallSlide{ from{ transform: translate3d(0,0,0); } to{ transform: translate3d(-50%,0,0); } }
.wall__scrim{ position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(44% 38% at 50% 50%, rgba(255,255,255,.42), rgba(255,255,255,.14) 58%, transparent 78%),
    linear-gradient(180deg, rgba(238,243,255,.72), rgba(238,243,255,.1) 26%, rgba(238,243,255,.1) 74%, rgba(238,243,255,.72)); }

.enter-orb{
  position: relative; z-index: 2; width: clamp(150px, 21vw, 236px); height: clamp(150px, 21vw, 236px); border-radius: 50%;
  display: grid; place-items: center; color: var(--text); letter-spacing: .5em; text-indent: .5em;
  background: linear-gradient(150deg, rgba(255,255,255,.94), rgba(255,255,255,.66) 52%, rgba(69,224,181,.45));
  /* 不用 backdrop-filter：它在旋转的照片墙上取样会错位，画面中间出现一块“空白” */
  border: 1px solid rgba(255,255,255,.95);
  box-shadow: inset 0 1px 0 rgba(255,255,255,1), 0 26px 60px -22px rgba(31,47,92,.45), 0 0 70px -10px rgba(69,224,181,.55);
  transition: transform .4s var(--ease-spring), box-shadow .4s;
  animation: orbBreathe 4.6s ease-in-out infinite;
}
.enter-orb::after{ content: ""; position: absolute; inset: -18px; border-radius: 50%; border: 1.5px solid rgba(255,255,255,.85);
  transition: inset .35s var(--ease-spring), border-color .35s; }
.enter-orb:hover{ transform: scale(1.045); box-shadow: inset 0 1px 0 rgba(255,255,255,1), 0 30px 70px -22px rgba(31,47,92,.5), 0 0 110px -6px rgba(69,224,181,.85); }
.enter-orb:hover::after{ inset: -26px; border-color: rgba(16,185,140,.5); }
.enter-orb:active{ transform: scale(.97); }
.enter-orb__label{ font-size: clamp(17px, 1.9vw, 20px); font-weight: 700; }
@keyframes orbBreathe{
  0%, 100%{ box-shadow: inset 0 1px 0 rgba(255,255,255,1), 0 26px 60px -22px rgba(31,47,92,.45), 0 0 52px -14px rgba(69,224,181,.45); }
  50%{ box-shadow: inset 0 1px 0 rgba(255,255,255,1), 0 26px 60px -22px rgba(31,47,92,.45), 0 0 92px -8px rgba(69,224,181,.8); }
}

/* ---------- 首页：个人主页式的资料卡 + 板块切换 ----------
   只把"切换方式"改成主页式（三栏均分的顶部标签），
   内容仍是一个板块一张大卡片，与改造前保持一致。 */
.hprofile{
  display: flex; align-items: center; gap: clamp(14px, 2.4vw, 22px);
  padding: clamp(4px, 1vw, 10px) 2px clamp(14px, 2vw, 20px);
}
.hprofile__av{
  flex: 0 0 auto; width: clamp(72px, 11vw, 96px); aspect-ratio: 1; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.95);
  box-shadow: 0 16px 34px -18px rgba(31,47,92,.4), 0 0 0 5px rgba(255,255,255,.5);
  overflow: hidden;
}
.hprofile__av img{ width: 100%; height: 100%; object-fit: cover; display: block; }
.hprofile__info{ min-width: 0; }
.hprofile__name{
  margin: 0 0 6px; font-size: clamp(24px, 3.6vw, 34px); font-weight: 800; letter-spacing: -.01em;
  color: var(--text); line-height: 1.15;
}
.hprofile__note{ margin: 0; color: var(--text-2); font-size: clamp(13px, 1.5vw, 15px); }

/* 板块切换条：底部一条滑动指示线，和 Dock 的液态高亮同一语言 */
.htabs{
  position: relative; display: grid; grid-template-columns: repeat(3, 1fr);
  margin: 2px 0 clamp(16px, 2.2vw, 22px);
  border-bottom: 1px solid rgba(22,36,66,.1);
}
/* 三个板块均分整宽，不再挤在左边 */
.htabs--3 .htab{ justify-content: center; }
.htab{
  position: relative; appearance: none; border: 0; background: none; cursor: pointer;
  padding: 11px 6px 13px; margin: 0; font-family: inherit;
  font-size: clamp(14px, 1.6vw, 16px); font-weight: 600; color: var(--text-3);
  display: flex; align-items: center; justify-content: center; gap: 7px;
  transition: color .25s var(--ease-out);
  border-radius: var(--r-sm) var(--r-sm) 0 0;
}
.htab:hover{ background: rgba(255,255,255,.5); }
.htab.is-on{ color: var(--text); font-weight: 800; }
.htab.is-on::after{
  content: ""; position: absolute; left: 50%; transform: translateX(-50%);
  width: min(58%, 120px); bottom: -1px; height: 2.5px; border-radius: 2px;
  background: linear-gradient(90deg, var(--aqua), var(--iris));
}
.htab__n{
  font-size: 11px; font-weight: 600; line-height: 1; padding: 3px 6px; border-radius: 999px;
  background: rgba(22,36,66,.07); color: var(--text-2);
}
.htab.is-on .htab__n{ background: rgba(16,185,140,.16); color: var(--aqua); }

/* 内容面板：一个板块 = 原来那张大卡片，保持原样 */
/* 内容卡片：固定一个舒服的上限宽度并居中，
   避免"电脑端太小、手机端太大"的两头不讨好。
   桌面 520px / 平板 460px / 手机铺满；图片比例桌面 16:10（舒展），手机 4:3（不占太多竖向空间） */
/* 作品封面拼贴：由数据驱动（1~4 张自动排布），
   作品增减或换封面都会自动适配，不需要改样式 */
.qcard__media--custom{ display: block; }
.wm{ width: 100%; height: 100%; display: grid; gap: 6px; padding: 6px;
  background: linear-gradient(140deg, rgba(108,92,231,.16), rgba(69,224,181,.16)); }
.wm__cell{ position: relative; overflow: hidden; border-radius: 10px; background: rgba(255,255,255,.5); }
.wm__cell img{ width: 100%; height: 100%; object-fit: cover; display: block; }
/* 1 张：铺满 */
.wm--1{ grid-template-columns: 1fr; }
/* 2 张：左右并排 */
.wm--2{ grid-template-columns: 1fr 1fr; }
/* 3 张：左大右两小 */
.wm--3{ grid-template-columns: 2fr 1fr; grid-template-rows: 1fr 1fr; }
.wm--3 .wm__cell:nth-child(1){ grid-row: span 2; }
/* 4 张：2×2 */
.wm--4{ grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
@media (max-width: 480px){
  .wm{ gap: 4px; padding: 4px; }
  .wm__cell{ border-radius: 8px; }
}

.hpanel{ display: grid; gap: 18px; justify-items: center; }
.hpanel > *{ width: 100%; max-width: min(520px, 100%); }
.hpanel .qcard__media{ aspect-ratio: 4 / 3; }
@media (min-width: 761px){
  .hpanel .qcard__media{ aspect-ratio: 16 / 10; }
}
@media (max-width: 480px){
  .hpanel .qcard__media{ aspect-ratio: 4 / 3; }
}

/* ---------- 返回主页按钮 ----------
   取代原来的底部 Dock：Dock 在电脑端太"手机"，而且内页要靠它跳转很别扭。
   现在统一改成左上角一个「← 主页」按钮 —— 用户的右手/鼠标不用满屏找，
   手机端再额外支持从左缘侧滑返回，符合本能。 */
.backbtn{
  position: fixed; z-index: 32;
  left: calc(var(--page-x) + env(safe-area-inset-left));
  top: calc(14px + env(safe-area-inset-top));
  display: inline-flex; align-items: center; gap: 7px;
  height: 42px; padding: 0 15px 0 12px; border-radius: 999px; cursor: pointer;
  font-family: inherit; font-size: 14px; font-weight: 650; color: var(--text);
  background: linear-gradient(135deg, rgba(255,255,255,.94), rgba(255,255,255,.68));
  -webkit-backdrop-filter: blur(22px) saturate(170%); backdrop-filter: blur(22px) saturate(170%);
  border: 1px solid rgba(255,255,255,.95);
  box-shadow: inset 0 1px 0 rgba(255,255,255,1), 0 16px 34px -20px rgba(31,47,92,.5);
  transition: transform .28s var(--ease-spring), box-shadow .28s, background .25s;
}
.backbtn svg{ width: 19px; height: 19px; }
.backbtn:hover{ transform: translateY(-1px); box-shadow: inset 0 1px 0 rgba(255,255,255,1), 0 20px 40px -20px rgba(31,47,92,.55); }
.backbtn:active{ transform: scale(.96); }
@media (max-width: 560px){
  .backbtn{ height: 40px; padding: 0 13px 0 10px; }
  .backbtn__label{ display: none; }   /* 窄屏只留箭头，省空间 */
  .backbtn{ width: 40px; padding: 0; justify-content: center; }
}

/* ---------- 应用外壳 ---------- */
.app{ position: relative; z-index: 2; opacity: 0; transform: scale(.992) translateY(6px);
  transition: opacity .45s var(--ease-out), transform .5s var(--ease-out); }
.app.is-in{ opacity: 1; transform: none; }

main{ position: relative; max-width: 1180px; margin: 0 auto; padding: calc(72px + env(safe-area-inset-top)) var(--page-x) 30px; }
.view{ animation: viewIn .45s var(--ease-out) both; }
@keyframes viewIn{ from{ opacity: 0; transform: translateY(16px) scale(.996); } to{ opacity: 1; transform: none; } }

.footer{ position: relative; max-width: 1180px; margin: 0 auto; padding: 30px var(--page-x) var(--dock-space); color: var(--text-3); font-size: 13px; display: flex; flex-wrap: wrap; gap: 10px 22px; align-items: center; }
.footer a{ color: var(--text-2); font-weight: 600; }
.footer__sep{ opacity: .4; }

/* ---------- 通用排版与元件 ---------- */
.lead{ font-size: clamp(17px, 2.2vw, 21px); color: var(--text-2); max-width: 620px; line-height: 1.9; }
.sec-head{ margin: 0 0 34px; }
.sec-head h2{ margin: 0 0 10px; font-size: clamp(30px, 4.6vw, 46px); font-weight: 800; letter-spacing: -.01em; }
.sec-head p{ margin: 0; color: var(--text-2); max-width: 560px; }
.mono{ font-family: var(--font-mono); font-size: 12px; letter-spacing: .1em; color: var(--text-3); font-variant-numeric: tabular-nums; }

.chip{ display: inline-flex; align-items: center; gap: 6px; padding: 5px 13px; border-radius: 999px; font-size: 12.5px; color: var(--text-2); background: rgba(255,255,255,.72); border: 1px solid rgba(255,255,255,.95); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
.chip--aqua{ color: #0A7A5C; background: rgba(69,224,181,.22); border-color: rgba(16,185,140,.35); }
.chip--coral{ color: #B93A1E; background: rgba(255,107,74,.16); border-color: rgba(255,107,74,.35); }
.chip--amber{ color: #8F6008; background: rgba(240,164,0,.16); border-color: rgba(240,164,0,.35); }
.chip--iris{ color: #4B3BC4; background: rgba(108,92,231,.16); border-color: rgba(108,92,231,.35); }

.btn{ position: relative; display: inline-flex; align-items: center; gap: 9px; padding: 12px 22px; border-radius: 999px; font-size: 14.5px; font-weight: 600;
  border: 1px solid rgba(255,255,255,.95); background: rgba(255,255,255,.75); transition: transform .25s var(--ease-spring), background .25s, box-shadow .25s; overflow: hidden;
  box-shadow: 0 10px 24px -16px rgba(31,47,92,.4); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }
.btn:hover{ transform: translateY(-2px); background: rgba(255,255,255,.95); }
.btn:active{ transform: translateY(0) scale(.98); }
.btn svg{ width: 17px; height: 17px; }
.btn--primary{ background: linear-gradient(135deg, #2AD0A2, #45E0B5 55%, #8CE9F5); color: #043A2B; border-color: transparent; box-shadow: 0 14px 32px -12px rgba(16,185,140,.6); }
.btn--primary:hover{ background: linear-gradient(135deg, #37DCAE, #6BEBCC 55%, #A9F2FB); }
.btn--ghost{ background: transparent; box-shadow: none; border-color: rgba(255,255,255,.9); }
.btn--ghost:hover{ background: rgba(255,255,255,.6); }
.ripple{ position: relative; overflow: hidden; }
.ripple__wave{ position: absolute; width: 12px; height: 12px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(16,185,140,.35), rgba(16,185,140,0) 68%);
  transform: translate(-50%,-50%) scale(.2); animation: rippleOut .65s var(--ease-out) forwards; }
@keyframes rippleOut{ to{ transform: translate(-50%,-50%) scale(var(--sc,8)); opacity: 0; } }

.empty{ padding: 60px 28px; text-align: center; border-radius: var(--r-lg); color: var(--text-2); }
.empty__glyph{ font-size: 40px; margin-bottom: 12px; opacity: .8; }

/* ---------- 首页 ---------- */
.hero{ padding: clamp(10px, 5vh, 56px) 0 44px; }
.hero__welcome{ margin: 0; font-size: clamp(34px, 6vw, 64px); font-weight: 800; letter-spacing: -.01em; line-height: 1.12;
  background: linear-gradient(115deg, #0E1730 28%, #4B3BC4 62%, var(--aqua));
  -webkit-background-clip: text; background-clip: text; color: transparent; }
.hero__note{ margin: 16px 0 0; font-size: clamp(14px, 1.7vw, 16.5px); color: var(--text-2); letter-spacing: .02em; }
.hero__wave{ display: block; width: min(420px, 70%); height: 26px; margin-top: 24px; opacity: .85; }

/* 快捷入口数量会变（板块空了就不出现），所以列数自适应，不留空格子 */
.quick-grid{ display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 18px; margin-bottom: 46px; }
.quick-grid .qcard:only-child{ max-width: 480px; }
.qcard{ position: relative; border-radius: var(--r-lg); overflow: hidden; text-align: left; display: block; width: 100%; padding: 0; }
.qcard__media{ position: relative; aspect-ratio: 4 / 3; overflow: hidden; }
.qcard__media img{ width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease-out); }
.qcard:hover .qcard__media img{ transform: scale(1.06); }
.qcard__media::after{ content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, transparent 74%, rgba(6,10,20,.26)); }
.qcard__body{ position: relative; padding: 18px 20px 20px; z-index: 1; }
.qcard__title{ display: flex; align-items: center; gap: 9px; margin: 0 0 7px; font-size: 18.5px; font-weight: 750; letter-spacing: .01em; color: var(--text); }
.qcard__dot{ flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; }
.qcard__dot--aqua{ background: var(--aqua); box-shadow: 0 0 0 3px rgba(16,185,140,.16); }
.qcard__dot--coral{ background: var(--coral); box-shadow: 0 0 0 3px rgba(255,107,74,.16); }
.qcard__dot--iris{ background: var(--iris); box-shadow: 0 0 0 3px rgba(108,92,231,.16); }
.qcard__desc{ margin: 0; font-size: 13.5px; color: var(--text-2); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.7; }
.qcard__go{ display: flex; width: max-content; white-space: nowrap; align-items: center; gap: 6px; margin-top: 12px; font-size: 13px; color: var(--text-3); font-weight: 600; transition: color .3s; }
.qcard:hover .qcard__go{ color: var(--aqua); }
.qcard__go svg{ width: 16px; height: 16px; flex: 0 0 auto; }


/* ---------- 摄影 ---------- */
/* ============ 摄影页：折叠式筛选（右上角胶囊） ============
   分组/标签可能几十个，平铺会把首屏占满，改成点开才展开的面板。 */
.headtools--photo{ display: flex; gap: 10px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }

.filtertoggle{
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  /* 固定高度：无论文字多长，按钮高度都不变，避免"忽大忽小" */
  height: 38px; box-sizing: border-box; flex: 0 0 auto;
  padding: 0 14px 0 12px; border-radius: 999px; font: inherit; font-size: 13.5px; font-weight: 650;
  background: rgba(255,255,255,.72); border: 1px solid rgba(255,255,255,.95);
  color: var(--text-2); position: relative;
  box-shadow: 0 10px 24px -18px rgba(31,47,92,.4);
  transition: background .22s, color .22s, border-color .22s, transform .18s var(--ease-out);
}
.filtertoggle:hover{ transform: translateY(-1px); background: rgba(255,255,255,.95); }
/* 图标尺寸必须写死：父容器是 flex，若 svg 没被显式约束，
   会被拉伸成和按钮一样大（手机上出现过被撑成三根大横条的情况）。 */
.filtertoggle > svg{
  width: 16px !important; height: 16px !important;
  min-width: 16px; min-height: 16px;
  flex: 0 0 16px; display: block;
}
.filtertoggle__t{ max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 有筛选条件时高亮，并点一个小圆点提醒"当前不是全部" */
.filtertoggle.is-active{ background: linear-gradient(135deg, #7C6BFF, #6C5CE7); border-color: transparent; color: #fff; }
.filtertoggle__dot{ width: 7px; height: 7px; border-radius: 50%; background: #45E0B5; box-shadow: 0 0 0 3px rgba(69,224,181,.3); }

/* 展开的面板 */
.fpanel{
  margin: 0 0 22px; padding: 16px 18px; border-radius: var(--r-md);
  background: rgba(255,255,255,.72); border: 1px solid rgba(255,255,255,.95);
  box-shadow: 0 18px 40px -30px rgba(31,47,92,.45);
  animation: fpanelIn .26s var(--ease-out) both;
}
@keyframes fpanelIn{ from{ opacity: 0; transform: translateY(-6px); } to{ opacity: 1; transform: none; } }
.fpanel__head{ display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.fpanel__head b{ font-size: 14px; }
.fpanel__head .muted{ font-size: 12.5px; color: var(--text-3); margin-right: auto; }
.fpanel__sec + .fpanel__sec{ margin-top: 14px; }
.fpanel__label{ font-size: 12px; font-weight: 700; color: var(--text-3); letter-spacing: .06em; margin-bottom: 8px; }
.fpanel__chips{ display: flex; flex-wrap: wrap; gap: 8px; }

@media (max-width: 760px){
  .headtools--photo{ width: 100%; justify-content: space-between; }
  .fpanel{ padding: 14px; }
  .fpanel__chips .filter{ font-size: 12.5px; padding: 6px 11px; }
}

/* 相册分组（编辑器里的"文件夹"）：用紫色系和标签筛选区分开，一眼看出层级 */
.filters--group{ margin-bottom: 12px; }
.filter--group{ background: rgba(108,92,231,.1); border-color: rgba(108,92,231,.3); color: #4B3BC4; }
.filter--group.is-on{ background: linear-gradient(135deg, #7C6BFF, #6C5CE7); border-color: transparent; color: #fff;
  box-shadow: 0 12px 26px -12px rgba(108,92,231,.7); }
.filter--group.is-on:hover{ color: #fff; }

/* 网格视图：按"大标签"（相册分组）分块显示 */
.pgroup{ margin: 0 0 30px; }
.pgroup__head{ display: flex; align-items: baseline; gap: 10px; margin: 0 0 14px; padding-bottom: 8px;
  border-bottom: 1px solid rgba(22,36,66,.1); }
.pgroup__name{ font-size: clamp(18px, 2.2vw, 22px); font-weight: 800; color: var(--text); }
.pgroup__n{ font-family: var(--font-mono); font-size: 12px; color: var(--text-3); }

.masonry{ column-count: 3; column-gap: 18px; }
.ph{
  position: relative; break-inside: avoid; margin: 0 0 18px; border-radius: var(--r-md); overflow: hidden; cursor: pointer; display: block; width: 100%; padding: 0; text-align: left;
  border: 1px solid rgba(255,255,255,.92); background: rgba(255,255,255,.55); box-shadow: 0 18px 40px -28px rgba(31,47,92,.38); }
/* height:auto 必须写：
   图片标签带 width/height 属性是为了让浏览器提前知道比例（避免布局跳动），
   但如果 CSS 不写 height:auto，浏览器会把 height 属性当成固定像素高度，
   结果图片被拉成又细又长的怪比例。 */
.ph img{ width: 100%; height: auto; transition: transform .32s var(--ease-out); }
.ph:hover img{ transform: scale(1.045); }
.ph::after{ content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, transparent 55%, rgba(5,9,18,.85)); opacity: 0; transition: opacity .4s; }
.ph:hover::after{ opacity: 1; }
.ph__meta{ position: absolute; left: 0; right: 0; bottom: 0; padding: 16px 18px; transform: translateY(10px); opacity: 0; transition: .4s var(--ease-out); z-index: 1; }
.ph:hover .ph__meta{ transform: none; opacity: 1; }
.ph__title{ font-weight: 700; font-size: 15px; color: #fff; }
.ph__sub{ font-family: var(--font-mono); font-size: 11.5px; color: rgba(255,255,255,.8); margin-top: 3px; }
.ph__note{ position: absolute; top: 12px; right: 12px; z-index: 1; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(255,255,255,.92); border: 1px solid rgba(255,255,255,1); box-shadow: 0 8px 20px -10px rgba(31,47,92,.5); opacity: 0; transition: opacity .3s; }
.ph:hover .ph__note{ opacity: 1; }
.ph__note svg{ width: 13px; height: 13px; color: var(--text-2); }

/* ---------- 灯箱 / 舞台 / 详情 通用 ---------- */
/* 浮层要盖住"视觉视口"而不是布局视口：
   iOS Safari 的工具栏会占掉底部一块，inset:0 只到布局视口底，
   于是工具栏附近会透出下面的页面内容。用 100dvh 才是真实可见高度。 */
.overlay{
  position: fixed; left: 0; right: 0; top: 0; height: 100vh; height: 100dvh;
  z-index: 90; display: flex; align-items: center; justify-content: center;
  padding: clamp(14px, 3vw, 40px); overflow: auto;
  overscroll-behavior: contain;
}
/* 浮层自己的底色（不透明）：双保险，任何缝隙都不会露出页面内容 */
.overlay::before{
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: var(--ink);
}
.overlay__scrim{ position: absolute; inset: 0; z-index: 1; background: rgba(224,232,252,.72); -webkit-backdrop-filter: blur(22px) saturate(140%); backdrop-filter: blur(22px) saturate(140%);
  opacity: 0; transition: opacity .35s; }
.overlay.is-open .overlay__scrim{ opacity: 1; }
/* 大图浮层的遮罩淡入稍慢一点，配合缩放过渡更连贯 */
.overlay--lightbox .overlay__scrim{ transition: opacity .3s ease; }
.overlay__panel{ position: relative; z-index: 2; width: 100%; opacity: 0; transform: translateY(22px) scale(.97); transition: opacity .4s var(--ease-out), transform .45s var(--ease-spring); }
.overlay.is-open .overlay__panel{ opacity: 1; transform: none; }
/* 关闭要干脆：淡出比入场快一截 */
.overlay:not(.is-open) .overlay__scrim{ transition: opacity .22s ease; }
.overlay:not(.is-open) .overlay__panel{ transition: opacity .24s ease, transform .26s ease; }

/* 关闭叉与返回键：跟随图片 / 相框 / 面板，不放在屏幕角落 */
.overlay:focus{ outline: none; }
.ov-ctl{ position: absolute; z-index: 3; display: flex; align-items: center; gap: 8px; }
.ov-ctl--close{ top: 10px; right: 10px; }
.ov-ctl--back{ top: 10px; left: 10px; }
/* 大图浏览（摄影灯箱 / 日记相框）：叉挂在相框外角上，不压住照片主体（更大的一枚） */
/* 关闭按钮放在图片内部右上角：
   以前用 translate(56%,-56%) 往外推，桌面端图片几乎顶满视口时
   按钮会被推到屏幕外，根本点不到。 */
.lb__figure .ov-ctl--close, .stage-col .ov-ctl--close{ top: 10px; right: 10px; transform: none; }
/* 手机上 figure 有 overflow:hidden，外挂的关闭按钮会被裁掉 —— 改成贴在图内右上角 */
@media (max-width: 760px){
  .lb__figure .ov-ctl--close{ transform: none; top: 8px; right: 8px; }
  .lb__figure .ov-ctl--close .ov-btn{ width: 44px; height: 44px; }
  .lb__figure .ov-ctl--close .ov-btn svg{ width: 18px; height: 18px; }
}
.lb__figure .ov-ctl--close .ov-btn, .stage-col .ov-ctl--close .ov-btn{ width: 54px; height: 54px; }
.lb__figure .ov-ctl--close .ov-btn svg, .stage-col .ov-ctl--close .ov-btn svg{ width: 21px; height: 21px; }
/* 液体玻璃小控件：关闭叉 / 翻页胶囊（更透、更亮、带一圈柔光环） */
.ov-btn{ display: inline-flex; align-items: center; gap: 7px; height: 44px; padding: 0 17px; border-radius: 999px; font-size: 14px; font-weight: 600; color: var(--text);
  background: linear-gradient(150deg, rgba(255,255,255,.82), rgba(255,255,255,.46) 55%, rgba(69,224,181,.22));
  border: 1px solid rgba(255,255,255,.92);
  -webkit-backdrop-filter: blur(20px) saturate(190%); backdrop-filter: blur(20px) saturate(190%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,1), inset 0 -10px 18px -10px rgba(69,224,181,.5),
    0 14px 30px -16px rgba(31,47,92,.5), 0 0 0 6px rgba(255,255,255,.16);
  transition: background .2s, transform .25s var(--ease-spring), box-shadow .25s; }
.ov-btn:hover{ background: #fff; transform: translateY(-1px); box-shadow: inset 0 1px 0 #fff, inset 0 -10px 18px -10px rgba(69,224,181,.6),
    0 18px 34px -16px rgba(31,47,92,.55), 0 0 0 8px rgba(255,255,255,.2); }
.ov-btn:active{ transform: scale(.96); }
.ov-btn svg{ width: 18px; height: 18px; }
.ov-btn--icon{ width: 44px; padding: 0; justify-content: center; }
.ov-btn--icon:hover{ transform: rotate(90deg); }

/* 大图容器：参与 iOS 风格的缩放过渡，需要裁切与圆角 */
.lb__figure{
  position: relative; width: fit-content; max-width: min(1080px, 100%);
  margin: 0 auto; text-align: center;
  overflow: hidden; border-radius: var(--r-md);
  backface-visibility: hidden;
}
.lb__figure img{ margin: 0 auto; max-height: min(76vh, calc(100dvh - 200px)); width: auto; max-width: 100%; border-radius: var(--r-md); border: 1px solid rgba(255,255,255,.95);
  box-shadow: 0 30px 70px -30px rgba(31,47,92,.55); }
.lb__bar{ max-width: min(1080px, 100%); margin: 20px auto 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.lb__info{ min-width: 0; }
.lb__title{ font-size: 18px; font-weight: 700; }
.lb__caption{ color: var(--text-2); font-size: 14px; margin-top: 6px; max-width: 560px; line-height: 1.8; }
.lb__tags{ display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
/* 大图翻页胶囊：挂在 overlay 直接子元素上（不是 panel 里），
   这样从第一帧就固定在屏幕底部，不受 panel 入场 transform 影响。 */
.lb-nav-slot{ display: contents; }
.lb-nav{
  position: fixed; left: 50%; bottom: calc(18px + env(safe-area-inset-bottom));
  transform: translateX(-50%); z-index: 6;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px; border-radius: 999px;
  background: linear-gradient(135deg, rgba(255,255,255,.95), rgba(255,255,255,.74));
  -webkit-backdrop-filter: blur(22px) saturate(170%); backdrop-filter: blur(22px) saturate(170%);
  border: 1px solid rgba(255,255,255,.95);
  box-shadow: inset 0 1px 0 rgba(255,255,255,1), 0 18px 40px -22px rgba(31,47,92,.55);
  animation: lbNavIn .3s var(--ease-out) both;
}
@keyframes lbNavIn{ from{ opacity: 0; transform: translateX(-50%) translateY(8px); } to{ opacity: 1; transform: translateX(-50%); } }
/* 给底部胶囊留空间 */
.lb__bar{ padding-bottom: 68px; }
.lb__count{ font-family: var(--font-mono); font-size: 12.5px; color: var(--text-3); letter-spacing: .12em;
  margin-right: 4px; white-space: nowrap; flex: 0 0 auto; }
.nav-btn{ width: 50px; height: 50px; border-radius: 50%; display: grid; place-items: center; color: var(--text);
  background: linear-gradient(150deg, rgba(255,255,255,.82), rgba(255,255,255,.46) 55%, rgba(69,224,181,.2));
  border: 1px solid rgba(255,255,255,.92);
  -webkit-backdrop-filter: blur(18px) saturate(190%); backdrop-filter: blur(18px) saturate(190%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,1), inset 0 -9px 16px -9px rgba(69,224,181,.45), 0 12px 26px -14px rgba(31,47,92,.45);
  transition: background .25s, transform .25s var(--ease-spring); }
.nav-btn:hover{ background: #fff; transform: translateY(-2px) scale(1.04); }
.nav-btn svg{ width: 21px; height: 21px; }

/* ---------- 恋爱日记 ---------- */
/* 日记墙用「瀑布流」而不是网格：照片长宽比各不相同，网格会把矮的那列留出空白 */
.diary-grid{ column-count: 3; column-gap: clamp(18px, 3vw, 34px); }
.diary-item{ display: flex; justify-content: center; break-inside: avoid; margin: 0 0 clamp(20px, 3vw, 38px); }
.frame{ position: relative; cursor: pointer; transition: transform .5s var(--ease-spring), box-shadow .5s; }
.diary-item .frame{ width: 100%; max-width: 330px; }
.frame__win{ overflow: hidden; }
/* height:auto 必须写：<img> 上带了 width/height 属性（用来预留比例），
   如果 CSS 不声明 height:auto，浏览器会把 height 属性当成固定像素高度，
   新上传的照片就会被拉成又细又长的样子（2026-10-21 修）。 */
.frame__win img{ width: 100%; height: auto; display: block; transition: opacity .18s ease; }
.frame__date{ font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .1em; text-align: center; }

.frame--polaroid{ background: linear-gradient(180deg, #FBF8F0, #F2EDE0); padding: 13px 13px 12px; border-radius: 5px;
  box-shadow: 0 26px 50px -22px rgba(0,0,0,.85), 0 3px 10px rgba(0,0,0,.4); }
/* 相纸底色：图还没解码完时露出的是纸色而不是黑块 */
.frame--polaroid .frame__win{ border-radius: 2px; background: #ece7dc; }
.frame--polaroid .frame__date{ color: #8a8071; padding: 12px 4px 4px; font-family: var(--font-serif); font-size: 13px; letter-spacing: .06em; }
.frame--gold{ background: linear-gradient(140deg, #1a2236, #0d1322 60%, #151d31); padding: 12px; border-radius: 20px;
  box-shadow: 0 26px 54px -22px rgba(0,0,0,.9); border: 1px solid rgba(255,194,75,.45); }
.frame--gold .frame__win{ border-radius: 12px; border: 1px solid rgba(255,194,75,.28); }
.frame--gold .frame__date{ color: rgba(255,194,75,.8); padding: 11px 4px 2px; }
.frame--wood{ background: linear-gradient(140deg, #4a3324, #2b1c12 55%, #3d2a1c); padding: 15px; border-radius: 10px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08), inset 0 2px 8px rgba(0,0,0,.6), 0 26px 54px -22px rgba(0,0,0,.9); }
.frame--wood .frame__win{ border-radius: 5px; box-shadow: inset 0 0 18px rgba(0,0,0,.55); }
.frame--wood .frame__date{ color: rgba(233,214,190,.75); padding: 12px 4px 2px; }

.diary-item:nth-child(3n+1) .frame{ transform: rotate(-1.8deg); }
.diary-item:nth-child(3n+2) .frame{ transform: rotate(1.2deg); }
.diary-item:nth-child(3n)   .frame{ transform: rotate(-.6deg); }
.diary-item .frame:hover{ transform: rotate(0) translateY(-10px) scale(1.025); z-index: 2; }
.frame--gold:hover{ box-shadow: 0 34px 70px -24px rgba(0,0,0,.95), 0 0 40px -8px rgba(255,194,75,.35); }

.stage-wrap{ display: flex; align-items: center; justify-content: center; gap: clamp(20px, 4vw, 54px); max-width: min(1320px, 100%); margin: 0 auto; }
/* 图片直接以视口为基准定尺寸，相框贴合图片 —— 不用 fit-content 互相引用（会算出小尺寸） */
.stage-wrap .frame{ width: fit-content; cursor: default; }
.stage-wrap .frame__win img{ width: auto; height: auto; max-width: min(92vw, 1240px); max-height: min(88vh, calc(100dvh - 80px)); }
/* 带手写信的照片：桌面端照片在左、信纸在右；窄屏上下排 */
@media (min-width: 900px){
  .stage-wrap:has(.letter){ flex-direction: row; align-items: center; gap: clamp(24px, 4vw, 60px); }
  .stage-wrap:has(.letter) .frame__win img{ max-width: calc(100vw - 700px); max-height: min(84vh, calc(100dvh - 140px)); }
  .stage-wrap:has(.letter) .letter{
    width: min(500px, 42vw);
    /* 关键：flex 行布局里必须禁止收缩，否则图片一宽，文字卡片会被压成一条细线。 */
    flex: 0 0 auto;
    min-width: 260px;
    max-height: min(78vh, calc(100dvh - 140px));
    overflow: auto; margin: 0;
  }
}
@media (max-width: 899px){
  .overlay--stage:has(.letter){ align-items: flex-start; padding-top: max(14px, 3vh); }
  .stage-wrap:has(.letter){ flex-direction: column; gap: 14px; }
  .stage-wrap:has(.letter) .frame__win img{ max-height: min(56vh, calc(100dvh - 190px)); }
  .stage-wrap:has(.letter) .letter{
    width: min(680px, 92vw); flex: 0 0 auto; min-width: 0;
    max-height: 26vh; overflow: auto; margin: 0 auto;
  }
}
.stage-wrap .frame:hover{ transform: none; }
.letter{ position: relative; width: min(360px, 88vw); padding: 34px 30px 30px; border-radius: 6px; transform: rotate(1.4deg);
  background: linear-gradient(180deg, #FBF6EA, #F3EDDC); color: #3d3628;
  box-shadow: 0 34px 70px -26px rgba(0,0,0,.9); animation: letterIn .6s var(--ease-spring) both .12s; }
@keyframes letterIn{ from{ opacity: 0; transform: rotate(1.4deg) translateY(26px) scale(.96); } to{ opacity: 1; transform: rotate(1.4deg) translateY(0) scale(1); } }
.letter::before{ content: ""; position: absolute; top: -14px; left: 50%; transform: translateX(-50%) rotate(-3deg); width: 110px; height: 30px;
  background: rgba(255,255,255,.4); border: 1px solid rgba(255,255,255,.5); box-shadow: 0 4px 10px rgba(0,0,0,.25); }
.letter__title{ font-family: var(--font-serif); font-size: 19px; font-weight: 700; margin: 0 0 5px; color: #2e2820; }
.letter__date{ font-family: var(--font-serif); font-size: 12.5px; color: #94896f; letter-spacing: .08em; }
.letter__text{ font-family: var(--font-serif); font-size: 16px; line-height: 2; margin: 16px 0 0; color: #443c2c; }
.letter__sign{ margin-top: 18px; text-align: right; font-family: var(--font-serif); font-size: 14px; color: #94896f; }
.stage-hint{ position: fixed; left: 50%; transform: translateX(-50%); bottom: calc(22px + env(safe-area-inset-bottom)); font-size: 12px; color: var(--text-3); letter-spacing: .1em; }

.burst{ position: fixed; z-index: 90; pointer-events: none; font-size: 20px; animation: burst .95s ease-out forwards; }
@keyframes burst{ from{ transform: translate(0,0) scale(.5) rotate(0); opacity: 1; } to{ transform: translate(var(--tx),var(--ty)) scale(1.2) rotate(var(--rz,20deg)); opacity: 0; } }

/* ---------- 创作成果 ---------- */
.filters{ display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 26px; }
.filter{ padding: 8px 18px; border-radius: 999px; font-size: 13.5px; color: var(--text-2); background: rgba(255,255,255,.68); border: 1px solid rgba(255,255,255,.95); transition: .25s; box-shadow: 0 8px 20px -16px rgba(31,47,92,.4); }
.filter:hover{ background: rgba(255,255,255,.95); color: var(--text); }
.filter.is-on{ color: #043A2B; background: linear-gradient(135deg, #2AD0A2, #45E0B5); border-color: transparent; font-weight: 700; box-shadow: 0 12px 26px -10px rgba(16,185,140,.55); }

.works-grid{ display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
.work-card{ position: relative; text-align: left; padding: 0; border-radius: var(--r-lg); overflow: hidden; display: flex; flex-direction: column; }
.work-card__cover{ position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: linear-gradient(135deg, rgba(69,224,181,.4), rgba(108,92,231,.34), rgba(255,107,74,.3)); }
.work-card__cover img{ width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease-out); }
.work-card:hover .work-card__cover img{ transform: scale(1.05); }
.work-card__cover--empty{ display: grid; place-items: center; }
.work-card__cover--empty svg{ width: 54px; height: 54px; color: rgba(255,255,255,.6); }
.cover-initial{ font-size: clamp(44px, 5vw, 64px); font-weight: 800; color: rgba(14,23,48,.26); letter-spacing: .08em; }
.work-card__play{ position: absolute; right: 14px; bottom: 14px; z-index: 2; width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center; color: #043A2B;
  background: linear-gradient(135deg, #2AD0A2, #6BEBCC); box-shadow: 0 12px 26px -10px rgba(16,185,140,.65); transition: transform .25s var(--ease-spring); }
.work-card__play:hover{ transform: scale(1.1); }
.work-card__play svg{ width: 18px; height: 18px; }
.work-card__body{ padding: 20px 24px 22px; flex: 1; display: flex; flex-direction: column; }
.work-card__top{ display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.work-card__date{ margin-left: auto; }
.work-card__name{ font-size: 19px; font-weight: 750; margin: 0 0 8px; }
.work-card__sum{ color: var(--text-2); font-size: 14px; margin: 0; flex: 1; }
.work-card__foot{ display: flex; align-items: center; gap: 14px; margin-top: 16px; font-size: 13.5px; color: var(--aqua); font-weight: 600; }
.work-card__foot svg{ width: 15px; height: 15px; }
.work-card__dl{ color: var(--text-3); font-weight: 400; display: inline-flex; align-items: center; gap: 6px; }

/* 作品详情卡：封面在上、文字在下，两者绝不重叠（以前用负 margin 把文字压到封面上，
   结果标题是白字、压在浅色封面时完全看不见）。整卡居中并限制高度，避免超出视口被裁。 */
.sheet{ position: relative; width: min(790px, 100%); max-width: min(790px, 100%);
  margin: 0 auto; border-radius: var(--r-lg); overflow: hidden;
  max-height: calc(100vh - clamp(28px, 6vw, 80px)); display: flex; flex-direction: column; }
.sheet__cover{ position: relative; aspect-ratio: 21 / 9; overflow: hidden; flex: 0 0 auto; background: rgba(22,36,66,.06); }
.sheet__cover img{ width: 100%; height: 100%; object-fit: cover; display: block; }
.sheet__inner{ position: relative; z-index: 1; margin-top: 0; flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain; background: rgba(255,255,255,.92); }
.sheet__head{ position: relative; padding: 22px 30px 6px; }
.sheet__name{ font-size: clamp(24px, 3.6vw, 32px); font-weight: 800; margin: 12px 0 0; color: var(--text); }
.sheet__meta{ display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.sheet__meta .mono{ color: var(--text-3); }
.sheet__body{ padding: 18px 30px 8px; }
.sheet__sum{ font-size: 16px; color: var(--text); margin: 0 0 16px; }
.sheet__p{ color: var(--text-2); font-size: 15px; margin: 0 0 12px; line-height: 1.9; }
.sheet__sec{ margin: 26px 0 12px; font-size: 14px; font-weight: 700; color: var(--text-2); display: flex; align-items: center; gap: 10px; }
.sheet__sec::after{ content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, rgba(22,36,66,.16), transparent); }
.dl-row{ display: flex; align-items: center; gap: 14px; padding: 13px 16px; border-radius: var(--r-sm); background: rgba(255,255,255,.62); border: 1px solid rgba(255,255,255,.95); margin-bottom: 10px; }
.dl-row__icon{ flex: 0 0 auto; width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center; color: var(--aqua); background: rgba(69,224,181,.2); border: 1px solid rgba(16,185,140,.35); }
.dl-row__icon svg{ width: 18px; height: 18px; }
.dl-row__info{ flex: 1; min-width: 0; }
.dl-row__label{ font-size: 14.5px; font-weight: 600; }
.dl-row__size{ font-family: var(--font-mono); font-size: 11.5px; color: var(--text-3); }
.dl-btn{ flex: 0 0 auto; display: inline-flex; align-items: center; gap: 7px; padding: 9px 18px; border-radius: 999px; font-size: 13.5px; font-weight: 700; color: #043A2B;
  background: linear-gradient(135deg, #2AD0A2, #6BEBCC); transition: transform .25s var(--ease-spring), box-shadow .25s; text-decoration: none !important; }
.dl-btn:hover{ transform: translateY(-2px); box-shadow: 0 12px 26px -10px rgba(16,185,140,.6); }
.dl-btn svg{ width: 15px; height: 15px; }
.sheet__audio{ width: 100%; margin: 4px 0 6px; accent-color: var(--aqua); border-radius: 99px; }
.audio-hint{ font-size: 12.5px; color: var(--text-3); margin: 0 0 6px; }
.link-row{ display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-radius: var(--r-sm); background: rgba(108,92,231,.12); border: 1px solid rgba(108,92,231,.32);
  color: #4B3BC4; font-size: 14.5px; margin-bottom: 10px; }
.link-row svg{ width: 16px; height: 16px; }
.sheet__foot{ display: flex; gap: 12px; padding: 22px 30px 26px; flex-wrap: wrap; }

/* ---------- 提示 ---------- */
.toast{ position: fixed; left: 50%; bottom: calc(100px + env(safe-area-inset-bottom)); transform: translate(-50%, 16px); z-index: 95; padding: 12px 22px; border-radius: 999px;
  font-size: 14px; color: var(--text); opacity: 0; pointer-events: none; transition: opacity .35s, transform .35s var(--ease-spring);
  background: rgba(255,255,255,.96); border: 1px solid rgba(255,255,255,1); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); box-shadow: 0 20px 44px -20px rgba(31,47,92,.55); }
.toast.is-show{ opacity: 1; transform: translate(-50%, 0); }

/* ---------- 过场衔接（View Transitions） ---------- */
::view-transition-old(root){ animation: vtOut .34s cubic-bezier(.45,0,.55,1) both; }
::view-transition-new(root){ animation: vtIn .55s var(--ease-out) both; }
@keyframes vtOut{ to{ opacity: 0; transform: translateY(-14px) scale(.992); } }
@keyframes vtIn{ from{ opacity: 0; transform: translateY(18px) scale(.996); } }

/* ---------- 结构细节 ---------- */
.app--instant{ transition: none !important; filter: none !important; transform: none !important; }
html.noanim *, html.noanim *::before, html.noanim *::after{ animation: none !important; transition: none !important; }
html.noanim .grain{ display: none !important; }
.qcard, .work-card{ color: var(--text); text-decoration: none; }
.qcard:hover, .work-card:hover{ text-decoration: none; }
.qcard__media, .qcard__body, .qcard__title, .qcard__desc{ display: block; }
.qcard__go svg, .work-card__foot svg{ vertical-align: -2px; }
.ph__meta, .ph__title, .ph__sub{ display: block; }
.frame{ display: block; }
.frame__win{ display: block; }
.frame__date{ display: block; }
.diary-item{ display: flex; justify-content: center; width: 100%; background: none; border: 0; padding: 0; color: inherit; }
.stage-col{ position: relative; display: flex; flex-direction: column; align-items: center; gap: 14px; }
.stage-tip{ font-size: 12px; color: var(--text-3); letter-spacing: .12em; }
/* 翻页胶囊固定在屏幕下方（切换竖/横版照片时不会跟着上下跳）
   ⚠️ 必须挂在遮罩层上、不能放进有入场 transform 的面板里，否则动画期间会以面板为参照先出现在中间 */
.stage-nav-slot{ display: contents; }
/* 胶囊自己有进出：开场上浮入场，关场先于照片下沉消失（不拖泥带水） */
.stage-nav{ position: fixed; left: 50%; bottom: calc(26px + env(safe-area-inset-bottom)); z-index: 4;
  display: flex; align-items: center; gap: 12px; padding: 9px 14px; border-radius: 999px;
  background: linear-gradient(150deg, rgba(255,255,255,.82), rgba(255,255,255,.46) 55%, rgba(69,224,181,.22));
  border: 1px solid rgba(255,255,255,.92);
  -webkit-backdrop-filter: blur(20px) saturate(190%); backdrop-filter: blur(20px) saturate(190%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,1), inset 0 -10px 18px -10px rgba(69,224,181,.5),
    0 16px 34px -18px rgba(31,47,92,.5), 0 0 0 6px rgba(255,255,255,.16);
  opacity: 0; transform: translateX(-50%) translateY(16px);
  transition: opacity .2s ease, transform .24s var(--ease-out); }
.overlay--stage.is-open .stage-nav{ opacity: 1; transform: translateX(-50%) translateY(0); transition-delay: .1s; }
/* 闲置自动隐藏：给大照片让出整个屏幕，一动鼠标/手指就回来 */
.stage-nav-slot.pill-hide .stage-nav{ opacity: 0; transform: translateX(-50%) translateY(10px); pointer-events: none; }
.overlay--stage:not(.is-open) .stage-nav{ opacity: 0; transform: translateX(-50%) translateY(14px); transition: opacity .14s ease, transform .16s ease; }
.stage-nav .lb__count{ font-size: 13.5px; }
.sheet--nocover .sheet__inner{ margin-top: 0; }
.sheet__inner::-webkit-scrollbar{ width: 8px; }

/* ---------- 响应式 ---------- */
@media (max-width: 1080px){
  .masonry{ column-count: 2; }
  .diary-grid{ column-count: 2; }
}
@media (max-width: 760px){
  body{ font-size: 15.5px; }
  /* 左上角有返回按钮：标题要让开，否则"一起吃的饭"的"一起"会被按钮压住 */
  main{ padding-top: calc(88px + env(safe-area-inset-top)); }
  .masonry{ column-count: 1; }
  .works-grid{ grid-template-columns: 1fr; }
  /* 日记保持 1 列：它是"一篇一篇"的阅读节奏，2 列会太挤 */
  .diary-grid{ column-count: 1; }
  .diary-item{ margin-bottom: 30px; }
  .diary-item:nth-child(n) .frame{ transform: rotate(0deg); }
  /* 手机端：大图尽量占满可视区，别只占中间一小条。
     用 svh（小视口高度）避免移动浏览器地址栏伸缩导致的跳动。 */
  .overlay--lightbox{ padding: 10px 10px 0; align-items: flex-start; }
  .overlay--lightbox .overlay__panel{ height: 100%; display: flex; flex-direction: column; }
  /* 手机上让"图片 + 文字"作为一个整体居中，而不是各占一半留个大空档 */
  .overlay--lightbox .overlay__panel{ justify-content: center; }
  .lb__figure{ flex: 0 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center;
    width: 100%; max-width: 100%; margin: 0; overflow: hidden; }
  /* 用 dvh：flex 子项里的百分比高度解析不到父级 */
  .lb__figure img{ max-height: calc(100dvh - 250px); max-width: 100%; width: auto; height: auto;
    object-fit: contain; border-radius: 14px; }
  .lb__bar{ flex: 0 0 auto; flex-direction: column; align-items: flex-start;
    margin-top: 10px; padding-bottom: 78px; width: 100%; }
  .lb__title{ font-size: 16px; }
  .lb__caption{ font-size: 13px; }
  .stage-wrap{ flex-direction: column; gap: 26px; }
  .stage-wrap .frame{ width: fit-content; max-width: min(90vw, 520px); }
  .stage-wrap .frame__win img{ max-height: 56vh; }
  .letter{ width: min(330px, 84vw); }
  .overlay--sheet{ align-items: flex-end; padding: 0; }
  .overlay--sheet .overlay__panel{ transform: translateY(60px); border-radius: var(--r-lg) var(--r-lg) 0 0; }
  .overlay--sheet.is-open .overlay__panel{ transform: none; }
  .sheet__inner{ max-height: 78vh; padding-bottom: env(safe-area-inset-bottom); border-radius: var(--r-lg) var(--r-lg) 0 0; }
  .sheet__head, .sheet__body, .sheet__foot{ padding-left: 20px; padding-right: 20px; }
  .ov-btn{ height: 38px; font-size: 13px; padding: 0 13px; }
  .ov-btn--icon{ width: 38px; padding: 0; }
  .wall{ inset: -30%; }
  .enter-orb{ width: clamp(132px, 36vw, 168px); height: clamp(132px, 36vw, 168px); }
}
@media (max-width: 400px){
      .hero__welcome{ font-size: 30px; }
}

/* ---------- 尊重系统设置 ---------- */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{ animation-duration: .001s !important; animation-iteration-count: 1 !important; transition-duration: .15s !important; }
  html{ scroll-behavior: auto; }
  .aurora__blob, .grain{ animation: none !important; }
  .wall__track{ animation: none !important; }
  .enter-orb{ animation: none !important; }
  .tilt{ transform: none !important; }
}
@media (hover: none){
  .tilt::after{ display: none; }
  .ph::after, .ph__meta, .ph__note{ opacity: 1 !important; transform: none !important; }
  .ph::after{ background: linear-gradient(180deg, transparent 62%, rgba(5,9,18,.82)); }
}

/* ---------- 视图切换（瀑布流 / 网格）与回到顶部 ---------- */
.sec-head:has(.viewtoggle){ display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.sec-head:has(.viewtoggle) p{ margin: 0 0 8px; }
/* 日记页顶部控件组：顺序切换 + 视图切换并排放 */
.headtools{ display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.ordertoggle{ display: inline-flex; padding: 3px; border-radius: 999px; gap: 2px;
  background: rgba(255,255,255,.72); border: 1px solid rgba(255,255,255,.95);
  box-shadow: 0 10px 24px -18px rgba(31,47,92,.4); }
.ot-btn{ appearance: none; border: 0; background: none; cursor: pointer; font-family: inherit;
  font-size: 13px; font-weight: 600; color: var(--text-3); padding: 7px 14px; border-radius: 999px;
  transition: background .25s var(--ease-out), color .25s; white-space: nowrap; }
.ot-btn:hover{ color: var(--text-2); }
.ot-btn.is-on{ background: linear-gradient(135deg, #2AD0A2, #45E0B5); color: #043A2B; font-weight: 700;
  box-shadow: 0 8px 18px -10px rgba(16,185,140,.55); }
.diary-nodate{ color: var(--text-3); }
@media (max-width: 560px){
  .ot-btn{ font-size: 12.5px; padding: 6px 11px; }
  .headtools{ width: 100%; }
}

.viewtoggle{ display: inline-flex; gap: 4px; padding: 4px; border-radius: 999px; background: rgba(255,255,255,.78);
  border: 1px solid rgba(255,255,255,.95); box-shadow: var(--shadow); }
.vt-btn{ border: 0; background: transparent; padding: 7px 15px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  color: var(--text-2); cursor: pointer; transition: background .2s, color .2s; }
.vt-btn:hover{ color: var(--text); }
.vt-btn.is-on{ background: linear-gradient(135deg, #2AD0A2, #45E0B5); color: #043A2B; }
/* 网格模式：等高小图，一屏看很多，方便寻找 */
.diary-grid.as-grid, .masonry.as-grid{ column-count: auto; column-gap: 12px; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.diary-grid.as-grid .diary-item{ margin: 0; }
.diary-grid.as-grid .frame{ width: 100%; max-width: none; transform: none; }
.diary-grid.as-grid .frame:hover{ transform: translateY(-4px); }
.diary-grid.as-grid .frame__win{ aspect-ratio: 1 / 1; }
.diary-grid.as-grid .frame__win img{ width: 100%; height: 100%; object-fit: cover; }
.masonry.as-grid .ph{ break-inside: auto; margin: 0; }
.masonry.as-grid .ph img{ height: 100%; object-fit: cover; aspect-ratio: 1 / 1; }
.masonry.as-grid .ph::after{ opacity: 1; }
.masonry.as-grid .ph .ph__meta{ transform: none; opacity: 1; }
/* 回到顶部 */
.totop{ position: fixed; right: 20px; bottom: 108px; z-index: 45; width: 48px; height: 48px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.92); color: var(--text); display: grid; place-items: center; cursor: pointer;
  background: linear-gradient(150deg, rgba(255,255,255,.82), rgba(255,255,255,.46) 55%, rgba(69,224,181,.2));
  -webkit-backdrop-filter: blur(18px) saturate(190%); backdrop-filter: blur(18px) saturate(190%);
  box-shadow: inset 0 1px 0 #fff, 0 14px 30px -16px rgba(31,47,92,.5), 0 0 0 6px rgba(255,255,255,.16);
  transition: transform .25s var(--ease-spring); }
.totop svg{ width: 20px; height: 20px; }
.totop:hover{ transform: translateY(-3px); }
.totop[hidden]{ display: none; }
/* 摄影页分类的小标题里“看全部” */
.linklike{ border: 0; background: none; color: var(--aqua); cursor: pointer; font: inherit; padding: 0 0 0 10px; text-decoration: underline; text-underline-offset: 3px; }
.linklike:hover{ color: var(--aqua-bright); }

/* ---------- 作品在线试玩入口 ---------- */
.work-card__enter{ position: absolute; left: 12px; bottom: 12px; z-index: 2; padding: 7px 14px; border-radius: 999px;
  font-size: 12.5px; font-weight: 700; color: #043A2B; background: linear-gradient(135deg, #2AD0A2, #45E0B5);
  border: 1px solid rgba(255,255,255,.9); box-shadow: 0 10px 24px -12px rgba(6,58,43,.55); cursor: pointer;
  transition: transform .25s var(--ease-spring); }
.work-card__enter:hover{ transform: translateY(-2px) scale(1.03); }
.sheet__playbtn{ display: inline-flex; align-items: center; gap: 8px; margin: 0 0 16px; padding: 11px 22px; border-radius: 999px;
  font-size: 14.5px; font-weight: 700; color: #043A2B; text-decoration: none;
  background: linear-gradient(135deg, #2AD0A2, #45E0B5 60%, #8CE9F5); border: 1px solid rgba(255,255,255,.9);
  box-shadow: 0 16px 34px -18px rgba(6,58,43,.55); transition: transform .25s var(--ease-spring), box-shadow .25s; }
.sheet__playbtn:hover{ transform: translateY(-2px); }

/* 主页没有返回按钮，顶部不需要为它留白；hero 自身也收紧一些，
   否则欢迎语上方会空掉一大块，看起来像页面没加载完。 */
body.is-home main{ padding-top: calc(22px + env(safe-area-inset-top)); }
body.is-home .hero{ padding: clamp(4px, 1.6vh, 16px) 0 30px; }
@media (max-width: 760px){
  body.is-home main{ padding-top: calc(18px + env(safe-area-inset-top)); }
  body.is-home .hero{ padding: 6px 0 24px; }
  body.is-home .hero__note{ margin-top: 12px; }
  body.is-home .hero__wave{ margin-top: 16px; }
}

/* ---------- 手机端触摸目标不小于 44px ----------
   Apple HIG 与 Material 都建议可点区域 ≥44×44，
   低于这个尺寸在手指上很难点准（尤其返回键和筛选胶囊）。 */
@media (max-width: 760px){
  .filtertoggle{ height: 44px; padding: 0 16px 0 13px; }
  .vt-btn{ height: 44px; padding: 0 18px; }
  .backbtn{ width: 44px; height: 44px; }
  .ot-btn{ min-height: 44px; padding: 8px 15px; }
  .fpanel__chips .filter{ min-height: 40px; padding: 9px 14px; }
  .htab{ min-height: 48px; }
  .linklike{ padding: 8px 4px; }
}

/* ============================================================
   主页"可滚动余量"
   ------------------------------------------------------------
   主页内容刚好一屏高（scrollHeight === clientHeight），浏览器会认为
   "这页不能滚"，于是把任何向下手势都当成下拉刷新 —— 这就是从欢迎页
   点进摄影作品时，点第一张图会突然刷新的原因（只在第一次触发，
   因为进入照片页后页面能滚了）。
   这里给主页留 1px 的可滚动余量，手势就会被当作滚动消费掉。
   视觉上完全看不出来，但能彻底避免误触刷新。
   ============================================================ */
/* 用 min-height 而不是 padding-bottom：
   main 的 padding 简写会重置 padding-bottom，导致规则失效。 */
/* 首页不要硬撑到"一整屏 + 40px"：那样页脚（欢迎！/一起吃的饭）刚好落在首屏外面，
   得往下滑一点才看得见。留出页脚的位置，让它在首屏底部露出来。 */
body.is-home main{ min-height: calc(100dvh - 150px); }
body.is-home .footer{ padding-top: 14px; padding-bottom: 14px; }
@media (max-width: 760px){
  /* 手机上整行稍微往右挪一点，别贴着屏幕边 */
  body.is-home .footer{ padding-left: calc(var(--page-x) + 10px); }
}
body.is-home main{ padding-bottom: 0; }

/* ============================================================
   内页暂停背景动画
   ------------------------------------------------------------
   .aurora__blob 是 3 个 blur(60px) 的大色块，动画永远在跑。
   在照片/日记/作品页它几乎看不见（被内容盖住），
   却持续产生合成与重绘开销，是手机滚动卡顿的隐性来源。
   ============================================================ */
body.bg-paused .aurora__blob{ animation-play-state: paused; }
body.bg-paused .aurora{ will-change: auto; }

/* ============================================================
   一起吃的饭（2026-10-19）
   ============================================================ */

/* "第 N 顿"角标（饭局列表用） */
.meal-item{ position: relative; }
.meal-tag{
  position: absolute; left: 12px; top: 12px; z-index: 2;
  padding: 4px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 700;
  color: #043A2B; background: linear-gradient(135deg, #2AD0A2, #45E0B5);
  box-shadow: 0 8px 18px -10px rgba(16,185,140,.7);
}

/* ============================================================
   进入页的问答门禁
   ============================================================ */
.gate{
  position: fixed; inset: 0; z-index: 120;
  display: grid; place-items: center; padding: 24px;
  background: rgba(224,232,252,.55);
  -webkit-backdrop-filter: blur(18px) saturate(140%); backdrop-filter: blur(18px) saturate(140%);
  opacity: 0; transition: opacity .22s ease;
}
.gate.is-in{ opacity: 1; }
.gate__box{
  width: min(400px, 100%); padding: 26px 24px 22px;
  border-radius: var(--r-lg); background: rgba(255,255,255,.96);
  border: 1px solid rgba(255,255,255,.95);
  box-shadow: 0 30px 70px -30px rgba(31,47,92,.5);
  display: flex; flex-direction: column; gap: 14px;
}
.gate__q{ font-size: 17px; font-weight: 700; line-height: 1.6; }
/* 字号必须 ≥16px：iOS Safari 对 <16px 的输入框会自动放大整个页面，
   而且聚焦结束后不会缩回去（就是"输入密码后页面变大再也复原不了"的原因）。 */
.gate__input, .meal-lock__input, input[type="text"], input[type="password"], input[type="search"], textarea{
  font-size: 16px;
}
.gate__input{
  width: 100%; padding: 12px 14px; border-radius: 12px;
  border: 1px solid rgba(22,36,66,.18); background: #fff; color: var(--text);
}
.gate__input:focus{ outline: 2px solid rgba(16,185,140,.5); outline-offset: 1px; }
.gate__err{ font-size: 13px; color: var(--coral); margin-top: -6px; }
.gate__btns{ display: flex; gap: 10px; justify-content: flex-end; }
.gate__ok{ background: linear-gradient(135deg, #2AD0A2, #45E0B5); color: #043A2B;
  padding: 10px 24px; border-radius: 999px; font-weight: 700; }
.gate__cancel{ background: rgba(22,36,66,.06); color: var(--text-2);
  padding: 10px 20px; border-radius: 999px; }
@keyframes gateShake{ 0%,100%{ transform: translateX(0); } 20%{ transform: translateX(-7px); } 40%{ transform: translateX(6px); } 60%{ transform: translateX(-4px); } 80%{ transform: translateX(3px); } }
.gate__box.shake{ animation: gateShake .4s ease; }

@media (max-width: 760px){
}

/* ============================================================
   「一起吃的饭」相册解锁面板（2026-10-20）
   主站不需要密码，只有这个相册要。
   ============================================================ */
.meal-lock{
  max-width: 420px; margin: 40px auto 60px; padding: 34px 28px 30px;
  border-radius: var(--r-lg); text-align: center;
  background: rgba(255,255,255,.82); border: 1px solid rgba(255,255,255,.95);
  box-shadow: 0 30px 64px -34px rgba(31,47,92,.45);
  display: flex; flex-direction: column; align-items: center; gap: 12px;
}
.meal-lock__icon{ font-size: 34px; line-height: 1; }
.meal-lock__title{ font-size: 18px; font-weight: 800; }
.meal-lock__hint{ font-size: 13px; color: var(--text-2); margin: -4px 0 2px; }
.meal-lock__input{
  width: 100%; max-width: 300px; text-align: center;
  /* 输入内容显示为圆点（等价于密码框），但保留完整的中文输入能力 */
  -webkit-text-security: disc; text-security: disc;
}
.meal-lock__err{ font-size: 12.5px; color: var(--coral); }
.meal-lock__btn{
  margin-top: 4px; padding: 11px 30px; border-radius: 999px; font-weight: 700;
  background: linear-gradient(135deg, #2AD0A2, #45E0B5); color: #043A2B;
  border: none; cursor: pointer; font-size: 14.5px;
}
.meal-lock__btn:disabled{ opacity: .65; cursor: default; }
.meal-lock.shake{ animation: gateShake .4s ease; }

@media (max-width: 760px){
  .meal-lock{ margin: 24px 16px 44px; padding: 26px 20px 24px; }
}

/* 欢迎页底部的入口：比日记页那个更靠下、更像"页脚链接" */
@media (max-width: 760px){
}

/* ============================================================
   微信内置浏览器（X5 / WKWebView）兼容 — 2026-10-20
   现象：同一份代码 Safari 正常，微信里进入页发糊、开关大图闪白。
   原因：微信内核把"带 filter / backdrop-filter / will-change 的合成层"
        按低分辨率栅格化，再放大到屏幕（Safari 不会）。
   做法：微信下去掉这几类效果，用接近的纯色代替；不要为了好看加回去。
   ============================================================ */
html.is-wechat .overlay__scrim{
  -webkit-backdrop-filter: none; backdrop-filter: none;
  background: rgba(236, 241, 252, .97);
}
html.is-wechat .view{ animation: none; }
html.is-wechat .intro.is-leaving{ filter: none; }
html.is-wechat .app{ filter: none; }
/* 墙的合成层是"糊"的主要来源之一：让微信按普通层绘制 */
html.is-wechat .wall__track{ will-change: auto; }

/* ============================================================
   瀑布流：横向铺开（2026-10-20）
   原来用 CSS 多列是"竖着填"，照片一多就出现左边不动、右边一直加载；
   现在由 JS 按 i % 列数 分发，每列是一个 flex 容器，视觉上从左到右逐行铺。
   ============================================================ */
.msn{ display: flex; gap: 18px; align-items: flex-start; }
.msn__col{ flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 18px; }
.msn .ph{ margin: 0; }
.msn .diary-item{ margin: 0; }
@media (max-width: 1080px){
  .msn{ gap: 14px; }
  .msn__col{ gap: 14px; }
}
@media (max-width: 760px){
  .msn{ gap: 0; }
  .msn__col{ gap: 26px; }
}

/* 加密照片还没解开时：隐藏 alt 文字（否则相框里会显示"日记照片"），只留相纸底色 */
.frame__win img[data-enc]{ opacity: 0; }

/* 加密照片还没解开时先占好位置（4:5），否则卡片塌成一条、一次性挤进视口，
   解密任务全被触发，还会引发布局跳动。图片到了就移除这个类，按真实比例显示。 */
.frame.frame--enc .frame__win{ aspect-ratio: 4 / 5; background: #ece7dc; }

/* 饭局大图：遮罩直接画在 overlay 本身。
   之前遮罩是从 opacity 0 淡入的，打开的头一两帧会露出白色页面（就是那下闪白）；
   画在元素自身上，hidden=false 的第一帧就是深底，不再露白。 */
#stage.is-meals::before{ background: #EDF2FF; }
#stage.is-meals .overlay__scrim{ background: transparent; }

/* 饭局大图：面板不要从 opacity 0 淡入。
   浅色底 + 半透明面板的那几帧，看起来就是"整屏泛白一下"。 */
#stage.is-meals .overlay__panel{ opacity: 1; transform: none; transition: none; }

/* 屏幕不高时（手机横屏、小笔记本）：首页把卡片和留白收一点，
   保证「欢迎！/一起吃的饭」那一行仍落在首屏内，不用往下滑。 */
@media (max-height: 800px){
  body.is-home .hero{ padding: 0 0 14px; }
  body.is-home .hero__note{ margin-top: 8px; }
  body.is-home .hero__wave{ margin-top: 8px; }
  body.is-home .hpanel .qcard__media{ aspect-ratio: 16 / 9; }
}
