/* 全站唯一字体：fonts/MyRegular.ttf（阿里巴巴普惠体 2.0 55 Regular）。
   声明放在 style.css 而不是 fonts/nss.css：这个文件带构建指纹（?v=时间戳），
   换字体后 WebView 一定会重新拉；nss.css 不带指纹，改动容易被旧缓存吃掉。
   只声明 400 一档 —— 需要更粗的地方由浏览器合成，层级仍在，
   也不会因为缺字重退回系统字体（那个看起来会像「字体没生效」）。 */
@font-face{
  font-family:'My Regular';
  font-weight:400;
  font-style:normal;
  font-display:swap;
  src:url('../fonts/MyRegular.ttf') format('truetype');
}

:root{
  /* 全站字体统一为 fonts/MyRegular.ttf（阿里巴巴普惠体 2.0 55 Regular）。
     三个语义变量都指向它：标题/正文、控件、数据（日期/计数）不再分家。
     老字体族留在后面只是兜底 —— 字体没加载出来时仍有中文字形，不会掉成方框。 */
  --font-serif:"My Regular","Noto Serif SC","Source Han Serif SC","Songti SC","STSong",serif;
  --font-sans:"My Regular","PingFang SC","HarmonyOS Sans SC","Noto Sans SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  --font-mono:"My Regular",ui-monospace,"SF Mono","JetBrains Mono",Menlo,Consolas,monospace;
  --ink:#1c1c1e;
  --ink-2:rgba(60,60,67,.58);
  --ink-3:rgba(60,60,67,.34);
  --ink-3-solid:#c2c2c6;
  /* 图标专用实色：正文用 --ink-2(.58)/--ink-3(.34) 这套半透明是柔和的，
     但 1.5px 细线图标在「半透明 + 抗锯齿」下会发虚、像褪了色的灰描边。
     这两个值就是它们落在白底上的等效合成色，换成实色后线条才实。 */
  --icon-2:#8e8e93;
  --icon-3:#bcbcc1;
  --accent:#b04a2c;
  /* 主题红的三个分身：文字/描边用 --accent，半透明描边用 --accent-rgb（夜间会跟着变浅），
     实心填充（气泡、红底按钮）用 --accent-fill——深色底上要配白字，不能跟着提亮 */
  --accent-rgb:176,74,44;
  --accent-fill:#b04a2c;
  /* 危险色（删除/清空/注销）：与主题红同属暖赭一家，不再各写一个红 */
  --danger:#a8392b;
  --danger-fill:#b8392b;
  --danger-rgb:184,57,43;
  --card-bg:#ffffff;
  --card-border:rgba(28,28,30,.07);
  --card-shadow:0 3px 16px -8px rgba(30,30,70,.14),0 1px 2px rgba(30,30,70,.04);
  /* 底部悬浮件（回收站/作品集/清空数据的胶囊、主页底部导航、预览页操作条、
     更多弹窗、反馈页按钮）统一用的柔和投影：原来的
     0 16px 34px -22px rgba(0,0,0,.45) 那种重投影全收淡成这一档 */
  --float-shadow:0 10px 28px -14px rgba(28,28,30,.22), 0 2px 8px -2px rgba(28,28,30,.08);
  --panel-bg:#f7f7f9;
  --panel-border:rgba(28,28,30,.08);
  --page-bg:#f8f9fb;
  /* 行间分隔线：0.5px + 极低对比——1px/.08 在手机上会显成一道"粗黑线"，
     这里统一成半像素浅灰，夜间由 night-font.css 换成低透明度白 */
  --hairline:.5px solid rgba(28,28,30,.06);
  /* 底部导航未选中图标：比 --ink-3-solid(#c2c2c6) 压一档，白底上才看得清 */
  --tab-idle:#9c9ca3;
  /* 字号缩放系数（0.85~1.25）：实际值由 js/night-font.js 按用户设置写到 .device 上，
     这里给兜底默认 1，night-font.css 缺失时 font-size 的 calc 也不会失效 */
  --fs:1;
  /* 回形针（模板装饰用）：细长金属丝，非方形 */
  --clip-img:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 66'%3E%3Cpath d='M8.6 58.5V15.4a5.7 5.7 0 0 1 11.4 0v32.8a4.2 4.2 0 0 1-8.4 0V22.6' fill='none' stroke='%235c5750' stroke-width='3.4' stroke-linecap='round'/%3E%3Cpath d='M8.6 58.5V15.4a5.7 5.7 0 0 1 11.4 0v32.8a4.2 4.2 0 0 1-8.4 0V22.6' fill='none' stroke='%23ded9cf' stroke-width='1.1' stroke-linecap='round'/%3E%3C/svg%3E");
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html,body{height:100%}
body{
  background:var(--page-bg);
  font-family:var(--font-serif);color:var(--ink);
  -webkit-font-smoothing:antialiased;overflow:hidden;overscroll-behavior:none;
}
/* 全屏外壳：直接铺满视口，不再套手机模型（无外框 / 无圆角 / 无外投影）
   --app-h 由 JS 锁成「键盘没弹时的窗口高度」：触屏上键盘弹出会改变视口高度，
   外壳跟着缩就会把底部导航顶到键盘上方，锁住高度后整页不再被压缩 */
.device{
  position:fixed;top:0;left:0;
  width:100%;height:100vh;height:var(--app-h,100dvh);
  overflow:hidden;
  background:var(--page-bg);
  transition:background .35s;
}
/* 内容列：手机上铺满整屏；平板上收成一列居中。
   宽度上限同时把 cqw/cqh 的基准锁在设计尺度附近，避免平板被 2 倍放大 */
.screen{
  position:relative;
  width:100%;max-width:560px;height:100%;
  margin:0 auto;
  overflow:hidden;
  container-type:size;
}
/* 大屏把整屏背景与内容列分层：列外留白呼吸，列内仍是原来的排版尺度 */

/* 全局禁选字，但必须把输入框排除在规则之外 —— 只靠后面再补一条 input{user-select:text}
   不够：Android WebView 里只要 input/textarea 被这条通配规则命中过，就会出现
   「点中间落不了光标、打出来的字总接在末尾」（光标钉在最后一位）。
   用 :not() 从源头绕开，输入框走浏览器默认值。 */
*:not(input):not(textarea):not([contenteditable]){
  -webkit-user-select:none;
  -moz-user-select:none;
  user-select:none;
  -webkit-touch-callout:none;
}
input,textarea,[contenteditable]{
  -webkit-user-select:text;
  -moz-user-select:text;
  user-select:text;
  -webkit-touch-callout:default;
  /* 输入框只吃点按/滚动手势：祖先写了 touch-action:none 时（取交集）也不至于把
     点按定位光标一起禁掉 */
  touch-action:manipulation;
  /* 光标颜色：跟主题赭色一致，不用系统默认的蓝。
     caret-color 是 Blink 自己画的（WebView 里的 input 是网页元素，不是原生 EditText），
     所以这一条就能管住闪烁的那根竖线。 */
  caret-color:var(--accent);
}
/* 选中文本的底色：系统默认那块蓝紫在暖白底上很跳，改成主题赭色的淡染。
   --accent-rgb 夜间会翻成浅橙（.device.night 那组变量），所以日夜自动各归其位。
   color 一并定死：Android 上选中文字颜色会被系统改写成「高亮底色上的对比色」，
   不锁死的话白天可能出现浅字压浅底。 */
::selection{
  background:rgba(var(--accent-rgb),.22);
  color:var(--ink);
}

.bg-layer{position:absolute;inset:-8%;overflow:hidden;background:var(--page-bg);transition:background .35s}
.blob{display:none}
.page{
  position:absolute;inset:0;z-index:10;display:flex;flex-direction:column;
  opacity:0;visibility:hidden;pointer-events:none;
  /* 页面必须是实心卡片：推入/推出时新页盖住旧页滑动，
     否则两页都是透明底，内容互相透视叠加，看起来就是「内部元素各动各的」 */
  background:var(--page-bg);
  transition:opacity .3s ease,visibility .3s;
}
.page.active{opacity:1;visibility:visible;pointer-events:auto}

/* ===== 二级页推入 / 推出（js/app.js 的 navSwap 挂这两个类） =====
   飞行的两页都必须保持可见：离开的那页已经摘掉 .active，默认 opacity:0
   会让它当场消失，位移也就看不见了。动画期间不吃点击，避免半路上误触。 */
.page.nav-leaving,
.page.nav-entering{opacity:1;visibility:visible;pointer-events:none}
/* 飞行两页都提升为合成层：transform + filter 都走合成器，动画期间不触发整页重绘 */
.page.nav-leaving,
.page.nav-entering{will-change:transform,filter}

/* 返回 tab 页的瞬间，底栏不播自己的滑入（见 js/app.js navSwap）。
   .tabbar.on 在文件后面也写了 transition，同权重会盖掉这条，所以带上 .on 一起压 */
.tabbar.nav-snap,
.tabbar.on.nav-snap{transition:none}

#page-batch{z-index:45}

/* ===== 滚动回弹的「弹回」过渡 =====
   列表 / 日期滚轮触顶触底被拉出去后，由 js/app.js 的 touch 通道挂这个类弹回原位；
   位移本身写在元素 inline transform 上，这里只管回弹曲线（带回一点点过冲） */
.rb-bounce{transition:transform .46s cubic-bezier(.22,1.12,.36,1) !important}

.eyebrow{font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));letter-spacing:.36em;color:var(--accent);margin-bottom:1.6cqh}
.sub{margin-top:1.3cqh;font-size:calc(clamp(11px,2.9cqw,13px) * var(--fs));color:var(--ink-2);letter-spacing:.16em}

/* ===== 首页顶部菜单栏 ===== */
/* 左上角一行小字眉标：等宽、字距拉开、点缀色（与测试页同款） */
.greeting{
  margin:0;
  font-family:var(--font-mono);
  font-size:calc(12px * var(--fs));
  font-weight:400;
  letter-spacing:.42em;
  line-height:1;
  color:var(--accent);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
  min-width:0;
}
.topbar{
  flex:0 0 auto;
  position:relative;
  z-index:30;
  padding:calc(0px + 16px) 5cqw 8px;   /* 底边距 0→8：菜单栏与内容再拉开一点 */
  /* 不透明底：列表触底回弹时整列会被拉上来，从顶栏底下穿过——
     顶栏没底色时日期按钮/切换组半透明的底就会透出下面的照片，像变透明了。
     补上与页面同色的实底（夜间 --page-bg 由 night-font.css 换成 #121212），
     穿上来的内容会被顶栏遮住，不再透出 */
  background:var(--page-bg);
}
.topbar-normal{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:3cqw;
}
.view-tabs{
  flex:1;min-width:0;
  display:flex;align-items:center;justify-content:space-between;gap:3cqw;
  margin-top:28px;   /* 18→28：与搜索按钮行拉开，防止点搜索误触到「照片墙」 */
  padding-bottom:12px;
}
/* 时光轴 / 照片墙：两枚圆形按钮，落在一条浅灰胶囊底板上（原来是无底色的下划线切换） */
.vs-group{
  position:relative;
  display:flex;align-items:center;gap:2px;margin-left:auto;
  padding:3px;
  background:rgba(28,28,30,.055);
  border-radius:999px;
  transition:background .35s;
}
/* 白色圆块做成独立滑块：切换时横向滑过去，而不是两个按钮各自淡入淡出 */
.vs-pill{
  position:absolute;left:0;top:3px;
  height:30px;width:0;
  border-radius:999px;
  background:#fff;
  box-shadow:0 1px 3px rgba(30,30,70,.10),0 1px 1px rgba(30,30,70,.04);
  pointer-events:none;
  will-change:transform,width;
  transition:transform .42s cubic-bezier(.22,1,.36,1),width .42s cubic-bezier(.22,1,.36,1),background .35s,box-shadow .35s;
}
@media (prefers-reduced-motion:reduce){
  .vs-pill{transition:background .35s,box-shadow .35s}
}
.view-tabs .vs-btn{
  position:relative;z-index:1;
  appearance:none;border:none;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  height:30px;padding:0 15px;
  background:none;border-radius:999px;
  font-family:var(--font-serif);font-size:calc(13.5px * var(--fs));font-weight:600;
  letter-spacing:.12em;line-height:1;color:rgba(60,60,67,.42);
  transition:color .26s;
}
.view-tabs .vs-btn span{position:relative;z-index:1}
.view-tabs .vs-btn.active{color:var(--ink)}
.view-tabs .vs-btn:active{color:var(--ink)}
/* 列表 ↔ 照片墙 切换：旧视图淡出 → 加载提示 → 新视图逐条入场（同 加载动画.html 的时序） */
#page-home .view-out{
  opacity:0;transform:translateY(6px);
  transition:opacity .18s ease,transform .2s ease;
}
#page-home .view-waiting{opacity:0;transition:none}
/* 切换后内容逐条错峰上浮（--st-i 由 JS 写入，最多 10 级） */
#page-home .view-stagger > *{
  animation:viewItemIn .42s cubic-bezier(.22,1,.36,1) both;
  animation-delay:calc(var(--st-i, 0) * 45ms);
}
@keyframes viewItemIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
/* 加载指示器：滑动短条 + 等宽小字 */
.view-loader{
  position:absolute;left:50%;top:42%;z-index:20;
  display:flex;flex-direction:column;align-items:center;gap:14px;
  opacity:0;pointer-events:none;
  transform:translate(-50%,calc(-50% + 8px));
  transition:opacity .2s ease,transform .3s cubic-bezier(.22,1,.36,1);
}
.view-loader.on{opacity:1;transform:translate(-50%,-50%)}
.vl-bar{
  position:relative;display:block;width:56px;height:2px;
  background:rgba(28,28,30,.08);overflow:hidden;
}
.vl-bar::after{
  content:'';position:absolute;top:0;left:0;
  width:44%;height:100%;background:var(--accent);
  animation:loaderSlide .92s cubic-bezier(.45,0,.55,1) infinite;
}
@keyframes loaderSlide{0%{transform:translateX(-110%)}100%{transform:translateX(240%)}}
.vl-text{
  font-family:var(--font-mono);font-size:calc(9.5px * var(--fs));
  letter-spacing:.32em;text-indent:.32em;
  color:var(--ink-3);white-space:nowrap;
}
#page-home.view-wall .timeline{display:none}
#page-home:not(.view-wall) .wall-scroll{display:none}

/* =====================================================
   日历视图：菜单栏 + 月历 + 当天的回忆
   ===================================================== */
.cal-scroll{
  flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;
  position:relative;   /* 快照层 / 吸顶元素的定位基准 */
  padding:0 5cqw calc(92px + 0px);
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
.cal-scroll::-webkit-scrollbar{display:none}

/* 菜单栏：左「月日 + 年」，右「今天」——吸顶固定，不跟着内容滚走
   背景与 .bg-layer 同色（日间纯白 / 夜间深黑），不能有可见色差 */
.cal-bar{
  position:sticky;top:0;z-index:6;
  margin:0 -5cqw;   /* 背景铺满整行，盖住两侧滚过的内容 */
  padding:calc(0px + 3.4cqh) 5cqw 1.6cqh;
  display:flex;align-items:center;justify-content:space-between;gap:3cqw;
  background:var(--page-bg);   /* 吸顶元素必须有底色，否则列表滚过时透出来 */
}
.cal-md{
  display:flex;align-items:baseline;gap:1.8cqw;
  background:none;border:none;padding:0;cursor:pointer;
  font-family:var(--font-serif);color:var(--ink);
}
.cal-md b{
  font-size:calc(clamp(22px,6.2cqw,27px) * var(--fs));font-weight:600;
  letter-spacing:.04em;line-height:1;color:var(--ink);
  transition:opacity .2s;
}
.cal-md.is-pick b{font-weight:600;letter-spacing:.08em}
.cal-md.is-pick span{display:none}   /* 年视图里大字就是年份，右边小年份不再重复 */
.cal-md span{
  font-family:var(--font-mono);font-size:calc(clamp(10px,2.6cqw,11.5px) * var(--fs));
  letter-spacing:.14em;color:var(--ink);
}
.cal-today{
  display:inline-flex;align-items:center;justify-content:center;
  width:30px;             /* 固定尺寸：不随屏宽缩放，里面的号数字号才始终一致 */
  height:30px;
  padding:0;
  margin:0;
  background:none;border:none;cursor:pointer;
  color:var(--ink);       /* 跟主题走：夜间翻白（写死 #000 在深底上看不见） */
  align-self:center;      /* 纵向和左侧同一中线 */
  flex:0 0 auto;          /* 不被压缩 */
  transition:transform .28s cubic-bezier(.34,1.56,.64,1), opacity .2s;
}
.cal-today svg{
  width:100%;height:100%;
  fill:none;
  stroke:var(--ink);
  stroke-width:1.5;
  stroke-linecap:round;
  stroke-linejoin:round;
}
.cal-today svg text{
  fill:var(--ink);
  stroke:none;
  font-family:var(--font-mono);
  font-weight:600;
  font-size:calc(10px * var(--fs));                 /* viewBox 单位：30px 实际渲染 ≈ 10px，恒定 */
  font-variant-numeric:tabular-nums;
  dominant-baseline:central;     /* 垂直居中在方框正中 */
}
.cal-today.is-now{opacity:1}
.cal-today:active{transform:scale(.92)}

/* 星期表头 */
.cal-wd{display:grid;grid-template-columns:repeat(7,1fr);padding:.6cqh 0 1.2cqh}
.cal-wd span{
  text-align:center;
  font-family:var(--font-mono);font-size:calc(clamp(11.5px,3cqw,13px) * var(--fs));
  letter-spacing:.1em;color:var(--ink-3);
}

/* 星期头 + 周历/月历 + 把手包成一个吸顶组，两种模式都钉在菜单栏下面——
   展开时日历固定不动、只有列表滚；把手长在日历正下方，随折叠/展开一起动 */
.cal-scroll:not(.picking) .cal-head{
  position:sticky;z-index:4;
  top:var(--cal-bar-h, 0px);
  /* 负 margin 撑满整行 + 内 padding 还原：底色才能盖住两侧滚过的列表内容 */
  margin:0 -5cqw;padding:0 5cqw;
  background:var(--page-bg);
}

/* 日期格：外层裁剪高度（周条 = 一行），内层网格整体位移产生上滑动画
   （拖动时由 JS 冻结过渡跟手，松手 snap 用短促的快出缓入曲线） */
.cal-cells-wrap{
  overflow:hidden;
  transition:height .34s cubic-bezier(.33,1,.68,1);   /* 换月行数变化：柔和高out缓动，避免生硬撑开 */
}
.cal-cells{
  display:grid;grid-template-columns:repeat(7,1fr);
  touch-action:pan-y;   /* 纵向交给原生滚动；收起/展开手势由 JS 按需 preventDefault 接管 */
  transition:transform .26s cubic-bezier(.22,1,.36,1);
}

/* 三面板滑动轨道（月/周 与 年视图共用，参考「滑动切换.html」）：
   上一页/当前页/下一页常驻真内容，拖动整条轨道跟手（端外阻尼），
   松手按阈值/速度翻页，动画完成后重渲染三块并无缝复位 */
.cal-track{
  display:flex;
  will-change:transform;
  touch-action:pan-y;   /* 纵向交给原生滚动，横向由 JS 接管 */
}
.cal-panel{flex:0 0 100%;min-width:0}

/* 日历与列表之间的把手：同一位置二选一（绝对定位重叠居中）——
   展开时只显示短横条；折叠后只显示朝下的箭头（路径原生朝下，不旋转）。
   把手在吸顶组内、日历正下方，随折叠/展开一起移动 */
.cal-grip{
  display:block;position:relative;
  height:14px;   /* 收紧：横条作为日历视图的收尾，贴紧日历格底边 */
}
.cal-grip-bar{
  position:absolute;left:50%;top:50%;
  width:22px;height:3.5px;border-radius:3px;
  transform:translate(-50%,-50%);
  background:rgba(28,28,30,.16);
  transition:opacity .18s ease;
}
.cal-grip-arrow{
  position:absolute;left:50%;top:50%;
  display:block;width:24px;height:9px;
  transform:translate(-50%,-50%);
  fill:none;stroke:#c4c4c8;stroke-width:4.5;   /* 原 rgba(28,28,30,.26)：半透明在卡片上会透底，换成等效实色 */
  stroke-linecap:round;stroke-linejoin:round;
  opacity:0;transition:opacity .18s ease;
}
.cal-scroll.is-week .cal-grip-bar{opacity:0}
.cal-scroll.is-week .cal-grip-arrow{opacity:1}
.cal-scroll.picking .cal-grip{display:none}
.cal-cell{
  position:relative;aspect-ratio:1/1;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.9cqw;
  background:none;border:none;padding:0;cursor:pointer;
}
.cal-cell::before{
  content:'';position:absolute;left:50%;top:50%;
  width:clamp(33px,9cqw,40px);height:clamp(33px,9cqw,40px);
  margin-left:calc(-1 * clamp(33px,9cqw,40px) / 2);
  margin-top:calc(-1 * clamp(33px,9cqw,40px) / 2);
  border-radius:50%;background:var(--ink);
  opacity:0;transform:scale(.82);
  transition:opacity .22s,transform .26s cubic-bezier(.22,1,.36,1);
}
.cal-cell.sel::before{opacity:1;transform:scale(1)}
/* 选中圈弹出动画只在「点了这一天」时重播（JS 加 .just-picked）；
   换月/换周重渲染不再重播，否则选中日期每次都闪跳 */
.cal-cell.sel.just-picked::before{animation:calSelPop .34s cubic-bezier(.22,1,.36,1)}
@keyframes calSelPop{from{opacity:0;transform:scale(.55)}to{opacity:1;transform:scale(1)}}
.cal-num{
  position:relative;z-index:1;
  font-family:var(--font-serif);font-size:calc(clamp(14px,3.9cqw,16.5px) * var(--fs));
  font-variant-numeric:tabular-nums;line-height:1;
  color:var(--ink-3);transition:color .22s;
}
/* 农历 / 节假日：节假日用主题红，普通农历浅灰 */
.cal-lunar{
  position:relative;z-index:1;
  font-size:calc(clamp(8px,2.15cqw,10px) * var(--fs));
  font-style:normal;
  line-height:1;letter-spacing:.03em;white-space:nowrap;
  color:var(--ink-3);transition:color .22s;
}
.cal-lunar.is-fest{color:var(--ink-2)}
/* 节气：比农历略深一档，但不用节日红 */
.cal-lunar.is-term{color:var(--ink-2)}
.cal-cell.has .cal-num{color:var(--ink-2)}
.cal-cell.today .cal-num{color:var(--accent);font-weight:600}
.cal-cell.sel .cal-num{color:var(--card-bg)}
.cal-cell.sel.today .cal-num{color:var(--card-bg)}
.cal-dot{
  position:absolute;left:50%;margin-left:-2px;bottom:6%;
  width:4px;height:4px;border-radius:50%;background:var(--accent);
  transition:background .22s;
}
/* 周条里不属于本月的日期标淡 */
.cal-cell.dim .cal-num{opacity:.4}
.cal-cell.dim .cal-lunar{opacity:.45}
.cal-cell.dim .cal-dot{opacity:.4}
/* 选中态：农历跟着反白 */
.cal-cell.sel .cal-lunar{color:var(--card-bg)}
.cal-cell.sel .cal-lunar.is-fest{color:var(--card-bg)}
.cal-cell.sel.today .cal-num{color:var(--card-bg)}
.cal-cell.sel.today .cal-lunar{color:var(--card-bg)}

/* 月 ↔ 年视图切换：淡入上浮（只用 opacity + translateY：
   不能用 scale，缩放会让轨道复位时量到的视口宽度偏小，日期整格错开几像素） */
.cal-anim-pop{animation:calPop .32s cubic-bezier(.22,1,.36,1)}
@keyframes calPop{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* ===== 月 ↔ 年 切换：两段式（旧视图缩放退场 → 新视图轻微放大入场） =====
   月 → 年：月历缩小淡出，下面的回忆列表被向下推开；年视图从略小放大就位
   年 → 月：年视图缩小淡出；月历从略小放大就位（方向相反） */
.cal-cells-wrap.cal-month-out{animation:calMonthOut .26s cubic-bezier(.4,0,.6,1) both}
@keyframes calMonthOut{to{opacity:0;transform:scale(.94)}}
.cal-day.cal-day-push{
  opacity:0;transform:translateY(46px);
  transition:opacity .24s ease,transform .3s cubic-bezier(.4,0,.6,1);
}
.cal-picker.cal-year-out{animation:calYearOut .24s cubic-bezier(.4,0,.6,1) both}
@keyframes calYearOut{to{opacity:0;transform:scale(.955)}}
.cal-picker.cal-year-in{animation:calYearIn .34s cubic-bezier(.22,1,.36,1) both}
@keyframes calYearIn{from{opacity:0;transform:scale(.965) translateY(10px)}to{opacity:1;transform:none}}
.cal-cells-wrap.cal-month-in{animation:calMonthIn .34s cubic-bezier(.22,1,.36,1) both}
@keyframes calMonthIn{from{opacity:0;transform:scale(.965) translateY(10px)}to{opacity:1;transform:none}}

/* 年视图：轨道视口装着 上一年/本年/下一年 三块面板（左右滑换年） */
.cal-picker{
  display:none;
  overflow:hidden;      /* 轨道视口 */
  touch-action:pan-y;   /* 年视图可能超高要能竖滚，横向滑动手势自接 */
}
.cal-scroll.picking .cal-wd,
.cal-scroll.picking .cal-cells-wrap,
.cal-scroll.picking .cal-cells,
.cal-scroll.picking .cal-day{display:none}
.cal-scroll.picking .cal-picker{display:block}
/* 年视图轨道面板：接管原 .cal-picker 的三列网格布局；
   面板之间留一道空隙，滑动时上一/下一年不会贴在一起（JS 的步进 = 面板宽 + 间隙） */
.cal-picker .cal-track{column-gap:6.5cqw}
.cal-picker .cal-panel{
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:1.2cqw;padding:.6cqh 0 2cqh;
}
.cal-mini{
  display:flex;flex-direction:column;gap:.9cqh;
  background:var(--card-bg);border:1px solid var(--card-border);
  border-radius:10px;
  padding:1.4cqw;cursor:pointer;text-align:left;
  transition:border-color .24s;
}
.cal-mini b{
  font-family:var(--font-serif);font-weight:400;
  font-size:calc(clamp(11px,2.9cqw,12.5px) * var(--fs));letter-spacing:.1em;color:var(--ink-2);
  padding:.3cqw .4cqw 0;
}
.cal-mini.on{border-color:rgba(var(--accent-rgb),.5)}
.cal-mini.on b{color:var(--accent)}
.cal-mini:active{background:var(--panel-bg)}
.cal-mgrid{display:grid;grid-template-columns:repeat(7,1fr);gap:.4cqw .2cqw}
.cal-mgrid i{
  font-style:normal;text-align:center;
  font-family:var(--font-mono);font-size:calc(clamp(6.5px,1.75cqw,7.5px) * var(--fs));
  line-height:1.8;color:var(--ink-3);font-variant-numeric:tabular-nums;
}
.cal-mgrid i.has{color:var(--accent);font-weight:600}
/* 年视图里的日期激活：圆形（今天是红圆，不再是方块） */
.cal-mgrid i.today{
  background:var(--accent);color:var(--card-bg);
  width:clamp(11px,3.1cqw,13px);height:clamp(11px,3.1cqw,13px);
  line-height:clamp(11px,3.1cqw,13px);
  border-radius:50%;justify-self:center;align-self:center;
}

/* 所选这天：回忆列表（不要分隔线） */
.cal-day{
  margin-top:2.4cqh;padding-top:1.8cqh;   /* 日历与列表之间留出明显间距，横条归属日历一侧 */
  transition:opacity .18s ease, transform .18s ease;
}
/* 数据加载（参考「数据加载动画.html」）：旧列表先淡出下移，重建后淡入，
   条目再逐条错峰上浮——不再整块「啪」地换内容 */
.cal-day.is-leaving{opacity:0;transform:translateY(6px)}
.cal-mem{
  animation:calItemIn .34s cubic-bezier(.22,.8,.3,1) both;
  animation-delay:calc(var(--i, 0) * 38ms);
}
@keyframes calItemIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
/* 「这天还没有回忆」不参与入场动画：切换月份时直接出现，避免文字先淡入再被替换 */
.cal-day-head{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:.6cqh}
.cal-day-head b{
  font-family:var(--font-serif);font-weight:400;
  font-size:calc(clamp(11px,2.9cqw,12.5px) * var(--fs));letter-spacing:.16em;color:var(--ink-2);
}
.cal-day-head span{
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.1em;color:var(--ink-3);
}
.cal-none{
  padding:3.4cqh 0 1cqh;text-align:center;
  font-size:calc(clamp(11px,2.9cqw,13px) * var(--fs));letter-spacing:.1em;color:var(--ink-3);
}
.cal-mem{
  display:flex;align-items:center;gap:3.4cqw;width:100%;
  padding:1.8cqw 0;background:none;border:none;cursor:pointer;text-align:left;
}
.cal-mem + .cal-mem{border-top:1px solid rgba(28,28,30,.05)}
.cal-thumb{
  position:relative;flex:0 0 auto;
  width:15cqw;height:15cqw;max-width:64px;max-height:64px;
  overflow:hidden;background:rgba(28,28,30,.05);
}
.cal-thumb .photo-img{position:absolute;inset:0}
.cal-thumb .stroke-layer{position:absolute;inset:0;width:100%;height:100%}
.cal-mtext{flex:1;min-width:0}
.cal-cap{
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  font-size:calc(clamp(12px,3.1cqw,14px) * var(--fs));letter-spacing:.07em;line-height:1.6;color:var(--ink);
}
.cal-loc{
  display:block;margin-top:.5cqw;
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.1em;color:var(--ink-3);
}

/* 那年今日：悬浮在顶栏正下方、盖在列表之上（按 测试.html 的做法）
   点开就是那天的回忆；左右滑均可关闭。关闭后列表顶部预留的空白一并收回 */
.anniv{
  position:absolute;
  top:100%;
  left:20px;
  right:20px;
  z-index:30;
  display:none;
  align-items:center;
  margin:8px 0 0;
  max-height:88px;
  overflow:hidden;
  background:var(--card-bg);
  border:1px solid var(--card-border);
  box-shadow:0 12px 30px -18px rgba(40,35,30,.5),
             0 2px 8px -4px rgba(40,35,30,.12);
  touch-action:pan-y;
  -webkit-user-select:none;user-select:none;
  -webkit-touch-callout:none;
  will-change:transform,opacity;
  transition:max-height .32s cubic-bezier(.22,1,.36,1),
             opacity .24s, margin .32s,
             transform .26s cubic-bezier(.22,1,.36,1),
             border-width .3s, box-shadow .3s;
}
.anniv.on{display:flex;animation:anniIn .5s cubic-bezier(.22,1,.36,1) both}
@keyframes anniIn{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
.anniv.drag{transition:none}
.anniv.gone{
  max-height:0;opacity:0;margin-top:0;
  border-top-width:0;border-bottom-width:0;box-shadow:none;
}
.anni-main{
  display:flex;align-items:center;gap:12px;width:100%;
  padding:10px;
  background:none;border:none;cursor:pointer;text-align:left;
}
.anni-thumb{
  position:relative;
  flex:0 0 auto;width:48px;height:48px;
  background-color:var(--panel-bg);
  background-size:cover;background-position:center;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.14);
}
.anni-body{display:flex;flex-direction:column;gap:5px;min-width:0}
.anni-kicker{
  font-family:var(--font-mono);font-size:calc(9px * var(--fs));
  letter-spacing:.14em;color:var(--accent);
}
.anni-cap{
  font-family:var(--font-serif);
  font-size:calc(13.5px * var(--fs));
  font-weight:500;
  letter-spacing:.04em;
  line-height:1.3;
  color:var(--ink);
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}

.year-btn{
  display:inline-flex;
  align-items:center;
  gap:5px;
  height:30px;
  padding:0 13px;
  background:rgba(28,28,30,.055);   /* 与右侧胶囊底板同色：一枚独立的浅灰圆形按钮 */
  border:none;
  border-radius:999px;
  cursor:pointer;
  font-family:var(--font-serif);
  font-size:calc(13.5px * var(--fs));
  font-weight:600;
  letter-spacing:.1em;
  color:var(--ink-2);
  line-height:1;
  transition:color .2s,background .35s;
  /* year-label 由 JS 填充：先占住年份的宽度，避免闪现占位文字和填充后的布局跳动 */
  min-width:calc(3.6em + 22px);
}
.year-btn:active{color:var(--ink);background:rgba(28,28,30,.1)}
.year-btn svg{
  width:11px;
  height:11px;
  margin-top:1px;
  stroke:currentColor;
  fill:none;
  stroke-width:1.9;
  stroke-linecap:round;
  stroke-linejoin:round;
  transition:transform .32s cubic-bezier(.22,1,.36,1);
}
.year-btn.is-open svg{transform:rotate(-180deg)}

/* ===== 右上角搜索按钮（按 测试.html 的 .hd-icon） ===== */
.top-search-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  flex:0 0 auto;
  width:38px;
  height:38px;
  margin:-8px -9px -8px 0;
  padding:0;
  background:none;
  border:none;
  cursor:pointer;
  color:var(--icon-2);
  transition:color .2s,transform .2s;
}
.top-search-btn:active{transform:scale(.9);color:var(--ink)}
.top-search-btn svg{
  width:20px;
  height:20px;
  stroke:currentColor;
  fill:none;
  stroke-width:1.7;
  stroke-linecap:round;
  stroke-linejoin:round;
}

/* ===== 搜索页 ===== */
.search-head{
  flex:0 0 auto;
  display:flex;align-items:center;gap:2.4cqw;
  padding:calc(0px + 10px) 5cqw 10px;
}

/* 左侧返回按钮 */
.search-back{
  flex:0 0 auto;
  width:32px;height:42px;
  margin-left:-6px;
  display:grid;place-items:center;padding:0;
  background:none;border:none;cursor:pointer;
  color:var(--icon-2);
  transition:color .2s,transform .2s;
}
.search-back:active{transform:scale(.9);color:var(--ink)}
.search-back svg{
  width:20px;height:20px;
  stroke:currentColor;fill:none;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
}

.search-field{
  flex:1;min-width:0;position:relative;
  display:flex;align-items:center;gap:2cqw;
  height:42px;padding:0 3.2cqw;
  background:var(--card-bg);
  border:none;
  border-radius:12px;
  /* 与登录/注册输入框同一档投影：白底浮起来，不靠描边分界 */
  box-shadow:0 2px 10px -3px rgba(28,28,30,.18), 0 1px 3px rgba(28,28,30,.06);
  transition:background .3s,border-color .3s;
}
.search-field > svg{
  flex:0 0 auto;width:16px;height:16px;
  stroke:var(--icon-3);fill:none;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
}
#search-input{
  flex:1;min-width:0;height:100%;
  border:none;outline:none;background:none;
  font-family:var(--font-serif);
  font-size:calc(clamp(13px,3.2cqw,15px) * var(--fs));
  letter-spacing:.06em;color:var(--ink);
}
#search-input::placeholder{color:var(--ink-3)}
.search-clear-input{
  flex:0 0 auto;width:24px;height:24px;
  display:grid;place-items:center;padding:0;margin-right:-4px;
  border:none;background:none;cursor:pointer;color:var(--icon-3);
  opacity:0;pointer-events:none;transition:opacity .2s;
}
.search-field.has-value .search-clear-input{opacity:1;pointer-events:auto}
/* 只要框里有字就露出清空钮 —— 用 :placeholder-shown 直接问浏览器，
   不靠 input 事件的时机：中文输入法在组合期间事件来得不规律，
   靠 JS 加 class 会出现「打了字没按钮、回删一下才冒出来」。
   两条规则并存：JS 那条给不支持 :placeholder-shown 的老壳兜底。 */
#search-input:not(:placeholder-shown) ~ .search-clear-input{opacity:1;pointer-events:auto}
.search-clear-input svg{
  width:15px;height:15px;stroke:currentColor;fill:none;
  stroke-width:1.8;stroke-linecap:round;
}

/* 右侧搜索按钮 */
.search-submit{
  flex:0 0 auto;
  height:42px;
  padding:0 2.4cqw;
  margin-right:-6px;
  background:none;border:none;cursor:pointer;
  font-family:var(--font-serif);
  font-size:calc(clamp(13px,3.2cqw,15px) * var(--fs));
  letter-spacing:.1em;
  color:var(--ink);
  transition:opacity .2s,transform .2s;
  white-space:nowrap;
}
.search-submit:active{opacity:.5;transform:scale(.96)}

.search-body{
  flex:1;min-height:0;overflow-y:auto;
  padding:1.4cqh 5cqw calc(30px + 0px);
  scrollbar-width:none;
}
.search-body::-webkit-scrollbar{display:none}

.history-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:1.8cqh 0 1.4cqh;
}
.history-head span{
  font-family:var(--font-mono);
  font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.22em;color:var(--ink-3);
}
.history-clear{
  border:none;background:none;cursor:pointer;padding:.2em .1em;
  font-family:var(--font-serif);font-size:calc(clamp(10px,2.6cqw,11.5px) * var(--fs));
  letter-spacing:.1em;color:var(--ink-3);
}
.history-clear:active{color:var(--ink)}

/* 搜索记录：一排自适应宽度的小胶囊（宽度跟文字走，不拉齐成等宽三列）。
   字数少的就是窄块，长的自然变宽，右侧 × 永远贴着文字。
   换行仍按行左对齐，视觉上比「三列等宽、每格一大片空白」紧凑得多。 */
.history-list{
  display:flex;flex-wrap:wrap;
  gap:2.2cqw;
}
.history-item{
  display:flex;align-items:center;gap:1.2cqw;
  flex:0 1 auto;
  min-width:76px;
  max-width:100%;
  padding:2.2cqw 2.4cqw;
  border:1px solid var(--card-border);
  border-radius:10px;
  background:var(--card-bg);
  cursor:pointer;
  transition:background .2s,border-color .2s;
}
.history-item:active{background:rgba(28,28,30,.06)}
.history-text{
  flex:0 1 auto;min-width:0;text-align:left;
  font-size:calc(clamp(11.5px,2.95cqw,13px) * var(--fs));
  letter-spacing:.04em;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.history-del{
  flex:0 0 auto;width:16px;height:16px;
  display:grid;place-items:center;padding:0;margin-right:-3px;
  border:none;background:none;cursor:pointer;color:var(--icon-3);
}
.history-del:active{color:var(--ink)}
.history-del svg{
  width:11px;height:11px;stroke:currentColor;fill:none;
  stroke-width:1.8;stroke-linecap:round;
}

.search-results{display:flex;flex-direction:column}
.s-card{
  display:flex;align-items:center;gap:3.4cqw;
  padding:2.6cqw 0;
  border-bottom:1px solid var(--card-border);
  cursor:pointer;
}
.s-thumb{
  position:relative;flex:0 0 auto;
  width:19cqw;height:19cqw;max-width:80px;max-height:80px;
  overflow:hidden;background:rgba(28,28,30,.05);
}
.s-thumb .photo-img{position:absolute;inset:0}
.s-thumb .stroke-layer{position:absolute;inset:0;width:100%;height:100%}
.s-info{flex:1;min-width:0;text-align:left}
.s-date{
  display:block;margin-bottom:1.2cqw;
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.14em;color:var(--accent);
}
.s-cap{
  font-size:calc(clamp(12px,3.1cqw,14px) * var(--fs));color:var(--ink);
  letter-spacing:.07em;line-height:1.6;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;
}
.search-empty{
  padding:10cqh 0;text-align:center;
  font-size:calc(clamp(12px,3cqw,13.5px) * var(--fs));
  color:var(--ink-3);letter-spacing:.12em;
}

.timeline{
  flex:1;min-height:0;overflow-y:auto;position:relative;
  /* 必须显式裁掉横向：overflow-y 一旦是 auto，overflow-x 也算成 auto，
     堆叠卡右滑时 transform 会把横向滚动区撑大（实测 scrollWidth 390→750+），
     部分机型 WebView 不认 touch-action:pan-y，就会把整个时光轴横向拖走。
     clip = 彻底不可滚，连程序滚动都不留（hidden 仍会留一个可滚区）。 */
  overflow-x:clip;
  padding:12px 5cqw calc(88px + 0px);
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
  transition:padding-top .3s cubic-bezier(.22,1,.36,1);
}
.timeline::-webkit-scrollbar{display:none}

/* 那年今日卡片悬浮时，列表 / 照片墙顶部要给它留出位置；
   卡片被划走后（类名移除）padding 过渡收回 */
#page-home.anniv-on .timeline,
#page-home.anniv-on .wall-scroll{padding-top:80px}

/* ===== 月份头：标题 + 一条细线 + 组数（列表与照片墙共用） ===== */
.month-head{
  display:flex;
  align-items:baseline;
  gap:10px;
  padding:0 0 14px;
}
/* 列表里每个月份块之间留一点呼吸（首个月份再多一点），照片墙沿用原间距 */
.timeline .month-group > .month-head{padding-top:6px}
.timeline .month-group:first-child > .month-head{padding-top:12px}
.month-title{
  font-family:var(--font-serif);
  font-size:calc(clamp(19px,5.2cqw,22px) * var(--fs));
  font-weight:600;
  letter-spacing:.14em;
  line-height:1;
  color:var(--ink);
  white-space:nowrap;
}
.month-line{
  flex:1;
  height:1px;
  align-self:center;
  background:linear-gradient(90deg,rgba(28,28,30,.1) 0%,transparent 92%);
  transition:background .35s;
}
.month-count{
  font-family:var(--font-mono);
  font-size:calc(9px * var(--fs));
  letter-spacing:.1em;
  color:var(--ink-3);
  white-space:nowrap;
}

/* ===== 底部「回忆更多 / 收起回忆」按钮 ===== */
.month-more{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:1.6cqw;
  width:100%;
  margin:0 0 4.6cqh;
  padding:1.6cqh 0;
  background:none;
  border:none;
  cursor:pointer;
  font-family:var(--font-serif);
  font-size:calc(clamp(11px,2.9cqw,13px) * var(--fs));
  letter-spacing:.18em;
  color:var(--ink-2);
  transition:color .2s;
}
.month-more:active{color:var(--ink)}
.month-more svg{
  width:clamp(10px,2.6cqw,12px);
  height:clamp(10px,2.6cqw,12px);
  stroke:currentColor;fill:none;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round;
  transform:rotate(180deg);
  transition:transform .3s cubic-bezier(.22,1,.36,1);
}
.month-group.is-collapsed .month-more svg{transform:rotate(0deg)}

.entry{
  position:relative;
  margin-bottom:48px;
  padding:0 6px;   /* 左右各收 6px：最近页卡片整体小一圈，月份头不动 */
}
.entry:last-of-type{margin-bottom:8px}

/* ============================================================
   拍立得卡：白框 + 方形照片（与批量页预览 1:1 一致）+ 卡内文字
   （同一天的多张卡共用这一套相纸样式，靠 transform 叠出层次）
   ============================================================ */
.card{
  display:block;
  width:100%;
  padding:8px 8px 0;
  background:#fff;
  border:none;
  box-shadow:0 10px 22px -10px rgba(40,35,30,.34),0 2px 5px -2px rgba(40,35,30,.09);
  transform-origin:50% 100%;
  transition:transform .42s cubic-bezier(.22,1,.36,1),opacity .34s ease;
  will-change:transform,opacity;
  position:relative;
  z-index:100;
  cursor:pointer;
  touch-action:pan-y;
}

/* 照片格底色与编辑页预览卡一致：纯白纸面（缩到整张可见 / 旋转留边时露出白，不是灰） */
.card-photo{position:relative;width:100%;aspect-ratio:1;overflow:hidden;background:#ffffff}
/* 实况角标：封面右上角的小圆环（实心点 + 虚线环）。
   z 要压过模板装饰层（相角/胶带那些 z-index:3~4），否则拍立得白边上会被盖掉。 */
.live-badge{
  position:absolute;
  /* 左下角：右上角在卡片里会压到拍立得的日期/回形针，左下是唯一一直干净的角 */
  bottom:6px;left:6px;
  z-index:6;
  display:grid;place-items:center;
  width:19px;height:19px;
  border-radius:50%;
  background:rgba(20,18,16,.46);
  color:rgba(255,255,255,.95);
  pointer-events:none;
}
.live-badge svg{width:12px;height:12px;display:block}
.photo-img{
  position:absolute;inset:0;background-size:cover;background-position:center;
  filter:saturate(.97) contrast(.98);
}
.photo-img::before{
  content:'';position:absolute;inset:0;z-index:2;pointer-events:none;
  background:radial-gradient(120% 92% at 30% 6%,rgba(255,255,255,.16),transparent 58%);
}
.stroke-layer{position:absolute;inset:0;width:100%;height:100%;z-index:3;pointer-events:none}
/* 首页卡片照片的高光：按 测试.html 的 .ph::after 参数 */
.card-photo .photo-img::before{
  background:radial-gradient(120% 90% at 30% 8%,rgba(255,255,255,.22),transparent 58%);
}
/* 卡片照片：蒙版 + 整张原图（与编辑页、拼图宫格同一模型）
   外层 .photo-img 是固定方框（.card-photo 负责裁），里面这张 <img> 是整张原图
   按自身比例缩到刚好放得下，再整体位移/旋转/缩放 —— 所以「编辑页怎么摆，
   卡片就怎么摆」，只是画框更小；缩放走解码后的原图位图，不会像
   background-image 那样按旧栅格拉伸发虚。 */
.photo-img img.pf-img{
  display:block;position:absolute;left:50%;top:50%;
  /* 这两行只是兜底：JS 量到 .photo-img 的实际尺寸后，会按「cover 基准」
     把宽高写成 px（原图比例 × 铺满倍数），此时 object-fit 不再起裁切作用 ——
     图片元素比方框大，超出的部分由 .card-photo 的 overflow 切掉。 */
  width:100%;height:100%;
  max-width:none;max-height:none;object-fit:cover;
  transform-origin:50% 50%;pointer-events:none;transition:none;
  -webkit-user-drag:none;user-select:none;
}

/* ============================================================
   模板装饰（首页卡片版）：卡片白框 / 文字排版完全不变，
   只在照片上加对应的装饰——胶带压上缘、胶卷齿孔、回形针夹角
   ============================================================ */
/* 胶带：一半压在卡片白边上，一半压在照片上缘 */
.card.tpl-tape::before{
  content:'';position:absolute;z-index:5;pointer-events:none;
  top:-4px;left:50%;width:74px;height:22px;
  transform:translateX(-50%) rotate(-2.2deg);
  background:rgba(228,206,168,.93);
  border:1px solid rgba(198,172,132,.42);
  clip-path:polygon(3% 3%,97% 0,100% 97%,0 100%);
  box-shadow:0 1px 2px rgba(60,50,30,.1);
}
/* 胶卷：照片上下各一条黑色胶片（实色，圆角齿孔），胶片占住照片上下边缘 */
.card.tpl-film .card-photo::before,
.card.tpl-film .card-photo::after{
  content:'';position:absolute;left:0;right:0;height:15px;z-index:4;
  background:#141416;
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='15'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M0,0H18V15H0ZM6.5,2H11.5A1.5,1.5,0,0,1,13,3.5V11.5A1.5,1.5,0,0,1,11.5,13H6.5A1.5,1.5,0,0,1,5,11.5V3.5A1.5,1.5,0,0,1,6.5,2Z'/%3E%3C/svg%3E");
  -webkit-mask-size:18px 15px;-webkit-mask-repeat:repeat-x;-webkit-mask-position:center;
}
.card.tpl-film .card-photo::before{top:0}
.card.tpl-film .card-photo::after{bottom:0}
/* 回形针：斜夹在照片左上角，细长、不遮内容（替代原来的方形邮戳） */
.card.tpl-clip::after{
  content:'';position:absolute;z-index:5;pointer-events:none;
  top:-3px;left:16px;width:22px;height:56px;
  transform:rotate(-8deg);
  background:var(--clip-img) center/100% 100% no-repeat;
  filter:drop-shadow(0 1px 2px rgba(30,30,40,.3));
}
/* 相角：四枚牛皮纸相角压住照片四角（首页卡片版，与拍立得同一画法） */
.card.tpl-corner .card-photo::before{
  content:'';position:absolute;inset:0;z-index:4;pointer-events:none;
  background-image:
    linear-gradient(135deg,var(--corner-c) 50%,transparent 50.6%),
    linear-gradient(225deg,var(--corner-c) 50%,transparent 50.6%),
    linear-gradient(45deg,var(--corner-c) 50%,transparent 50.6%),
    linear-gradient(315deg,var(--corner-c) 50%,transparent 50.6%);
  background-position:0 0,100% 0,0 100%,100% 100%;
  background-size:30px 30px;
  background-repeat:no-repeat;
  filter:drop-shadow(0 1px 1.5px rgba(60,50,30,.18));
}

/* ===== 圆形邮戳（A 经典双圈）：落在照片右下角，外实线 + 内虚线 =====
   尺寸用 em 驱动：不同容器只改 font-size，圈内字号与圆同比缩放 */
.stamp-mark{
  position:absolute;right:.55em;bottom:.55em;z-index:6;
  width:5.4em;height:5.4em;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:.18em;
  border-radius:50%;
  /* 注意：Chrome 会把 border-width 向下取整到整数 px，
     .3em（≈3px）才真的看得出「加粗」 */
  border:.3em solid rgba(var(--accent-rgb),.8);
  color:rgba(var(--accent-rgb),.9);
  transform:rotate(-9deg);
  pointer-events:none;-webkit-user-select:none;user-select:none;
}
.stamp-mark::before{
  content:'';position:absolute;inset:.4em;border-radius:50%;
  border:.12em dashed rgba(var(--accent-rgb),.64);
}
.stamp-mark b{
  font-family:var(--font-mono);font-size:.72em;font-weight:700;
  letter-spacing:.14em;text-indent:.14em;line-height:1;
}
.stamp-mark i{
  font-family:var(--font-mono);font-style:normal;font-weight:500;
  font-size:.82em;letter-spacing:.04em;line-height:1;
}
/* 首页卡：卡宽约 340px，邮戳直径 ≈ 65px */
.card .stamp-mark{font-size:calc(12px * var(--fs))}

/* 卡内文字（按 测试.html）：第一行左「日期 | 星期」、右「地点」，正文在下 */
.card-info{
  display:flex;
  flex-direction:column;
  min-height:106px;
  padding:13px 7px 15px;
  box-sizing:border-box;
}
.card-head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:12px;
  margin-bottom:9px;
}
.card-head-l{
  flex:0 0 auto;
  display:flex;
  align-items:baseline;
  gap:7px;
  min-width:0;
}
.card-date{
  font-family:var(--font-mono);
  font-size:calc(11px * var(--fs));
  letter-spacing:0;
  color:var(--accent);
  white-space:nowrap;
}
.card-date .sep{
  display:inline-block;
  margin:0;
  padding:0;
}
.card-week{
  position:relative;
  padding-left:8px;
  font-family:var(--font-serif);
  font-size:calc(11.5px * var(--fs));
  font-weight:500;
  letter-spacing:.04em;
  color:var(--ink-3);
  white-space:nowrap;
}
.card-week::before{
  content:'';
  position:absolute;
  left:0;
  top:50%;
  width:1px;
  height:8px;
  margin-top:-4px;
  background:rgba(28,28,30,.48);
}
.card-loc{
  flex:0 1 auto;
  min-width:0;
  display:inline-flex;
  align-items:center;
  gap:4px;
  font-family:var(--font-serif);
  font-size:calc(11.5px * var(--fs));
  font-weight:500;
  letter-spacing:.04em;
  color:var(--accent);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.card-loc svg{
  flex:0 0 auto;
  width:10px;height:10px;
  stroke:currentColor;fill:none;
  stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;
}
/* 卡片题注：真正加粗到 600（同 测试.html） */
.card-cap{
  font-family:var(--font-serif);
  font-size:calc(14px * var(--fs));
  font-weight:600;
  line-height:1.75;
  letter-spacing:.02em;
  color:#1c1c1e;
  display:-webkit-box;
  -webkit-line-clamp:2;
  -webkit-box-orient:vertical;
  overflow:hidden;
}

/* ===== 拍立得下堆叠：一张张往下压，左右滑翻人 ===== */
.stack{
  position:relative;
  padding-bottom:46px;   /* 给最下面那层（下移 44px）留位 */
  isolation:isolate;
  touch-action:pan-y;
  -webkit-user-select:none;user-select:none;
}
/* 第一张留在文档流里撑起高度，其余的绝对定位叠在它身上 */
.stack .card{
  position:absolute;
  top:0;left:0;
  pointer-events:none;
}
.stack .card:first-of-type{position:relative}
.stack .card.on-top{pointer-events:auto;cursor:pointer}
/* 拖拽中：跟随手指直接走，不加过渡 */
.stack.dragging .card{transition:none}
.stack-count{
  position:absolute;
  top:16px;right:16px;
  z-index:160;
  pointer-events:none;
  padding:3px 8px;
  background:rgba(20,18,16,.46);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  color:#fff;
  font-family:var(--font-mono);
  font-size:calc(9px * var(--fs));
  letter-spacing:.08em;
  line-height:1.4;
}

.empty{
  flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:2.4cqh;padding:0 12cqw;text-align:center;
}
.empty-icon{width:16cqw;height:16cqw;border:1px solid rgba(28,28,30,.14);border-radius:18px;display:grid;place-items:center}
.empty-icon svg{width:52%;height:52%;stroke:var(--icon-3);fill:none;stroke-width:1.4}
.empty p{font-size:calc(clamp(12px,3.1cqw,14px) * var(--fs));color:var(--ink-2);letter-spacing:.1em;line-height:1.9}

/* 空状态在滚动区里上下居中。
   .empty 的 flex:1 只在 flex 父级里有效，而「最近 / 收藏 / 回收站 / 作品集」
   这几个滚动容器都是普通块级（grid）容器，所以占位符一直贴在内容顶部。
   这里改成绝对定位铺满滚动区（三个容器已 position:relative）。 */
.timeline > .empty,
.wall-scroll > .empty,
.stash-grid > .empty{
  position:absolute;
  top:0;left:0;right:0;bottom:0;
  padding:0 12cqw;
  margin:0;
}
/* 只有「最近」页底部压着悬浮导航，需要让出它的 70px；
   收藏 / 回收站 / 作品集是二级页，导航已隐藏，直接按整页居中 */
.timeline > .empty,
#page-home .wall-scroll > .empty{
  bottom:calc(70px + 0px);
}

.tabbar{
  /* 悬浮胶囊：左右留边 + 离底 10px，圆角 + 毛玻璃 */
  position:absolute;left:14px;right:14px;
  bottom:calc(10px + 0px);
  z-index:40;
  display:flex;align-items:stretch;
  height:60px;
  padding:0 2px;
  border-radius:28px;
  overflow:hidden;
  background:rgba(255,255,255,.72);
  -webkit-backdrop-filter:blur(20px) saturate(180%);
  backdrop-filter:blur(20px) saturate(180%);
  /* 内侧一圈高光 + 外侧柔和投影：玻璃边缘靠高光，不靠描边 */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.75),
    inset 0 0 0 .5px rgba(28,28,30,.06),
    var(--float-shadow);
  transform:translateY(calc(100% + 24px));
  visibility:hidden;
  transition:transform .34s cubic-bezier(.22,1,.36,1),visibility 0s linear .34s,background .3s,border-color .3s;
}
.tabbar.on{
  transform:none;visibility:visible;
  transition:transform .34s cubic-bezier(.22,1,.36,1),visibility 0s,background .3s,border-color .3s;
}
/* 键盘弹出时收起底部导航，避免被顶到键盘上方 */

body.kb-open .tabbar{
  transform: translateY(calc(100% + 24px));
  visibility: hidden;
  transition: none;
}
.tab{
  flex:1;height:100%;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:3px;
  background:none;border:none;cursor:pointer;
  font-family:var(--font-sans);
  font-size:calc(10px * var(--fs));
  letter-spacing:.16em;color:var(--ink-3);
  transition:color .25s;
}
.tab.active{color:var(--ink)}
.tab svg{
  width:19px;height:19px;
  color:var(--tab-idle);
  stroke:currentColor;fill:none;
  stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;
  transition:color .25s;
}
.tab.active svg{color:var(--ink)}
/* 记录：四格里的第三格，用深色实心方块保持最高视觉权重 */
.tab-add{
  flex:1;height:100%;padding:0;gap:3px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  background:none;border:none;cursor:pointer;
}
.tab-add-dot{
  width:38px;height:38px;
  border-radius:50%;
  display:grid;place-items:center;
  background:var(--ink);color:#faf9f7;
  transition:transform .22s cubic-bezier(.34,1.56,.64,1),background .22s,color .22s;
}
.tab-add:active .tab-add-dot{transform:scale(.94)}
.tab-add-dot svg{
  width:21px;height:21px;stroke:currentColor;fill:none;
  stroke-width:1.7;stroke-linecap:round;
}

.editor-bar{
  flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:2cqw;
  /* 顶距只留呼吸位：安全区一律由 .page 的 padding-top:--sf-sat 让过了。
     这里**不能再加 env(safe-area-inset-top)** —— 安卓 WebView 在刘海/挖孔机上
     env() 并不为 0（等于屏幕切口高度），而 --sf-sat 本身已经含了切口，
     两者叠加就正好多出一个状态栏的量。 */
  padding:2.2cqh 5cqw 1.6cqh;
}
/* 浏览器 / PWA（没有原生壳）：.page 不补安全区，顶栏自己让刘海 */
html:not([data-shell="ios"]):not([data-shell="android"]) .editor-bar{
  padding-top:max(2.2cqh, env(safe-area-inset-top, 0px));
}
.btn-ghost{
  font-family:var(--font-serif);font-size:calc(clamp(11.5px,2.9cqw,13px) * var(--fs));letter-spacing:.12em;
  color:var(--ink-2);cursor:pointer;padding:.62em .95em;
  background:#ffffff;
  border:1px solid rgba(28,28,30,.08);
  transition:background .25s,border-color .25s;
  white-space:nowrap;
}
.btn-ghost:active{background:#f2f2f5}
/* 右列：保存按钮 */
.bar-right{display:flex;flex-direction:column;align-items:flex-end;gap:.55em}
.btn-solid{
  border:1px solid transparent;background:#1c1c1e;
  color:#fff;font-family:var(--font-serif);font-size:calc(clamp(11.5px,2.9cqw,13px) * var(--fs));letter-spacing:.12em;
  padding:.7em 1.3em;cursor:pointer;
  box-shadow:0 8px 22px -10px rgba(20,20,40,.5);
  transition:transform .25s,background .25s,color .25s;
  white-space:nowrap;
}
.btn-solid:active{transform:scale(.96)}

.editor-stage{position:relative;flex:1;min-height:0;display:grid;place-items:center;padding:1.4cqh 3.5cqw 1cqh}
#page-batch .batch-stage{overflow:hidden}
.polaroid{
  position:relative;width:100%;max-width:64cqw;
  padding:3cqw 3cqw 3.6cqw;
  background:#ffffff;
  border:1px solid var(--card-border);
  box-shadow:0 24px 48px -18px rgba(30,30,70,.22),0 2px 6px rgba(30,30,70,.05);
  transition:background .3s,border-color .3s;
}
/* 照片格：4:5 竖版（高比宽大一些），底色纯白 —— 与保存后的回忆卡片同一个底色，
   缩到「整张可见」或旋转留边时露出来的是白纸，不是灰块。 */
.slot{position:relative;width:100%;aspect-ratio:4/5;overflow:hidden;background:#ffffff;cursor:pointer}
/* 编辑页照片：.slot 是固定方框蒙版（overflow:hidden），里面这张 <img> 是**整张原图**。
   跟拼图宫格完全一套：JS 把宽高写成「原图等比放大到刚好铺满方框」（cover）的 px，
   所以默认看到的是**填满**，但图片本身一像素没裁 —— 双指缩小能把整张找回来，
   放大/旋转/移位也全作用在整张原图上，只有渲染层被蒙版切掉。
   下面两行 width/height:100% 是 JS 量尺寸之前的兜底（视觉与 fit 后一致，不会跳）。 */
.slot .ed-img{
  display:block;position:absolute;left:50%;top:50%;
  width:100%;height:100%;
  max-width:none;max-height:none;object-fit:cover;
  transform-origin:50% 50%;pointer-events:none;transition:none;
  -webkit-user-drag:none;user-select:none;
}
/* 手势全归 JS：单指移位 / 双指缩放旋转，别让页面跟着滚 */
#batch-slot{touch-action:none}
.caption{
  margin-top:3.2cqw;min-height:1.7em;text-align:center;
  font-size:calc(clamp(12px,3.3cqw,15px) * var(--fs));color:var(--ink);letter-spacing:.07em;line-height:1.7;
  cursor:text;position:relative;z-index:4;
}
.caption:empty::before{content:attr(data-ph);color:var(--ink-3)}

.date-wrap{display:flex;justify-content:center;position:relative;z-index:7}
/* 地点：只显示图标，贴在日期右侧 */
.loc-btn{
  flex:0 0 auto;display:inline-grid;place-items:center;
  width:2.6em;height:2.6em;padding:0;cursor:pointer;
  background:#fafafa;border:0;color:var(--accent);
  transition:background .2s,color .2s;
  -webkit-tap-highlight-color:transparent;
}
.loc-btn svg{width:62%;height:62%;stroke:currentColor;fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.loc-btn:active{background:rgba(var(--accent-rgb),.06)}
/* 已定位：过去用实线边框提示，去边框后改用底色深浅区分 */
.loc-btn.has{background:rgba(var(--accent-rgb),.09)}
.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}
.date-btn{
  display:inline-flex;align-items:center;gap:1.4cqw;
  margin:0 auto 1.2cqw;padding:.34em .9em;
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.16em;color:var(--accent);
  border:0;cursor:pointer;
  background:#fafafa;
}
.date-btn svg{width:11px;height:11px;stroke:currentColor;fill:none;stroke-width:1.6}

/* 原图（无模板）：编辑器内与首页卡片一致，仍是白卡包照片，只是不加任何修饰 */

/* 拍立得：相纸尺寸与其他模板卡等高（436）——
   高度 = 上白边 + 方图 + 信息区 + 下白边；左右白边 5.8cqw(≈22px) 让照片尽量大，
   上白边收窄到 6.4cqw 让顶部更紧凑，省下的高度挪到卡底（真相纸底部留白更宽） */
.polaroid.tpl-classic{padding:6.2cqw 5cqw 4.2cqw}
.card.tpl-classic{padding:6.4cqw 5.8cqw 3.1cqw}
.pl-deco{display:none;z-index:5;pointer-events:none;color:var(--ink-3)}
.polaroid.tpl-classic .pl-deco,.card.tpl-classic .pl-deco{display:flex}
.pl-top{
  position:absolute;top:7px;left:28px;right:28px;
  align-items:center;gap:9px;
  font-family:var(--font-mono);font-size:clamp(8px,2.1cqw,9.5px);
  color:var(--ink-3);
}
.pl-top i{flex:1;height:1px;background:rgba(28,28,30,.16)}
.pl-top em{font-style:normal;letter-spacing:.52em;text-indent:.52em;color:var(--ink-2);position:relative}
.pl-top em::after{  /* 标题后接一颗实心菱形 */
  content:'';position:absolute;top:50%;right:-11px;width:4px;height:4px;
  margin-top:-2px;background:var(--accent);transform:rotate(45deg);
}
.pl-left,.pl-right{
  position:absolute;top:50%;transform:translateY(-50%);
  writing-mode:vertical-rl;
  align-items:center;gap:10px;
  font-family:var(--font-serif);font-size:clamp(7.5px,1.7cqw,9px);
  letter-spacing:.46em;line-height:1;
  opacity:.75;
  white-space:nowrap;   /* 竖排模式下不换行，否则文字会被折成第二列 */
}
.pl-left{left:7px}
.pl-right{right:7px}
.pl-right::after{  /* 右列底下一小段 accent 短线 */
  content:'';display:block;width:1px;height:16px;margin-top:9px;
  background:var(--accent);opacity:.55;
}
/* 几何小形状：左列空心圆 / 右列空心菱形 */
.shp{flex:0 0 auto;display:block}
.shp-c{width:7px;height:7px;border:1px solid var(--ink-3-solid);border-radius:50%}
.shp-d{width:7px;height:7px;border:1px solid var(--accent);opacity:.6;transform:rotate(45deg)}

.polaroid.tpl-tape::before{  content:'';position:absolute;top:-3cqw;left:50%;
  width:20cqw;height:6cqw;max-width:96px;max-height:28px;
  transform:translateX(-50%) rotate(-2.5deg);z-index:8;
  background:rgba(226,205,168,.85);
  border:1px solid rgba(200,175,135,.5);
  clip-path:polygon(3% 0,97% 4%,100% 96%,0 100%);
}
/* 胶卷：照片上下各一条黑色胶片（实色，圆角齿孔），与首页卡片同一画法 */
.polaroid.tpl-film{padding:3cqw 3cqw 3.6cqw}
.polaroid.tpl-film .slot::before,
.polaroid.tpl-film .slot::after{
  content:'';display:block;position:absolute;left:0;right:0;height:5.2cqw;z-index:4;pointer-events:none;
  background:#141416;
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='66' height='52'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M0,0H66V52H0ZM24,7H42A5,5,0,0,1,47,12V40A5,5,0,0,1,42,45H24A5,5,0,0,1,19,40V12A5,5,0,0,1,24,7Z'/%3E%3C/svg%3E");
  -webkit-mask-size:6.6cqw 5.2cqw;-webkit-mask-repeat:repeat-x;-webkit-mask-position:center;
}
.polaroid.tpl-film .slot::before{top:0;bottom:auto}
.polaroid.tpl-film .slot::after{top:auto;bottom:0}
/* 回形针：夹在照片左上角（原来是方形邮戳，改为细长金属夹） */
.polaroid.tpl-clip::after{
  content:'';position:absolute;z-index:9;pointer-events:none;
  top:.4cqw;left:4.6cqw;width:9.6cqw;height:24cqw;
  transform:rotate(-8deg);
  background:var(--clip-img) center/100% 100% no-repeat;
  filter:drop-shadow(0 1px 2px rgba(30,30,40,.24));
}
/* 邮戳：只在使用该模板时显示，落在照片区右下方（避开"点击更换照片"提示） */
.polaroid .stamp-mark{display:none;font-size:calc(11.5px * var(--fs))}
.polaroid.tpl-stamp .stamp-mark{display:flex}
.polaroid.tpl-stamp .slot::after{right:auto;left:2.4cqw}

/* ============ 邮票：齿孔（锯齿）边做在照片上，照片像邮票贴在卡纸上 ============
   mask 打在照片蒙版（.slot / .card-photo）上：四条边各一层重复径向渐变，
   每颗圆把照片边缘「咬」掉一个半圆，四层相交（source-in）＝整圈齿孔。
   齿距 = 1.9×齿孔半径（比直径略小）→ 相邻齿孔几乎相接、中间只剩一点
   圆滑的窄棱，出来的是一排**凹进去的圆形齿孔**，不是尖刺也不是凸包。 */
.polaroid.tpl-postage .slot,
.card.tpl-postage .card-photo{
  --perf: 7px;                       /* 齿孔半径：凹进去的圆孔直径 14px */
  -webkit-mask-image:
    radial-gradient(circle at 50% 0, transparent calc(var(--perf) - .5px), #000 var(--perf)),
    radial-gradient(circle at 50% 100%, transparent calc(var(--perf) - .5px), #000 var(--perf)),
    radial-gradient(circle at 0 50%, transparent calc(var(--perf) - .5px), #000 var(--perf)),
    radial-gradient(circle at 100% 50%, transparent calc(var(--perf) - .5px), #000 var(--perf));
  -webkit-mask-size:
    calc(var(--perf) * 2.4) 100%, calc(var(--perf) * 2.4) 100%,
    100% calc(var(--perf) * 2.4), 100% calc(var(--perf) * 2.4);
  -webkit-mask-position:
    var(--perf) 0, var(--perf) 0,
    0 var(--perf), 0 var(--perf);
  -webkit-mask-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
  -webkit-mask-composite: source-in;
  border-radius:2px;
}
/* 邮票贴在卡纸上：纸边留宽，照片四周一圈白卡才衬得出齿孔 */
.polaroid.tpl-postage{padding:6.6cqw 6.6cqw 3.4cqw}
.card.tpl-postage{padding:5.6cqw 5.6cqw 3.4cqw}
/* 邮票不要卡纸那圈细边：有那条线，齿孔看着像「画在方框里」而不是咬在纸上 */
.polaroid.tpl-postage,
.card.tpl-postage{border-color:transparent}
.tpl[data-tpl="postage"] .tpl-photo{box-shadow:none}

/* 相角：四枚牛皮纸相角压住照片四角（老相册贴法）
   一个伪元素铺满照片区，用四条对角渐变各画出一只三角相角 */
.polaroid.tpl-corner,.card.tpl-corner{--corner-c:rgba(228,207,172,.92)}
.polaroid.tpl-corner .slot::before{
  content:'';position:absolute;inset:0;z-index:2;pointer-events:none;
  background-image:
    linear-gradient(135deg,var(--corner-c) 50%,transparent 50.6%),
    linear-gradient(225deg,var(--corner-c) 50%,transparent 50.6%),
    linear-gradient(45deg,var(--corner-c) 50%,transparent 50.6%),
    linear-gradient(315deg,var(--corner-c) 50%,transparent 50.6%);
  background-position:0 0,100% 0,0 100%,100% 100%;
  background-size:30px 30px;
  background-repeat:no-repeat;
  filter:drop-shadow(0 1px 1.5px rgba(60,50,30,.18));
}

.editor-tools{
  flex:0 0 auto;
  padding:0 5cqw calc(1.4cqw + 0px);
  background:#f7f7f9;
  border-top:1px solid rgba(28,28,30,.08);
  transition:background .3s,border-color .3s;
}
/* 选项面板：展开/收起用 0fr → 1fr 过渡高度，照片会跟着一起平滑缩放 */
.editor-panel{
  display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .3s cubic-bezier(.22,1,.36,1);
}
.editor-panel.on{grid-template-rows:1fr}
.panel-wrap{min-height:0;min-width:0;overflow:visible}
.pane{display:none}
.pane.on{display:block;padding:2.4cqw 0 2cqw;animation:paneIn .26s cubic-bezier(.22,1,.36,1)}
@keyframes paneIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}


/* ===== 图片文字（贴纸）：直接落在照片区里，可拖拽换位 =====
   坐标按照片区百分比存，编辑器与首页卡片共用同一套渲染；
   非编辑态整层 pointer-events:none，只作展示不打架（换照片/裁剪等点击不受影响） */
.text-layer{position:absolute;inset:0;z-index:1;pointer-events:none;font-size:13px}
.text-layer .txt{
  position:absolute;transform:translate(-50%,-50%);
  max-width:92%;text-align:center;white-space:pre-wrap;word-break:break-word;
  line-height:1.35;
  text-shadow:0 1px 4px rgba(0,0,0,.42),0 0 2px rgba(0,0,0,.22);
}
/* 首页卡片上的同款（卡片照片区更小，基准字号压一档） */
.card-photo .text-layer{font-size:9.5px;z-index:2}
/* 带底色的文字框：阴影由样式 tab 的「阴影」选项控制（内联），这里不强制 */
.text-layer .txt[data-b]{-webkit-tap-highlight-color:transparent}


/* ===== 编辑器：模板选择（真实缩略预览） =====
   每张选项 = 当前照片套上真实模板的迷你版：迷你白卡 + 对应装饰，
   与编辑区 / 首页卡片同构，选完所见即所得 */
.tpl-row{
  display:flex;align-items:flex-start;gap:2.4cqw;
  margin:0 -5cqw;padding:.4cqw 5cqw 1.2cqw;
  overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-ms-overflow-style:none;
  -webkit-overflow-scrolling:touch;
}
.tpl-row::-webkit-scrollbar{display:none}
.tpl{
  flex:0 0 auto;display:flex;flex-direction:column;align-items:center;gap:1.1cqw;
  background:none;border:none;padding:0;cursor:pointer;
  font-family:var(--font-serif);font-size:calc(clamp(8.5px,2.1cqw,9.5px) * var(--fs));
  letter-spacing:.06em;color:var(--ink-3);
  -webkit-tap-highlight-color:transparent;
}
/* 迷你白卡：真实卡片等比缩小 */
.tpl-frame{
  position:relative;display:block;width:12.8cqw;height:15.8cqw;min-width:47px;min-height:58px;
  background:#ffffff;border-radius:1px;
  box-shadow:0 2px 8px rgba(0,0,0,.38);
  transition:box-shadow .22s,transform .22s;
}
/* 原图：没有白卡，照片直接铺满（选中时靠描边环区分）。
   必须放在 .active 之前：同为三级选择器，选中环靠后声明盖过默认描边 */
.tpl[data-tpl="none"] .tpl-frame{background:transparent;box-shadow:inset 0 0 0 1px rgba(255,255,255,.14)}
.tpl[data-tpl="none"] .tpl-photo{inset:0}
.tpl:active .tpl-frame{transform:scale(.95)}
.tpl.active{color:var(--accent)}
.tpl.active .tpl-frame{box-shadow:0 0 0 1.5px var(--accent),0 2px 8px rgba(0,0,0,.38)}
/* 照片层：底图统一走 --tpl-src（一张图复用七次，不重复写 DOM） */
.tpl-photo{
  position:absolute;display:block;
  background-image:var(--tpl-src);background-size:cover;background-position:center;
  box-shadow:inset 0 0 0 1px rgba(28,28,30,.06);
}
/* 装饰层：每张迷你卡最多两层伪元素，按模板各自绘制 */
.tpl-deco{position:absolute;inset:0;pointer-events:none}

/* 拍立得：照片上缩，底部留白 + 一行字线 */
.tpl[data-tpl="classic"] .tpl-photo{inset:11% 11% 32%}
.tpl[data-tpl="classic"] .tpl-deco::before{
  content:'';position:absolute;left:26%;right:26%;bottom:16%;height:1.5px;
  background:rgba(28,28,30,.22);
}
/* 胶带：顶部一段牛皮纸胶带 */
.tpl[data-tpl="tape"] .tpl-photo{inset:13% 10% 11%}
.tpl[data-tpl="tape"] .tpl-deco::before{
  content:'';position:absolute;top:-5%;left:28%;width:44%;height:14%;
  background:rgba(226,205,168,.92);
  border:1px solid rgba(200,175,135,.5);
  transform:rotate(-3deg);
  clip-path:polygon(4% 0,96% 8%,100% 92%,0 100%);
}
/* 胶卷：齿孔压在照片窗口上下边缘（照片 inset 17% 8%，齿孔对齐 17% 处） */
.tpl[data-tpl="film"] .tpl-photo{inset:17% 8%}
.tpl[data-tpl="film"] .tpl-deco::before,
.tpl[data-tpl="film"] .tpl-deco::after{
  content:'';position:absolute;left:8%;right:8%;height:9%;
  background:#141416;
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='10'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M0,0H14V10H0ZM5,1.5H9A1,1,0,0,1,10,2.5V7.5A1,1,0,0,1,9,8.5H5A1,1,0,0,1,4,7.5V2.5A1,1,0,0,1,5,1.5Z'/%3E%3C/svg%3E");
  -webkit-mask-size:7px 100%;-webkit-mask-repeat:repeat-x;-webkit-mask-position:center;
}
.tpl[data-tpl="film"] .tpl-deco::before{top:17%}
.tpl[data-tpl="film"] .tpl-deco::after{bottom:17%}
/* 回形针：左上角一枚细金属夹（与真实模板同一张 SVG） */
.tpl[data-tpl="clip"] .tpl-photo{inset:12% 10% 12%}
.tpl[data-tpl="clip"] .tpl-deco::before{
  content:'';position:absolute;top:-2%;left:8%;width:26%;height:58%;
  background:var(--clip-img) center/100% 100% no-repeat;
  transform:rotate(-8deg);
  filter:drop-shadow(0 1px 1px rgba(30,30,40,.3));
}
/* 邮戳：右下一枚圆戳（实环 + 内虚线环） */
.tpl[data-tpl="stamp"] .tpl-photo{inset:12% 10% 12%}
.tpl[data-tpl="stamp"] .tpl-deco::before,
.tpl[data-tpl="stamp"] .tpl-deco::after{
  content:'';position:absolute;border-radius:50%;aspect-ratio:1;
}
.tpl[data-tpl="stamp"] .tpl-deco::before{
  right:7%;bottom:8%;width:44%;
  border:1.5px solid rgba(var(--accent-rgb),.75);
}
.tpl[data-tpl="stamp"] .tpl-deco::after{
  right:11%;bottom:12%;width:36%;
  border:1px dashed rgba(var(--accent-rgb),.5);
}
/* 邮票：迷你缩略里照片窗口同样做齿孔边（齿小一号，同样平边+凹孔） */
.tpl[data-tpl="postage"] .tpl-photo{
  inset:14%;
  --perf: 2.2px;
  -webkit-mask-image:
    radial-gradient(circle at 50% 0, transparent calc(var(--perf) - .5px), #000 var(--perf)),
    radial-gradient(circle at 50% 100%, transparent calc(var(--perf) - .5px), #000 var(--perf)),
    radial-gradient(circle at 0 50%, transparent calc(var(--perf) - .5px), #000 var(--perf)),
    radial-gradient(circle at 100% 50%, transparent calc(var(--perf) - .5px), #000 var(--perf));
  -webkit-mask-size:
    calc(var(--perf) * 2.6) 100%, calc(var(--perf) * 2.6) 100%,
    100% calc(var(--perf) * 2.6), 100% calc(var(--perf) * 2.6);
  -webkit-mask-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
  -webkit-mask-composite: source-in;
}
/* 相角：四枚牛皮纸角压住照片 */
.tpl[data-tpl="corner"]{--corner-c:rgba(228,207,172,.92)}
.tpl[data-tpl="corner"] .tpl-photo{inset:11% 10%}
.tpl[data-tpl="corner"] .tpl-deco::before{
  content:'';position:absolute;inset:11% 10%;
  background-image:
    linear-gradient(135deg,var(--corner-c) 50%,transparent 50.6%),
    linear-gradient(225deg,var(--corner-c) 50%,transparent 50.6%),
    linear-gradient(45deg,var(--corner-c) 50%,transparent 50.6%),
    linear-gradient(315deg,var(--corner-c) 50%,transparent 50.6%);
  background-position:0 0,100% 0,0 100%,100% 100%;
  background-size:26% 26%;
  background-repeat:no-repeat;
  filter:drop-shadow(0 1px 1px rgba(60,50,30,.2));
}


.profile-body{
  flex:1;min-height:0;overflow-y:auto;
  padding:3cqh 5cqw calc(92px + 0px);
  scrollbar-width:none;
}
.profile-body::-webkit-scrollbar{display:none}
/* 退出登录已移到「账号安全」页，这一页不再多出一行，无需收紧间距 */
/* 顶部三个入口：作品集 / 收藏 / 回收站 */
.p-entries{
  display:grid;grid-template-columns:repeat(3,1fr);
  border:none;
  border-radius: 16px;
  overflow:hidden;   /* 子项点击底色也跟着圆角裁掉 */
  background:#ffffff;
  transition:background .35s,border-color .35s;
}
.p-entry{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1.8cqw;
  padding:4.4cqw 2cqw;cursor:pointer;
  border:none;
  border-right:var(--hairline);
  background:none;font-family:var(--font-serif);
  transition:background .2s;
}
.p-entry:last-child{border-right:none}
.p-entry:active{background:#f6f6f4}
.p-entry svg{
  width:23px;height:23px;
  fill:none;stroke:var(--icon-2);stroke-width:1.2;
  stroke-linecap:round;stroke-linejoin:round;
}
.p-entry span{
  font-size:calc(clamp(11px,2.9cqw,13px) * var(--fs));
  color:var(--ink);letter-spacing:.14em;
}

/* 每组设置行 = 一张卡：整组圆角，首行/末行与分割线都裁进弧内 */
.p-toggles{
  margin-top:4cqh;display:flex;flex-direction:column;
  border-radius:16px;
  overflow:hidden;
}
.p-toggle-row{
  display:flex;align-items:center;justify-content:flex-start;gap:11px;
  min-height:56px;
  padding:3.4cqw 4cqw;
  background:#ffffff;
  border:none;
  border-bottom:var(--hairline);
  transition:background .35s,border-color .35s;
}
/* 行首加了图标后，右侧控件（开关 / 值 / 箭头）自己顶到最右 */
.p-toggle-row > .switch,
.p-toggle-row > .p-row-side,
.p-toggle-row > .p-row-arrow{margin-left:auto}
.p-toggle-row:last-child{border-bottom:none}
.p-toggle-info{display:flex;flex-direction:column;gap:.6cqw;text-align:left}
.p-toggle-info span{font-size:calc(clamp(13px,3.3cqw,14.5px) * var(--fs));color:var(--ink);letter-spacing:.1em}
.p-toggle-info small{font-size:calc(clamp(10px,2.5cqw,11px) * var(--fs));color:var(--ink-3);letter-spacing:.06em}
/* 行首图标：细线、不带色块，和「作品集 / 收藏 / 回收站」同一语系 */
.p-ico{
  flex:0 0 auto;
  width:17px;height:17px;
  fill:none;stroke:var(--icon-2);stroke-width:1.5;
  stroke-linecap:round;stroke-linejoin:round;
  transition:stroke .35s;
}

.switch{
  position:relative;flex:0 0 auto;
  width:48px;height:28px;border-radius:14px;
  background:rgba(28,28,30,.16);
  border:none;cursor:pointer;padding:0;
  transition:background .26s;
}
.switch .knob{
  position:absolute;top:4px;left:4px;
  width:20px;height:20px;border-radius:50%;
  background:#fff;
  box-shadow:0 1px 4px rgba(0,0,0,.16);
  transition:transform .28s cubic-bezier(.34,1.56,.64,1);
}
/* 开启态用主题红（与「应用红」同一支），不再用系统绿：
   那年今日 / 自动备份 两个开关都吃这一条，深色下由 --accent-fill 换成暗一档的赭红 */
.switch.on{background:var(--accent-fill,var(--accent))}
.switch.on .knob{transform:translateX(20px)}
/* 三档选择导航（我的页 · 夜间模式：系统 / 浅色 / 深色）
   与顶栏「时光轴 / 照片墙」完全同款：胶囊轨道 + 白色浮块滑块，
   尺寸/字重/动画曲线全部对齐 .view-tabs（js/night-font.js 的 syncSegPill 量位）。 */
.seg-nav{
  position:relative;
  flex:0 0 auto;
  margin-left:auto;
  display:flex;
  padding:3px;
  /* 圆角跟着按钮一起收小：从满圆胶囊改成小圆角矩形 */
  border-radius:9px;
  background:rgba(28,28,30,.08);
  transition:background .35s;
}
.seg-pill{
  position:absolute;
  left:0;top:3px;
  height:calc(100% - 6px);
  width:0;
  border-radius:7px;
  background:#ffffff;
  box-shadow:0 1px 3px rgba(30,30,70,.10),0 1px 1px rgba(30,30,70,.04);
  pointer-events:none;
  will-change:transform,width;
  transition:transform .42s cubic-bezier(.22,1,.36,1),width .42s cubic-bezier(.22,1,.36,1),background .35s,box-shadow .35s;
}
@media (prefers-reduced-motion:reduce){
  .seg-pill{transition:background .35s,box-shadow .35s}
}
.seg-btn{
  position:relative;z-index:1;
  appearance:none;
  border:none;background:transparent;cursor:pointer;
  font-family:var(--font-serif);
  font-size:calc(12.5px * var(--fs));font-weight:600;
  letter-spacing:.1em;
  line-height:1;
  /* 30px / 15px 内边距显得笨重，收成 26px / 11px，三档排在一起更紧凑 */
  height:26px;
  padding:0 11px;
  border-radius:7px;
  color:var(--ink-3);
  transition:color .26s;
}
.seg-btn.on{color:var(--ink)}

/* ===== 我的页改版（参照 my.html，仅布局）===== */
/* 头像：我的这一枚（点击进个人信息） */
.pf-pair{
  display:flex;flex-direction:column;align-items:center;
  margin-bottom:5cqh;
}
.pf-avatars{
  position:relative;
  display:flex;align-items:center;justify-content:center;
  padding-top:4.5cqh;
}
.ava{
  width:56px;height:56px;
  border-radius:50%;
  border:2px solid var(--card-bg);
  box-sizing:content-box;
  flex:0 0 auto;
  display:grid;place-items:center;
  transition:border-color .35s;
}
.pf-me{
  position:relative;z-index:2;
  background:#e5e5e7;color:rgba(60,60,67,.55);
  transition:background-color .35s,color .35s;
}
.pf-me svg{
  width:28px;height:28px;
  stroke:currentColor;fill:none;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;
}
/* 换过头像：铺满小圆并藏掉默认人像；登录后点头像进「个人信息」 */
#page-profile .pf-me{cursor:pointer}
/* 三个子属性都写死：夜间若被简写重置也不会出现平铺/拉长 */
.pf-me.has-img{background-size:cover;background-position:center;background-repeat:no-repeat}
.pf-me.has-img svg{display:none}

/* 按钮型设置行（字体大小 / 清空数据）*/
button.p-toggle-row{
  width:100%;
  font-family:var(--font-serif);text-align:left;cursor:pointer;appearance:none;
}
button.p-toggle-row:active{
  background:#f6f6f4;transition-duration:.12s;
}
.p-row-side{
  display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;
}

/* 行式列表（账户管理 / 意见反馈 / 关于）*/
.p-row{
  display:flex;align-items:center;gap:11px;   /* 与 .p-toggle-row 同间距：两组的行首文字落在同一列 */
  width:100%;min-height:56px;padding:0 4cqw;cursor:pointer;
  background:#ffffff;
  border:none;
  border-bottom:var(--hairline);
  font-family:var(--font-serif);text-align:left;appearance:none;
  transition:background .35s,border-color .35s;
}
.p-row:last-child{border-bottom:none}
.p-row:active{background:#f6f6f4;transition-duration:.12s}
.p-row-label{
  flex:1;min-width:0;
  font-size:calc(clamp(13px,3.3cqw,14.5px) * var(--fs));
  letter-spacing:.1em;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:color .35s;
}
.p-row-value{
  flex:0 0 auto;
  font-family:var(--font-mono);
  font-size:calc(clamp(10px,2.5cqw,11px) * var(--fs));
  letter-spacing:.08em;color:var(--ink-3);
  transition:color .35s;
}
.p-row-arrow{
  flex:0 0 auto;width:13px;height:13px;
  stroke:var(--icon-3);fill:none;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round;
  transition:stroke .35s;
}

/* 退出登录已并入「账号安全」页的列表（和注销账户同款行式条目，见 css/auth.css 的 .sec-row） */

/* ===== 关于页（logo / 口号 / 检查更新居中，底部政策与协议） ===== */
.about-body{
  flex:1;min-height:0;
  display:flex;flex-direction:column;
  padding:0 6cqw calc(0px + 3.2cqh);
}
.about-center{
  flex:1;min-height:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;
}
.about-logo{
  /* 两枚取景框落在圆角方形白底上，图形本体按根目录 logo.svg 等比映射（见 index.html 内联注释）。
     这三个色写死不走主题：品牌标记不反色，跟夜间那颗白色「检查更新」按钮同理——
     底一翻成深灰，logo 就不再是 logo 了。--al-accent 取 logo.svg 的原色 #e63946，
     不用主题赭 --accent(#b04a2c)：品牌文件的颜色跟着品牌文件走，不跟页面主题走。 */
  --al-bg:#ffffff;
  --al-ink:#1a1a1a;
  --al-accent:#e63946;
  /* 投影会溢出 viewBox，所以要 overflow:visible，否则圆角卡的阴影被切平 */
  width:calc(clamp(64px,16cqw,78px) * var(--fs));height:auto;
  overflow:visible;
}
.about-name{
  margin-top:3cqh;
  font-size:calc(clamp(22px,6.4cqw,30px) * var(--fs));
  font-weight:500;letter-spacing:.3em;text-indent:.3em;
  color:var(--ink);transition:color .35s;
}
.about-slogan{
  margin-top:1.4cqh;
  font-size:calc(clamp(11px,2.9cqw,13px) * var(--fs));
  letter-spacing:.22em;text-indent:.22em;
  color:var(--ink-3);transition:color .35s;
}
.about-check{
  margin-top:5cqh;cursor:pointer;appearance:none;
  min-height:46px;padding:0 9cqw;
  background:#1c1c1e;color:#ffffff;border:none;
  border-radius:999px;   /* 独立动作按钮：整颗胶囊 */
  font-family:var(--font-serif);
  font-size:calc(clamp(13px,3.3cqw,14.5px) * var(--fs));
  letter-spacing:.18em;text-indent:.18em;
  transition:opacity .2s,background .35s,color .35s;
}
/* 查到新版：按钮从「实心黑的操作钮」变成「白底 + 主色描边」的待办态，
   只改观感，不会自己弹窗 —— 点它才打开更新说明 */
.about-check.has-new{
  background:#ffffff;color:var(--accent,#e8452f);
  box-shadow:inset 0 0 0 1px currentColor;
}
.about-check:active{opacity:.85}
.about-version{
  margin-top:2.4cqh;
  font-family:var(--font-mono);
  font-size:calc(clamp(10px,2.5cqw,11px) * var(--fs));
  letter-spacing:.12em;color:var(--ink-3);transition:color .35s;
}
.about-links{
  flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;gap:14px;
  padding:2.4cqh 0 0;
}
.about-link{
  appearance:none;background:none;border:none;cursor:pointer;
  font-family:var(--font-serif);
  font-size:calc(clamp(11px,2.7cqw,12px) * var(--fs));
  letter-spacing:.1em;color:var(--ink-2);transition:color .35s;
}
.about-link:active{opacity:.65}
.about-link-sep{width:1px;height:1em;background:var(--ink-3-solid);opacity:.6}

/* 「我的」页主要文字加粗一档（Noto Serif SC 500），辅助小字保持原样 */
#page-profile .p-entry span,
#page-profile .p-toggle-info > span,
#page-profile .p-row-label,
#page-profile .p-row-value{font-weight:500}

/* 夜间切换时文字与卡片底色同拍（.35s）过渡，避免文字先翻色、底色后跟上的割裂感 */
#page-profile .p-entry span,
#page-profile .p-toggle-info > span,
#page-profile .p-toggle-info small,
#page-profile .p-row-label,
#page-profile .p-row-value,#page-profile .about{transition:color .35s}
#page-profile .p-entry svg,
#page-profile .p-ico{transition:stroke .35s}

#page-profile.logged-out .pf-me{cursor:pointer}

/* ===== 回收站 ===== */
.trash-head{
  position:relative;
  flex:0 0 auto;display:flex;align-items:center;gap:1.6cqw;
  padding:calc(0px + 14px) 5cqw 10px;
  /* 同 .topbar：收藏/回收站/作品集等页的列表触底上拉时会从头部底下穿过，
     头部补上不透明底，内容穿上来时被遮住（夜间色走 --page-bg） */
  background:var(--page-bg);
}
/* 返回按钮（全站统一）：无横线小箭头坐在白圆底上，配一枚柔和投影；
   夜间换深色圆底、去掉投影只留 0.5px 内描边（见 night-font.css）。
   搜索页例外：不要圆底不要投影，只要箭头本身（见 .search-back）。 */
.trash-back{
  flex:0 0 auto;width:34px;height:34px;margin-left:-6px;
  display:grid;place-items:center;padding:0;
  background:var(--card-bg);
  border:none;border-radius:50%;
  box-shadow:0 2px 10px -3px rgba(28,28,30,.18), 0 1px 3px rgba(28,28,30,.06);
  cursor:pointer;color:var(--ink-2);
  transition:transform .2s,color .2s,box-shadow .2s;
}
.trash-back:active{transform:scale(.9);color:var(--ink)}
.trash-back svg{
  width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
}
/* 选择态：左上角的返回箭头换成 ✕（点它 = 取消选择，不是退出页面）。
   开关由 .page.selecting 驱动 —— 回收站/作品集在 syncStashChrome 里同步，
   数据清空页在它自己的 updateBar 里同步（那一页本来就用这个 class）。 */
.trash-back .ic-cancel{display:none}
.page.selecting .trash-back .ic-back{display:none}
.page.selecting .trash-back .ic-cancel{display:block}
.page.selecting .trash-back{color:var(--ink)}
/* 标题一律水平居中：绝对定位到头部中线，左右两侧的返回键 / 全选 / 计数
   都不再挤动标题的位置（头部高度仍由返回键撑住） */
.trash-title{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  margin:0;white-space:nowrap;pointer-events:none;
  font-size:calc(clamp(15px,4cqw,17px) * var(--fs));font-weight:400;letter-spacing:.16em;color:var(--ink);
}
/* 全选：纯图标按钮（勾选框 = 全选 / 减号 = 取消全选）。
   原来是一条文字按钮，多选态下太抢眼，也把标题挤到中间；
   改成右上角一枚无底色的图标，和顶栏其他图标同一语系。 */
.sel-all-btn{
  margin-left:auto;
  flex:0 0 auto;
  width:34px;height:34px;padding:0;
  display:grid;place-items:center;
  border:none;
  border-radius:50%;
  background:none;
  color:var(--icon-2);
  cursor:pointer;appearance:none;
  transition:opacity .18s,transform .18s,color .2s;
}
.sel-all-btn svg{
  width:19px;height:19px;
  fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
}
.sel-all-btn .ic-none{display:none}
/* 全部已选：图标换成减号，颜色压深一档表示「再点一下取消」 */
.sel-all-btn.on{color:var(--ink)}
.sel-all-btn.on .ic-all{display:none}
.sel-all-btn.on .ic-none{display:block}
.sel-all-btn:active{transform:scale(.9)}
.sel-all-btn.hide{opacity:0;pointer-events:none}
/* 旧的文字按钮样式留着：别的页面（如反馈历史）还在用 .trash-all 的排布 */
.trash-all{
  margin-left:auto;
  padding:6px 0 6px 10px;
  background:none;border:none;cursor:pointer;
  font-family:var(--font-sans);font-size:calc(clamp(11px,2.9cqw,12.5px) * var(--fs));
  letter-spacing:.12em;color:var(--accent);
}
.trash-all.off{color:var(--ink-3)}
.trash-all:active{opacity:.55}
/* ===== 回收站 / 作品集：纯图片网格（格子里不放任何文字） ===== */
.stash-scroll{
  flex:1;min-height:0;overflow-y:auto;position:relative;
  padding:0 5cqw calc(92px + 0px);
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
}
.stash-scroll::-webkit-scrollbar{display:none}
.stash-grid{
  display:grid;grid-template-columns:repeat(4,1fr);
  gap:1.4cqw;
  align-content:start;
}
.stash-grid > .empty{grid-column:1 / -1}

.stash-cell{
  position:relative;display:block;width:100%;aspect-ratio:1;
  padding:0;border:none;border-radius:2px;overflow:hidden;cursor:pointer;
  background:rgba(28,28,30,.05);
  /* 横向手势归长按扫选，纵向仍可滚动；长按别弹系统选字/复制菜单 */
  touch-action:pan-y;
  -webkit-touch-callout:none;-webkit-user-select:none;user-select:none;
}
.stash-cell .photo-img{
  position:absolute;inset:0;
  transition:transform .32s cubic-bezier(.22,1,.36,1),opacity .2s;
}
.stash-cell .stroke-layer{position:absolute;inset:0;width:100%;height:100%}
.stash-cell:active .photo-img{transform:scale(.97)}
.stash-cell.on .photo-img{transform:scale(.9);opacity:.75}
/* 复选框默认藏起来，长按（或已有选中）后才浮出 */
.stash-check{
  position:absolute;right:1.4cqw;top:1.4cqw;z-index:2;
  width:20px;height:20px;padding:0;
  border-radius:50%;border:1px solid rgba(255,255,255,.9);
  background:rgba(255,255,255,.42);
  box-shadow:0 1px 6px rgba(0,0,0,.18);
  cursor:pointer;display:grid;place-items:center;
  opacity:0;transform:scale(.55);pointer-events:none;
  transition:opacity .18s,transform .18s,background .2s,border-color .2s;
}
.stash-check::after{
  content:'';width:9px;height:5px;margin-top:-2px;
  border-left:1.6px solid transparent;border-bottom:1.6px solid transparent;
  transform:rotate(-45deg);
  transition:border-color .2s;
}
.stash-check.on{background:var(--danger-fill);border-color:var(--danger-fill)}
.stash-check.on::after{border-color:#fff}
.stash-grid.sel .stash-check{opacity:1;transform:none}
.stash-cell.on .stash-check{opacity:1;transform:none}

/* 底部操作：不再是贴边的整条白条，改成居中的悬浮胶囊。
   已选数量并到标题里（回收站 · 已选 3），底部只留动作本身。 */
.trash-bar{
  position:absolute;left:0;right:0;bottom:0;z-index:20;
  display:flex;align-items:center;justify-content:center;gap:10px;
  padding:12px 5cqw calc(12px + env(safe-area-inset-bottom, 0px));
  background:none;border-top:none;
  pointer-events:none;                /* 空白处不挡下面的网格滚动 */
  transform:translateY(140%);
  transition:transform .28s cubic-bezier(.22,1,.36,1);
}
.trash-bar.on{transform:none}
.trash-bar > span{display:none}       /* 计数已并入标题 */

/* 一片胶囊装下这一组动作：左「恢复」透明、右「永久删除」红底，
   两个动作属于同一次选择，不该各飘一颗圆钮 */
.act-pill{
  display:flex;align-items:stretch;
  pointer-events:auto;
  border-radius:999px;
  overflow:hidden;
  background:var(--card-bg);
  border:1px solid var(--card-border);
  box-shadow:var(--float-shadow);
}
.act-btn{
  display:flex;align-items:center;justify-content:center;gap:6px;
  height:44px;padding:0 20px;
  border:none;background:none;cursor:pointer;appearance:none;
  font-family:var(--font-sans);font-size:calc(clamp(12px,3cqw,13px) * var(--fs));
  letter-spacing:.1em;line-height:1;
  color:var(--ink);
  -webkit-tap-highlight-color:transparent;
  transition:background .2s,color .2s,opacity .2s;
}
/* 两个动作之间的分隔线：细到 1px，只用来分界，不制造第二层底色 */
.act-btn + .act-btn{box-shadow:inset 1px 0 0 var(--card-border)}
.act-btn svg{
  width:15px;height:15px;flex:0 0 auto;
  fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;
}
/* 危险动作不用红色，也不铺深色块：整颗胶囊就是一层浅底 + 一圈细描边，
   两段文字同为墨色，靠中间那条分隔线区分 —— 红只留给确认弹窗那一下。 */
.act-btn.danger{background:none;color:var(--ink)}
.act-btn:active{opacity:.6}
/* 单动作（作品集 / 清空数据页）：整颗胶囊就是那只红按钮 */
.act-pill > .act-btn:only-child{padding:0 24px}

.trash-all.hide{opacity:0;pointer-events:none}

/* ===== 预览查看器（轮播） =====
   舞台默认是白底（照片像一张摊在白纸上的相纸），轻点照片切到黑底沉浸态：
   只剩照片，顶部张数与底部按钮全部淡出；再轻点回到白底全套界面。
   背景色走 --v-bg-rgb，`--bg-a` 仍由下滑关闭/飞回卡片时衰减。 */
.viewer{
  /* 用 !important 锁住预览页自己的色板：夜间主题（night-font.css）按页面级
     变量统一翻白时会把这里的 --v-muted 一并翻掉，白底上星标/评论/拼图
     图标就看不见了。预览页白底/黑底自管，不让外部主题掺和。 */
  --v-bg-rgb:255,255,255;
  --v-fg:#1c1c1e;
  --v-accent:var(--accent) !important;
  --v-muted:rgba(28,28,30,.55) !important;
  --v-line:rgba(28,28,30,.10);
  --v-shadow:0 24px 60px -26px rgba(0,0,0,.22);
  --bg-a:1;
  /* 照片上下要留出的总高度（顶部张数 + 底部动作条）。
     横屏时高度紧张，由 @media (max-height:520px) 压到 120px。 */
  --v-pad-y:176px;
  position:absolute;inset:0;z-index:300;display:grid;place-items:center;
  background-color:rgba(var(--v-bg-rgb),var(--bg-a,1));
  opacity:0;pointer-events:none;
  transition:opacity .4s ease, background-color .3s ease;
  touch-action:none;
  overflow:hidden;
}
/* 从编辑页原路回预览时挂上：预览瞬间盖住底页，不再走 0.4s 淡入。
   否则切页动画 + 淡入叠在一起，中途会看见底下的回忆页。 */
.viewer.no-fade{transition:none}
/* 沉浸态：黑场 + 隐藏全部界面元素（关闭钮、张数、底部操作） */
.viewer.dim{--v-bg-rgb:0,0,0}
.viewer.dim .v-close,
.viewer.dim .v-live,
.viewer.dim .v-counter,
.viewer.dim .viewer-text{opacity:0;pointer-events:none}

/* 抽屉展开态：同样隐藏顶部关闭钮/张数、底部操作 —— 信息页是主舞台 */
.viewer.drawer-open .v-close,
.viewer.drawer-open .v-counter,
.viewer.drawer-open .viewer-text{opacity:0;pointer-events:none}

/* 左上角关闭按钮：磨砂白圆 + 深色叉，落在照片或白底上都看得清 */
.v-close{
  position:absolute;
  left:6cqw;
  /* 圆心对准顶部张数文字的中线；原生壳里让到状态栏下面（--sf-sat 由 cap-bridge 写入），
     照片本身仍铺满整屏 —— 沉浸式该是这样：画面在栏下，控件不压系统图标 */
  top:calc(max(6cqh, calc(var(--sf-sat, env(safe-area-inset-top, 0px)) + 14px)) - 11px);
  z-index:5;
  width:34px;height:34px;
  display:grid;place-items:center;
  padding:0;border:none;border-radius:50%;
  background:rgba(255,255,255,.88);
  color:#1c1c1e;
  box-shadow:0 2px 12px -2px rgba(0,0,0,.22), 0 1px 3px rgba(0,0,0,.08);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  cursor:pointer;appearance:none;
  -webkit-tap-highlight-color:transparent;
  transition:opacity .26s ease, background .2s ease, transform .18s ease;
}
.v-close svg{
  width:16px;height:16px;
  fill:none;stroke:currentColor;stroke-width:2.2;
  stroke-linecap:round;stroke-linejoin:round;
}
.v-close:active{transform:scale(.92);background:rgba(255,255,255,.7)}

/* 右上角实况按钮：和关闭钮同一套磨砂白圆（同心圆对齐），只是图标是播放。
   只有当前这张是实况图才出现 —— 显示/隐藏由 JS 控制 hidden 属性。 */
.v-live{
  position:absolute;
  right:6cqw;
  top:calc(max(6cqh, calc(var(--sf-sat, env(safe-area-inset-top, 0px)) + 14px)) - 11px);
  z-index:5;
  width:34px;height:34px;
  display:grid;place-items:center;
  padding:0;border:none;border-radius:50%;
  background:rgba(255,255,255,.88);
  color:#1c1c1e;
  box-shadow:0 2px 12px -2px rgba(0,0,0,.22), 0 1px 3px rgba(0,0,0,.08);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  cursor:pointer;appearance:none;
  -webkit-tap-highlight-color:transparent;
  opacity:0;transform:scale(.9);
  transition:opacity .22s ease, transform .22s ease, background .2s ease, color .2s ease;
}
.v-live[hidden]{display:none}
.v-live:not([hidden]){opacity:1;transform:none}
.v-live svg{
  width:18px;height:18px;
  fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
}
.v-live:active{transform:scale(.92);background:rgba(255,255,255,.7)}
.v-live.on{color:var(--accent)}       /* 正在播：图标转主题红 */
.v-live.busy{opacity:.55}

/* 实况视频层：盖在静帧上，铺满整个照片盒（和 .photo-img 同一块区域） */
.viewer-photo .vp-live{
  position:absolute;inset:0;z-index:2;
  width:100%;height:100%;
  object-fit:cover;
  background:#000;
  animation:vpLiveIn .18s ease-out both;
}
@keyframes vpLiveIn{from{opacity:0}to{opacity:1}}
.viewer.on{opacity:1;pointer-events:auto}
/* 图片取三者的最小值：两边占满整个屏宽 / 底部图标改为悬浮后照片可再高一些 */
.viewer-inner{width:100cqw;text-align:center;position:relative}
.v-track{
  display:flex;
  column-gap:14px;      /* 相邻图片之间留一道间隙（JS 的翻页步长 = slide宽 + 14px，两边要同步改） */
  align-items:center;   /* 每张 slide 在轨道内垂直居中：矮图不再贴顶 */
  will-change:transform;
}
.v-slide{
  flex:0 0 100%;
  width:100%;
  min-width:0;
}
/* 预览页只看照片本身：没有白卡、没有模板装饰，按原图比例摆放
   比例由 JS 写入 --v-ar（拿不到时 1:1）；高度/宽度都钳在可用区域内 */
.viewer-photo{
  position:relative;margin:0 auto;
  /* 按图片真实比例（JS 写入 --v-ar）判断：宽图按屏宽、高图按可用高换算，
     宽度取两者较小值 → 图片盒恒等于原图比例，cover 不再裁切，双向居中 */
  width:min(100cqw, calc((100cqh - var(--v-pad-y, 176px)) * var(--v-ar, 1)));
  aspect-ratio:var(--v-ar, 1);
  overflow:hidden;
  background:transparent;
  will-change:transform,opacity;
  transform-origin:center center;
  cursor:pointer;
  -webkit-touch-callout:none;
  -webkit-user-select:none;user-select:none;
}
.viewer-photo .vp-inner{position:relative;width:100%;height:100%;overflow:hidden}
.viewer-photo .photo-img{
  position:absolute;inset:0;
  background-size:cover;background-position:center;
}
/* ==================================================================
   预览页同一屏分栏（show.html 骨架，逐字对齐）
   三层完全复刻 show.html 的 .stage / .wrapper / .img-pane / .info-pane
   · v-stage = .stage          —— fixed/absolute + touch-action:none + cursor:grab
   · v-wrapper = .wrapper      —— height:1.666667*page-h + transform:translate3d(0,-p*0.666667*page-h,0)
   · v-img-pane = .img-pane    —— height: page-h（固定 1 屏）
   · v-info-pane = .info-pane  —— height: 0.666667 * page-h（固定 2/3 屏）
   viewer-inner(多图) 放在 v-img-pane 里，保持原 grid 居中逻辑。
   ================================================================== */
.v-stage{
  position:absolute;inset:0;z-index:1;
  overflow:hidden;
  touch-action:none;
  user-select:none;
  -webkit-user-select:none;
  cursor:grab;
  --p:0;                              /* 进度变量：JS 写 vStageEl.style.setProperty('--p', ...) */
  --page-h:100vh;                     /* show.html 用 100dvh，我用 100vh 等价 */
}
.v-stage.dragging{cursor:grabbing}

/* 内容轨道：整块上移 —— show.html .wrapper 的逻辑 */
.v-wrapper{
  position:relative;
  height:calc(var(--page-h) * 1.666667);
  transform:translate3d(0, calc(var(--p) * var(--page-h) * -0.666667), 0);
  will-change:transform;
  transition:none !important;   /* 强制禁 CSS transition —— JS RAF 驱动 */
}

/* 第一页：固定 1 屏高 + grid 居中 viewer-inner（恢复 viewer 原来的居中行为）。
   JS 在 vDApply 里写 viewer-inner 的 translateY = p * (vImgH - vInnerH) / 2，
   让图片从 center 线性滑到 v-img-pane 底边 → 贴 info-pane 顶边 */
.v-img-pane{
  position:relative;
  height:var(--page-h);
  overflow:hidden;
  display:grid;
  place-items:center;
  transition:none !important;   /* 强制禁 CSS transition —— JS 跟手驱动 */
}

/* 第二页：固定 2/3 屏高（show.html .info-pane）。
   顶部两边圆角 + 柔和上阴影（日间模式），和上面的图片做分层 */
.v-info-pane{
  position:relative;
  height:calc(var(--page-h) * 0.666667);
  overflow:hidden;
  background:rgba(var(--v-bg-rgb,255,255,255),1);
  color:var(--v-fg);
  /* 打开时直接显示 —— 不做任何动画，强制禁继承的 transition */
  opacity:1;
  transform:none;
  transition:none !important;
}
/* 内部文字元素也强制禁 transition —— 防止从祖先继承来的 transition:all */
.v-info-pane *{transition:none !important;animation:none !important;}
.v-info-body{
  height:100%;
  overflow-y:auto;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
  scrollbar-width:none;
  padding:14px 24px calc(env(safe-area-inset-bottom) + 18px);
}
.v-info-body::-webkit-scrollbar{display:none}

/* 黑底沉浸态：强制 --p=0 + wrapper translateY(0)，两页回到起始位置 */
.viewer.dim .v-stage{ --p:0 !important; cursor:default; }
.viewer.dim .v-info-pane{ background:rgba(0,0,0,0); border-top-color:rgba(0,0,0,0); box-shadow:none; opacity:0 !important; }

/* ---- 信息页内容排版 ---- */
.v-info-row{
  display:flex;align-items:flex-start;gap:14px;
  padding:14px 0;
  border-bottom:1px solid var(--v-line);
}
.v-info-row:last-child{border-bottom:none}
.v-info-row .v-label{
  flex:0 0 54px;font-size:13px;color:rgba(28,28,30,.55);letter-spacing:.04em;
}
.v-info-row .v-val{
  flex:1 1 auto;min-width:0;font-size:15px;line-height:1.5;color:var(--v-fg);word-break:break-word;
}
.v-info-row .v-val .v-date-time{
  font-variant-numeric:tabular-nums;
}
.v-info-row .v-geo{
  display:inline-flex;align-items:center;gap:6px;
}
.v-info-row .v-geo svg{
  width:14px;height:14px;flex:0 0 auto;
  fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round;color:rgba(28,28,30,.5);
}

.v-info-desc{
  padding:18px 0 6px;
  font-size:16px;line-height:1.65;color:var(--v-fg);white-space:pre-wrap;word-break:break-word;
}
.v-info-desc:empty{display:none}

/* 大图用 <img> 而不是背景图：放大到 4~6 倍时浏览器按解码位图重采样，
   背景图那种「整层按旧栅格拉伸」会明显糊 */
.viewer-photo img.photo-img{
  width:100%;height:100%;display:block;
  object-fit:cover;object-position:center;
  -webkit-user-drag:none;user-select:none;pointer-events:none;
}

/* 固定的操作图标区：悬浮在底部，与顶部张数文字同一偏移、上下对称 */
.viewer-text{
  position:absolute;
  left:0;right:0;
  /* 悬浮在底部：原生壳里抬到导航条安全区之上，网页端回落 env()；离底边更近 */
  bottom:max(3.4cqh, calc(var(--sf-sab, env(safe-area-inset-bottom, 0px)) + 10px));
  margin:0;
  display:flex;
  justify-content:center;
  z-index:2;
  /* 切黑场时整排淡出（JS 的收起/关闭动画会临时覆盖这条 transition） */
  transition:opacity .26s ease;
}
/* 回收站 / 清空数据页的预览：白色圆钮同样贴底悬浮 */
.viewer.ops .viewer-text{
  bottom:calc(var(--sf-sab, env(safe-area-inset-bottom, 0px)) + 14px);
}

/* ===== 预览页底部操作条（收藏 / 拼图 / 下载 / 分享） =====
   实底圆角悬浮条，观感与左上角关闭按钮同一套：
   磨砂白实底 + 深墨图标 + 同款投影，不用 backdrop-filter（毛玻璃已去掉）。 */
.v-actions{
  display:flex;
  align-items:flex-end;
  justify-content:center;
  /* 五颗（分享/收藏/删除/编辑/更多），每颗 = 图标 + 底部文字。
     字宽撑开之后整条反而比六颗图标时更短，390 宽下总宽约 300 */
  gap:clamp(8px,3.6cqw,20px);
  margin-top:0;
  padding:7px clamp(12px,4cqw,20px) 6px;
  border-radius:999px;
  background:rgba(255,255,255,.88);
  border:none;
  box-shadow:var(--float-shadow);
}
.v-action{
  /* 图标在上、文字在下：宽度跟着文字走（min-width 兜住「分享/收藏」两字也够稳） */
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:flex-end;
  gap:4px;
  min-width:clamp(38px,10.4cqw,48px);
  padding:0;
  background:none;
  border:none;
  cursor:pointer;
  /* 图标墨色与左上角关闭按钮同一支（#1c1c1e），不再用半透明 muted */
  color:#1c1c1e !important;
  transition:transform .2s ease;
  -webkit-tap-highlight-color:transparent;
}
/* 图标下方的动作名：只画图标要用户靠猜，文字压一档不抢画面 */
.v-action-label{
  font-family:var(--font-sans);
  font-size:calc(clamp(10px,2.6cqw,11px) * var(--fs));
  letter-spacing:.04em;
  line-height:1;
  color:inherit;
  opacity:.6;
  transition:opacity .18s ease;
}
.v-action.on .v-action-label{opacity:.95}
.v-action svg{
  width:clamp(19px,4.8cqw,22px);
  height:clamp(19px,4.8cqw,22px);
  stroke:currentColor;
  fill:none;
  stroke-width:1.5;
  stroke-linecap:round;
  stroke-linejoin:round;
}
.v-action:active{transform:scale(.9)}
.v-action.on{color:var(--v-accent) !important}   /* 基础色带 !important，这里必须同级压过，否则实心红不生效 */
.v-action.on svg{fill:var(--v-accent);stroke:var(--v-accent)}   /* 单一颜色来源：fill/stroke 直接取主题红，不依赖 currentColor */

/* Lucide 占位元素未渲染时的兜底（避免布局跳动） */
.v-action i[data-lucide]{
  display:block;
  width:clamp(19px,4.8cqw,22px);
  height:clamp(19px,4.8cqw,22px);
}

/* ===== 预览页「更多」菜单（#v-menu）=====
   在「更多」按钮正上方弹出的一列动作，不是底部上拉面板：
   位置由 JS 按按钮矩形写 inline bottom/right，转屏/横屏也跟着按钮走。
   一列（整体列表排布）：下载 / 拼图 / 旋转 / 幻灯片播放。 */
.v-menu-mask{
  position:absolute;inset:0;z-index:310;
  background:transparent;
  opacity:0;pointer-events:none;
  transition:opacity .18s ease;
}
.v-menu-mask.on{opacity:1;pointer-events:auto}
.v-menu{
  position:absolute;z-index:311;
  min-width:148px;
  padding:6px;
  border-radius:16px;
  background:rgba(255,255,255,.97);
  box-shadow:var(--float-shadow);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  /* 从按钮那一角长出来：缩放锚点固定右下 */
  transform-origin:100% 100%;
  opacity:0;transform:translateY(8px) scale(.94);
  pointer-events:none;
  transition:opacity .16s ease, transform .22s cubic-bezier(.22,1,.36,1);
}
.v-menu.on{opacity:1;transform:none;pointer-events:auto}
.v-menu-item{
  display:flex;align-items:center;gap:11px;
  width:100%;padding:10px 12px;
  border:none;border-radius:10px;background:none;
  color:#1c1c1e;
  font-family:var(--font-sans);
  font-size:calc(clamp(12.5px,3.2cqw,14px) * var(--fs));
  letter-spacing:.06em;text-align:left;
  cursor:pointer;appearance:none;
  -webkit-tap-highlight-color:transparent;
  transition:background .16s ease;
}
.v-menu-item:active{background:rgba(28,28,30,.07)}
.v-menu-item svg{
  width:17px;height:17px;flex:0 0 auto;
  stroke:currentColor;fill:none;
  stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;
}
.v-menu-item i[data-lucide]{display:block;width:17px;height:17px;flex:0 0 auto}

/* ===== 预览页照片旋转（「更多」→ 旋转，每次逆时针 90°）=====
   只转显示：.vp-inner 绕中心旋转，盒子按旋转后的宽高比重排（--v-ar-rot 由 JS 写好），
   否则 90° 时横向会被裁掉一截。缩放/位移仍作用在最外层 .viewer-photo 上，两者不打架。
   角度走变量 --v-rot（JS 写 inline 变量，不写 inline transform，免得和这里的
   translate(-50%,-50%) 互相覆盖）。 */
.viewer-photo .vp-inner{
  transform-origin:50% 50%;
  will-change:transform;
}
/* 转成竖版（90°/270°）：盒子换成倒数比例，内部按「原尺寸」摆好再转 */
.viewer-photo.rot-quarter{
  width:min(100cqw, calc((100cqh - var(--v-pad-y, 176px)) / var(--v-ar, 1)));
  aspect-ratio:var(--v-ar-rot, 1);
}
.viewer-photo.rot-quarter .vp-inner{
  position:absolute;top:50%;left:50%;
  width:min(calc(100cqh - var(--v-pad-y, 176px)), calc(100cqw * var(--v-ar, 1)));
  height:auto;
  aspect-ratio:var(--v-ar, 1);
  transform:translate(-50%,-50%) rotate(var(--v-rot, 90deg));
}
.viewer-photo.rot-half .vp-inner{transform:rotate(var(--v-rot, 180deg))}

/* ===== 回收站 / 清空数据页的预览：底部换成「对当前这一张」的操作 =====
   其余来源（首页/照片墙/日历…）仍用上面那排图标；这里只在 .viewer.ops 时换。
   两个动作装进同一颗白色胶囊：左「恢复」黑、右「删除」红，中间一条细分隔线。
   以前是两颗各自浮着的白圆钮，和列表页底部的操作不是同一套语言。 */
.v-ops{
  display:none;align-items:stretch;justify-content:center;
  border-radius:999px;overflow:hidden;
  background:#fff;
  box-shadow:0 10px 28px -12px rgba(0,0,0,.28), 0 1px 4px rgba(0,0,0,.08);
}
.viewer.ops .v-actions{display:none}
.viewer.ops .v-ops{display:flex}
/* 清空数据页只有「清空」一个操作，恢复按钮不出现；只剩一只时胶囊两端自然收圆 */
.viewer.ops-single .v-op[data-op="restore"]{display:none}

.v-op{
  display:flex;flex-direction:row;align-items:center;justify-content:center;gap:6px;
  height:clamp(40px,11.2cqw,46px);
  padding:0 clamp(16px,4.6cqw,20px);
  border:none;border-radius:0;
  background:none;color:#1c1c1e;
  font-family:var(--font-sans);
  cursor:pointer;appearance:none;
  -webkit-tap-highlight-color:transparent;
  transition:background .18s ease;
}
/* 两个动作之间的分隔线用内阴影画，不额外加元素 */
.v-op + .v-op{box-shadow:inset 1px 0 0 rgba(28,28,30,.10)}
/* 删除不用红字：这排按钮在照片下方，红字会把视线从照片上拽走；
   真正不可逆的那一步由确认弹窗负责提示 */
.v-op[data-op="purge"]{color:#1c1c1e}
.v-op svg{
  width:clamp(15px,4cqw,17px);
  height:clamp(15px,4cqw,17px);
  flex:0 0 auto;
  fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;
}
.v-op .v-op-label{
  font-size:calc(clamp(11px,2.9cqw,12.5px) * var(--fs));
  line-height:1;letter-spacing:.08em;
  white-space:nowrap;
}
.v-op:active{background:#f2f1ef}

/* 操作行是圆形钮，位置由 JS 算在「照片下沿 → 屏幕底」的中间。
   极高竖图会把可用空白压到只剩 88px，居中后按钮离照片仅 17px —— 这张表里
   再收 40px，保证按钮上下都不少于 24px；方图/横图本来就矮，不受影响。 */
.viewer.ops .viewer-photo{
  width:min(100cqw, calc((100cqh - 216px) * var(--v-ar, 1)));
}

/* 这一排按钮正好落在 toast 的默认高度上：开着操作行时把提示抬到按钮上方。
   深色浮层上 #1c1c1e 的提示几乎看不见，补一圈极细白边 + 模糊底 */
.viewer.on.ops ~ #toast{
  bottom:calc(22cqw + 56px + 0px);
  background:rgba(38,38,41,.94);
  box-shadow:0 0 0 1px rgba(255,255,255,.15), 0 10px 28px rgba(0,0,0,.5);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
}

.v-counter{
  position:absolute;top:max(6cqh, calc(var(--sf-sat, env(safe-area-inset-top, 0px)) + 14px));left:50%;transform:translateX(-50%);
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,11px) * var(--fs));
  letter-spacing:.22em;color:var(--v-muted);
  z-index:2;
  will-change:transform,opacity;
  transition:opacity .26s ease;
}

/* 视口很矮（手机横屏）：照片尺寸被高度卡住后，收紧上下留白 */
@media (max-height:520px){
  /* 横屏：上下留白压到 120px，照片才有高度（旋转后的竖版也跟着这个值算） */
  .viewer{--v-pad-y:120px}
  .viewer-inner{width:100cqw}
  .viewer-text{bottom:max(4cqh, calc(var(--sf-sab, env(safe-area-inset-bottom, 0px)) + 10px))}
  .v-actions{margin-top:0}
  .v-action{min-width:34px;gap:3px}
  .v-action svg{width:18px;height:18px}
  .v-action-label{font-size:9px}
}

/* 横屏预览：内容列不再收窄到 560px，否则照片只剩中间一条。
   只在预览打开时放开（.viewer-open 由 JS 挂到 .device 上），
   关闭预览立刻还原，背后的列表不会莫名重排成宽版。 */
@media (orientation:landscape){
  .device.viewer-open .screen{max-width:none}
}

/* ===== 幻灯片（全屏播放这个月的照片，点一下结束） =====
   黑底 + contain：竖图横图都完整显示；层在最上面，横屏也不受内容列限制。 */
.slideshow{
  position:absolute;inset:0;z-index:900;
  display:grid;place-items:center;
  background:#000;
  opacity:0;pointer-events:none;
  transition:opacity .32s ease;
}
.slideshow.on{opacity:1;pointer-events:auto}
.ss-img{
  /* 绝对定位铺满黑框：用 grid 居中 + height:100% 时，横屏会把「100% 高度」
     解析成按宽度算出的固有高度（撑破黑框、上下被切），absolute 不吃这套 */
  position:absolute;left:0;top:0;
  width:100%;height:100%;
  object-fit:contain;
  opacity:0;
  transition:opacity .6s ease;
  -webkit-user-drag:none;user-select:none;pointer-events:none;
}
.ss-img.on{opacity:1}
.ss-top{
  position:absolute;left:0;right:0;
  top:calc(var(--sf-sat, env(safe-area-inset-top, 0px)) + 18px);
  text-align:center;
  font-family:var(--font-mono);
  font-size:calc(clamp(10px,2.4cqw,11.5px) * var(--fs));
  letter-spacing:.22em;color:rgba(255,255,255,.6);
  transition:opacity .5s ease;
}
.ss-hint{
  position:absolute;left:0;right:0;
  bottom:calc(var(--sf-sab, env(safe-area-inset-bottom, 0px)) + 26px);
  text-align:center;
  font-size:calc(clamp(11px,2.8cqw,12.5px) * var(--fs));
  letter-spacing:.16em;color:rgba(255,255,255,.4);
  animation:ssHintOut 5s ease forwards;
}
@keyframes ssHintOut{0%,55%{opacity:1}100%{opacity:0}}

.sheet{
  position:absolute;inset:0;z-index:400;display:flex;align-items:flex-end;
  background:rgba(20,20,28,.42);
  opacity:0;pointer-events:none;transition:opacity .28s;
  padding-bottom:var(--kb,0px);
}
.sheet.on{opacity:1;pointer-events:auto}
.sheet-inner{
  width:100%;background:#ffffff;
  /* 顶部两侧圆角：拼图 / 字体大小 / 文本备注几个弹层共用这套骨架 */
  border-radius:18px 18px 0 0;
  padding:4cqw 5cqw calc(4cqw + 0px);
  transform:translateY(100%);transition:transform .32s cubic-bezier(.22,1,.36,1),background .35s,border-color .35s;
}
.sheet.on .sheet-inner{transform:none}
.sheet-inner textarea{
  width:100%;min-height:72px;max-height:26vh;resize:none;outline:none;
  border:1px solid rgba(28,28,30,.12);background:#fafafa;border-radius:12px;
  font-family:var(--font-serif);font-size:calc(clamp(13px,3.4cqw,15px) * var(--fs));
  letter-spacing:.06em;line-height:1.7;color:var(--ink);padding:3cqw;
}
.sheet-inner textarea::placeholder{color:var(--ink-3)}

/* ===== 底部弹层骨架（拼图 / 字体大小 / 文本备注共用）===== */
.pt-inner{
  padding:8px 24px calc(32px + 0px);
  touch-action:none;will-change:transform;
}
/* 带输入框的两层（写下此刻 / 地点）单独放开 touch-action：
   touch-action 是「自身与所有祖先取交集」，只要 .pt-inner 是 none，
   输入框里点按就落不了光标 —— 光标永远停在文本末尾（用户说的「不能自定义位置输入」）。
   拖拽关闭的手感由 js/app.js bindSheetDrag 里的 touchmove preventDefault 保住。 */
#caption-inner,
#loc-inner,
#phone-sheet .pt-inner{touch-action:manipulation}
#caption-inner textarea,
#loc-inner input,
#phone-sheet input{touch-action:auto}
.sheet.dragging .pt-inner{transition:none}
.pt-handle{
  display:block;width:36px;height:4px;
  margin:0 auto 12px;border-radius:2px;
  background:rgba(28,28,30,.18);
  cursor:grab;transition:background .35s;
}

/* ===== 分享弹窗（#share-sheet）=====
   四个定向渠道（微信好友 / 朋友圈 / QQ好友 / QQ空间）+ 一条系统面板入口。
   图标用品牌色圆角方块，底下一行小字；不做投影，夜间只靠 --card-bg 换深底。 */
.sf-share-inner{
  padding:8px 20px calc(14px + var(--sf-sab, env(safe-area-inset-bottom, 0px)));
}
.sf-share-title{
  margin:2px 0 18px;
  text-align:center;
  font-family:var(--font-sans);
  font-size:calc(clamp(12.5px,3.2cqw,13.5px) * var(--fs));
  font-weight:500;letter-spacing:.16em;
  color:var(--ink-3);
}
.sf-share-grid{
  display:grid;grid-template-columns:repeat(5,1fr);
  gap:2px;margin-bottom:14px;
}
.sf-share-item{
  display:flex;flex-direction:column;align-items:center;gap:9px;
  padding:6px 0 2px;
  background:none;border:0;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.sf-share-ico{
  width:48px;height:48px;border-radius:16px;
  display:grid;place-items:center;
  color:#fff;
  transition:transform .2s cubic-bezier(.2,.8,.25,1), opacity .2s;
}
.sf-share-ico svg{width:24px;height:24px}
.sf-share-ico.wx{background:#2aae67}
.sf-share-ico.qq{background:#0099ff}
.sf-share-ico.qzone{background:#f7b500}
/* 第五格「更多」：中性灰底 + 深色描边图标，不抢前面四个品牌色 */
.sf-share-ico.more{background:rgba(28,28,30,.06);color:var(--ink-2)}
.sf-share-ico.more svg{
  fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
  width:22px;height:22px;
}
.device.night .sf-share-ico.more{background:rgba(255,255,255,.09);color:rgba(255,255,255,.6)}
.sf-share-item:active .sf-share-ico{transform:scale(.94)}
.sf-share-item.busy{pointer-events:none}
.sf-share-item.busy .sf-share-ico{opacity:.55}
.sf-share-name{
  font-family:var(--font-sans);
  font-size:calc(clamp(10.5px,2.7cqw,11.5px) * var(--fs));
  letter-spacing:.04em;
  color:var(--ink-2);
  transition:color .35s;
}
/* 系统面板那一条原来是一整行，现在并进网格当第五格，这里只剩取消 */
.sf-share-cancel{
  display:block;width:100%;height:44px;margin-top:6px;
  background:none;border:0;cursor:pointer;
  color:var(--ink-3);
  font-family:var(--font-sans);
  font-size:calc(clamp(12px,3cqw,13.5px) * var(--fs));
  letter-spacing:.08em;
}
.sf-share-cancel:active{opacity:.6}
.pt-handle:active{cursor:grabbing}

/* 顶部图形按钮栏（字体大小 / 写下此刻 / 绑定手机号共用）
   —— 复用日期弹窗的 .year-picker-bar + 圆形 ✕ / ✓，位置也要一模一样：
      按钮距面板左右各 12px（3cqw 内边距）、距面板顶 16px。
      .pt-inner 自带 24px 左右内边距与 8px 上内边距，这里用负 margin 抵回去，
      否则按钮会被推到 36px 处、整体下移 8px（就是「位置不对」的由来） */
.sheet-bar{margin:-8px -24px 0}
/* 去掉标题后，按钮栏直接接内容：补上原来 h2 让出的那段呼吸间距 */
.sheet-bar + textarea{margin-top:16px}
.sheet-bar + .pt-tip{margin-top:14px}

/* 弹窗标题：所有 pt 骨架弹窗统一 —— 同字号、靠左、留出与内容的间距 */
.pt-title{
  margin:2px 0 16px;text-align:left;font-weight:400;
  font-size:calc(clamp(15px,4cqw,16.5px) * var(--fs));
  letter-spacing:.14em;color:var(--ink);
  transition:color .35s;
}
/* 拼图弹窗标题行：标题居左，右侧一颗 ✕ 圆钮（复用日期弹窗的取消按钮样式） */
.pz-head{
  display:flex;align-items:center;justify-content:space-between;
  margin:2px 0 16px;
}
.pz-head .pt-title{margin:0}
.pt-tip{
  margin-bottom:22px;text-align:center;
  font-size:calc(clamp(11px,2.8cqw,11.5px) * var(--fs));
  line-height:1.9;letter-spacing:.06em;color:var(--ink-3);
  transition:color .35s;
}
.pt-actions{display:flex;gap:10px;margin-top:20px}
.pt-btn{
  flex:1;height:46px;cursor:pointer;
  font-family:var(--font-serif);
  font-size:calc(clamp(12px,3.1cqw,13px) * var(--fs));
  letter-spacing:.14em;
  border:1px solid #d4d4d8;background:#ffffff;color:#8a8a8e;
  border-radius:12px;
  transition:opacity .2s,background .35s,border-color .35s,color .35s;
}
.pt-btn:active{opacity:.7}
.pt-btn.solid{background:#1c1c1e;color:#fff;border-color:#1c1c1e}

.menu{
  position:absolute;inset:0;z-index:350;display:flex;align-items:flex-end;justify-content:center;
  background:rgba(0,0,0,.5);
  opacity:0;visibility:hidden;pointer-events:none;transition:opacity .26s,visibility .26s;
}
.menu.on{opacity:1;visibility:visible;pointer-events:auto}
.menu-card{
  width:calc(100% - 7cqw);
  margin-bottom:calc(4cqw + 0px);
  background:#ffffff;
  border-radius:18px;    /* 悬浮小卡片：和确认弹窗同一档 */
  overflow:hidden;
  box-shadow:var(--float-shadow);
  transform:translateY(16px);
  transition:transform .3s cubic-bezier(.22,1,.36,1);
}
.menu.on .menu-card{transform:none}
.menu-btn{
  display:block;width:100%;height:12cqw;min-height:50px;cursor:pointer;
  font-family:var(--font-serif);font-size:calc(clamp(13px,3.3cqw,14.5px) * var(--fs));letter-spacing:.12em;
  background:transparent;
  border:none;             /* 去掉行间 1px 细线，靠留白和颜色区分 */
  color:var(--ink);
}
.menu-btn:first-child{border-top:none}
.menu-btn:active{background:rgba(0,0,0,.035)}
.menu-btn.danger{color:var(--danger)}
.menu-btn.plain{color:var(--ink-2)}

/* ===== 年份选择器（底部滚轮） ===== */
.year-picker{
  position:absolute;inset:0;z-index:360;
  display:flex;align-items:flex-end;
  background:rgba(0,0,0,.5);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .26s,visibility .26s;
}
.year-picker.on{opacity:1;visibility:visible;pointer-events:auto}

.year-picker-panel{
  width:100%;
  background:#ffffff;
  border-radius:18px 18px 0 0;
  overflow:hidden;
  transform:translateY(100%);
  transition:transform .32s cubic-bezier(.22,1,.36,1),background .3s;
  padding-bottom:0px;
  box-shadow:0 -12px 42px -14px rgba(20,20,40,.32);
}
.year-picker.on .year-picker-panel{transform:none}

/* 顶部抓取条 + 下滑关闭（与字体大小 / 拼图弹窗同款手感）：
   拖拽手势只认抓取条和顶部栏（滚轮列自己的滚动不受影响），
   跟手位移由 js/app.js 的 bindYearDrag 写 inline transform，
   所以拖拽期间要关掉面板自身的 transition，松手再还给它 */
.year-picker-handle{
  display:block;width:36px;height:4px;
  margin:10px auto 2px;border-radius:2px;
  background:rgba(28,28,30,.18);
  cursor:grab;touch-action:none;
}
.year-picker-handle:active{cursor:grabbing}
.year-picker-bar{touch-action:none}
.year-picker.dragging .year-picker-panel{transition:none}
.year-picker-panel{will-change:transform}

.year-picker-bar{
  display:flex;align-items:center;justify-content:space-between;
  padding:2cqw 3cqw;
}

.year-picker-cancel,
.year-picker-ok{
  width:30px;                 /* 圆底再收一档（40 → 34 → 30），靠图标本身撑住辨识度 */
  height:30px;
  display:grid;
  place-items:center;
  border:none;
  border-radius:50%;          /* 两颗都做成圆形按钮（原来是无底色的裸图标） */
  cursor:pointer;
  padding:0;
  transition:background .35s,color .35s,opacity .18s,transform .12s;
}
/* 取消：浅灰圆底 + 中灰叉；确认：黑底白勾（和底部「+」同一套实心语系） */
.year-picker-cancel{background:rgba(28,28,30,.06);color:var(--ink-2)}
.year-picker-ok{background:var(--ink);color:#faf9f7}
.year-picker-cancel:active{background:rgba(28,28,30,.12);transform:scale(.96)}
.year-picker-ok:active{opacity:.84;transform:scale(.96)}
.year-picker-cancel svg,
.year-picker-ok svg{
  width:clamp(18px,4.6cqw,20px);
  height:clamp(18px,4.6cqw,20px);
  stroke:currentColor;
  fill:none;
  stroke-width:2.5;           /* 圆底小了，笔画压粗一点才不显虚 */
  stroke-linecap:round;
  stroke-linejoin:round;
}

.year-wheel-wrap{
  --item-h: 11cqw;
  --visible: 5;
  position:relative;
  height:calc(var(--item-h) * var(--visible));
  overflow:hidden;
}

.year-wheel{
  position:relative;
  z-index:1;
  height:100%;
  overflow-y:auto;
  scroll-snap-type:y mandatory;
  padding:calc(var(--item-h) * (var(--visible) - 1) / 2) 0;
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
}
.year-wheel::-webkit-scrollbar{display:none}

.year-wheel-item{
  height:var(--item-h);
  display:flex;align-items:center;justify-content:center;
  scroll-snap-align:center;
  font-family:var(--font-mono);
  font-size:calc(clamp(15px,4cqw,18px) * var(--fs));
  letter-spacing:.08em;
  color:var(--ink-3);
  transition:color .2s,font-size .2s;
}
.year-wheel-item.active{
  color:var(--ink);
  font-size:calc(clamp(18px,4.8cqw,22px) * var(--fs));
}

.year-wheel-highlight{
  position:absolute;
  left:4cqw;right:4cqw;
  top:50%;transform:translateY(-50%);
  height:var(--item-h);
  /* 选中窗口：一层圆角浅灰带，不再用两条通栏细线（线在圆角面板里显得方） */
  border-radius:12px;
  background:rgba(28,28,30,.045);
  pointer-events:none;
  z-index:2;
  transition:background .35s;
}

.year-wheel-mask{
  position:absolute;left:0;right:0;height:calc(var(--item-h) * 1.3);
  pointer-events:none;z-index:3;
}
.year-wheel-mask.top{
  top:0;
  background:linear-gradient(180deg,#fff 20%,rgba(255,255,255,0));
}
.year-wheel-mask.bottom{
  bottom:0;
  background:linear-gradient(0deg,#fff 20%,rgba(255,255,255,0));
}

/* ===== 日期选择器：三列滚轮（复用年份选择器的滚轮与面板样式） ===== */
.dp-wheels{
  --item-h: 11cqw;
  --visible: 5;
  position:relative;
  display:flex;
  height:calc(var(--item-h) * var(--visible));
}
.dp-wheels .year-wheel-wrap{flex:1;height:100%;min-width:0}
.dp-wheels .year-wheel{padding-left:0;padding-right:0}
.dp-wheels .year-wheel-item{
  font-size:calc(clamp(14px,3.6cqw,16.5px) * var(--fs));letter-spacing:.04em;
}
.dp-wheels .year-wheel-item.active{
  font-size:calc(clamp(17px,4.4cqw,20px) * var(--fs));
}
.dp-wheels .year-wheel-highlight{left:3cqw;right:3cqw}

/* ===== 自定义确认弹窗 ===== */
.confirm{
  position:absolute;inset:0;z-index:520;
  display:grid;place-items:center;
  padding:0 8cqw;
  background:rgba(0,0,0,.5);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .22s,visibility .22s;
}
.confirm.on{opacity:1;visibility:visible;pointer-events:auto}
.confirm-card{
  width:100%;max-width:330px;
  padding:7cqw 6cqw 5.2cqw;
  background:var(--card-bg);
  border:none;                 /* 浮在遮罩上，靠投影定边界，不再描一圈灰线 */
  border-radius:18px;
  box-shadow:0 26px 64px -26px rgba(20,20,40,.55);
  transform:translateY(12px) scale(.97);
  transition:transform .3s cubic-bezier(.22,1,.36,1),background .3s;
}
.confirm.on .confirm-card{transform:none}
.confirm-card h3{
  font-size:calc(clamp(15px,3.9cqw,17px) * var(--fs));font-weight:400;letter-spacing:.14em;
  color:var(--ink);text-align:center;
}
.confirm-card p{
  margin-top:2.8cqw;
  font-size:calc(clamp(11.5px,3cqw,13px) * var(--fs));line-height:1.9;letter-spacing:.05em;
  color:var(--ink-2);text-align:center;
}
.confirm-actions{display:flex;gap:2.4cqw;margin-top:6.4cqw}
.confirm-actions button{
  flex:1;height:11cqw;min-height:44px;cursor:pointer;
  font-family:var(--font-serif);font-size:calc(clamp(12px,3.1cqw,13.5px) * var(--fs));
  letter-spacing:.14em;
  border:none;border-radius:12px;background:var(--panel-bg);color:var(--ink-2);
  transition:opacity .2s,background .2s,color .2s;
}
.confirm-actions button:active{opacity:.7}
.confirm-actions .ok{background:var(--ink);border-color:transparent;color:#fff}
.confirm-actions .ok.danger{background:var(--danger-fill);color:#fff}

/* ===== 实况封面取帧浮层（导入实况图时先选封面） =====
   底部升起的一张纸：横向胶片条 + 两个按钮。
   第一格永远是「原图」（12MP 静帧），后面几格是视频帧（1080p），
   所以默认选中第一格，用户不动就是画质最好的那一版。 */
.live-sheet{
  position:absolute;inset:0;z-index:520;
  display:flex;align-items:flex-end;
  background:rgba(0,0,0,.5);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .22s,visibility .22s;
}
.live-sheet.on{opacity:1;visibility:visible;pointer-events:auto}
.ls-panel{
  width:100%;
  padding:5.4cqw 0 calc(var(--sf-sab, env(safe-area-inset-bottom, 0px)) + 4.4cqw);
  background:var(--card-bg);
  border-radius:20px 20px 0 0;
  box-shadow:0 -18px 48px -28px rgba(20,20,40,.5);
  transform:translateY(100%);
  transition:transform .3s cubic-bezier(.22,1,.36,1),background .3s;
}
.live-sheet.on .ls-panel{transform:none}
.ls-head{
  display:flex;align-items:baseline;justify-content:space-between;
  padding:0 5.6cqw 3.2cqw;
}
.ls-head b{
  font-family:var(--font-serif);font-weight:400;
  font-size:calc(clamp(14px,3.7cqw,16px) * var(--fs));
  letter-spacing:.14em;color:var(--ink);
}
.ls-head em{
  font-style:normal;
  font-size:calc(clamp(10px,2.6cqw,11.5px) * var(--fs));
  letter-spacing:.06em;color:var(--ink-3);
}
.ls-strip{
  display:flex;gap:2.6cqw;align-items:flex-start;
  padding:0 5.6cqw 1cqw;
  overflow-x:auto;overflow-y:hidden;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
.ls-strip::-webkit-scrollbar{display:none}
.ls-cell{
  flex:0 0 auto;
  width:16cqw;max-width:72px;
  padding:0;border:none;background:none;
  display:grid;justify-items:center;gap:1.4cqw;
  cursor:pointer;appearance:none;
  -webkit-tap-highlight-color:transparent;
}
.ls-cell span{
  width:16cqw;max-width:72px;
  aspect-ratio:3/4;
  border-radius:6px;
  background-size:cover;background-position:center;
  background-color:rgba(28,28,30,.06);
  box-shadow:inset 0 0 0 1px rgba(28,28,30,.06);
  transition:box-shadow .18s ease,transform .18s ease;
}
.ls-cell i{
  font-style:normal;
  font-size:calc(clamp(9px,2.3cqw,10.5px) * var(--fs));
  letter-spacing:.04em;color:var(--ink-3);
}
.ls-cell.on span{box-shadow:0 0 0 2px var(--accent),0 6px 16px -10px rgba(0,0,0,.5)}
.ls-cell.on i{color:var(--accent)}
.ls-cell:active span{transform:scale(.96)}
.ls-loading{
  font-size:calc(clamp(11px,2.9cqw,12.5px) * var(--fs));
  letter-spacing:.06em;color:var(--ink-3);
  padding:6cqw 0 7cqw;
}
.ls-actions{display:flex;gap:2.6cqw;padding:3.6cqw 5.6cqw 0}
.ls-btn{
  flex:1;height:11cqw;min-height:44px;cursor:pointer;
  font-family:var(--font-serif);
  font-size:calc(clamp(12px,3.1cqw,13.5px) * var(--fs));
  letter-spacing:.14em;
  border:none;border-radius:12px;
  background:var(--panel-bg);color:var(--ink-2);
  transition:opacity .2s,background .2s,color .2s;
}
.ls-btn:active{opacity:.7}
.ls-btn.solid{background:var(--ink);color:#fff}
.ls-btn:disabled{opacity:.5}

.toast{
  position:absolute;left:50%;bottom:calc(22cqw + 0px);
  transform:translate(-50%,14px);z-index:600;   /* 更新/协议弹窗(560)之上：弹窗内触发的提示不被遮罩压住 */
  padding:2.4cqw 5cqw;white-space:nowrap;
  border-radius:999px;
  background:#1c1c1e;
  color:#fff;font-size:calc(clamp(11px,2.9cqw,12.5px) * var(--fs));letter-spacing:.12em;
  opacity:0;pointer-events:none;transition:opacity .3s,transform .3s;
}
.toast.on{opacity:1;transform:translate(-50%,0)}

/* 卡片上的地点小字：样式统一在 .card-info 的 .card-head 一行里（见上） */


.loc-btn:active{opacity:.7}

.loc-btn svg{
  width:clamp(13px,3.4cqw,15px);height:clamp(13px,3.4cqw,15px);
  stroke:currentColor;fill:none;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;
}
.loc-use{
  display:inline-flex;align-items:center;gap:1.4cqw;
  background:none;border:none;cursor:pointer;
  font-family:var(--font-serif);font-size:calc(clamp(11px,2.8cqw,12.5px) * var(--fs));
  letter-spacing:.08em;color:var(--accent);
}
.loc-use:active{opacity:.6}
.loc-use.busy{opacity:.45;pointer-events:none}
.loc-use svg{
  width:clamp(13px,3.4cqw,15px);height:clamp(13px,3.4cqw,15px);
  stroke:currentColor;fill:none;stroke-width:1.5;
  stroke-linecap:round;
}
#loc-input{
  width:100%;height:11cqw;min-height:44px;outline:none;
  border:1px solid rgba(28,28,30,.12);background:#fafafa;
  font-family:var(--font-serif);font-size:calc(clamp(13px,3.4cqw,15px) * var(--fs));
  letter-spacing:.06em;color:var(--ink);padding:0 3cqw;
}
#loc-input::placeholder{color:var(--ink-3)}

/* ===== 收藏页：星标回忆列表，按月归纳 ===== */
#page-fav{background:var(--page-bg)}
.wall-scroll{
  flex:1;min-height:0;overflow-y:auto;position:relative;
  padding:0 5cqw calc(92px + 0px);
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
  transition:padding-top .3s cubic-bezier(.22,1,.36,1);
}
.wall-scroll::-webkit-scrollbar{display:none}

/* 月份小标题：细字 + 一条向右延伸的细线 */
.wall-month{
  display:flex;align-items:center;gap:3cqw;
  margin:3cqh 0 .6cqw;
}
.wall-month:first-child{margin-top:1.6cqh}
.wall-month b{
  font-family:var(--font-serif);font-weight:400;
  font-size:calc(clamp(11px,2.9cqw,12.5px) * var(--fs));letter-spacing:.16em;color:var(--ink-2);
  white-space:nowrap;
}
.wall-month i{
  flex:1;height:1px;background:rgba(28,28,30,.1);
  transition:background .35s;
}

/* 左滑结构：行浮在删除按钮上，左移露出按钮 */
.fav-swipe{position:relative;overflow:hidden}
.fav-row{
  position:relative;z-index:1;
  display:flex;align-items:center;gap:3.4cqw;
  padding:1.4cqw 0;
  cursor:pointer;
  background:var(--page-bg);
  transition:opacity .2s, transform .25s;
  touch-action:pan-y;
}
.fav-row.swiped{transform:translateX(-19cqw)}
.fav-del{
  position:absolute;top:0;right:0;bottom:0;z-index:0;
  width:19cqw;max-width:82px;
  display:grid;place-items:center;
  background:rgba(var(--danger-rgb),.92);color:#fff;
  border:none;cursor:pointer;
  opacity:0;pointer-events:none;            /* 平时隐藏：按压行时不会透出来 */
  transition:opacity .15s;
}
.fav-row.swiped + .fav-del{opacity:1;pointer-events:auto}
.fav-del svg{
  width:20px;height:20px;
  stroke:currentColor;fill:none;
  stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;
}
.fav-del:active{filter:brightness(1.12)}
.fav-thumb{
  position:relative;flex:0 0 auto;
  width:15cqw;height:15cqw;max-width:64px;max-height:64px;
  overflow:hidden;background:rgba(28,28,30,.05);
}
.fav-thumb .photo-img{position:absolute;inset:0}
.fav-thumb .stroke-layer{position:absolute;inset:0;width:100%;height:100%}
.fav-info{flex:1;min-width:0;text-align:left}
.fav-date{
  display:block;margin-bottom:1.1cqw;
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.12em;color:var(--accent);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.fav-cap{
  font-size:calc(clamp(12px,3.1cqw,14px) * var(--fs));color:var(--ink);
  letter-spacing:.07em;line-height:1.6;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;
}
/* 收藏页 / 照片墙的空状态统一走 .empty 那套居中规则（不再单独往下压 14cqh） */

/* =====================================================
   照片墙：按月分段，三列拍立得（图钉 + 轻微歪斜 + 下方日期）
   ===================================================== */
/* 照片墙不再单独一页：作为「最近」的第二种排布（顶栏切换） */
#page-home .wall-scroll{
  padding:12px 5cqw calc(88px + 0px);
}
#page-home .wall-grid{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:18px 10px;
  padding:12px 2px 6px;
}
#page-home .wall-grid + .month-head{margin-top:22px}

/* 一张照片 = 白边相纸（下缘留宽边写日期），图钉钉在纸上 */
#page-home .wall-photo{
  position:relative;
  display:block;width:100%;
  padding:5px 5px 22px;
  border:none;
  background:#fff;
  cursor:pointer;
  box-shadow:0 6px 16px -10px rgba(40,35,30,.26),0 1px 3px -1px rgba(40,35,30,.07);
  transform:rotate(var(--rot,0deg));
  transition:transform .26s cubic-bezier(.22,1,.36,1),box-shadow .26s;
  -webkit-touch-callout:none;-webkit-user-select:none;user-select:none;
}
#page-home .wall-photo:active{
  transform:rotate(var(--rot,0deg)) scale(.95);
  box-shadow:0 2px 6px rgba(40,35,30,.14);
}
/* 图钉落在纸上的投影 */
#page-home .wall-photo::before{
  content:'';
  position:absolute;top:2px;left:50%;
  width:9px;height:4px;margin-left:-4.5px;
  border-radius:50%;
  background:radial-gradient(ellipse at 50% 40%,rgba(40,35,30,.24),transparent 72%);
  z-index:2;pointer-events:none;
}
/* 圆形图钉本体：纯黑实心，7px */
#page-home .wp-pin{
  position:absolute;left:50%;top:-3px;
  width:7px;height:7px;margin-left:-3.5px;
  border-radius:50%;
  background:#2e2e2e;
  box-shadow:0 1px 1.5px rgba(40,35,30,.28);
  z-index:3;pointer-events:none;
}
#page-home .wall-photo .wp-face{
  position:relative;display:block;width:100%;
  aspect-ratio:1;
  overflow:hidden;
  background:rgba(28,28,30,.05);
}
#page-home .wall-photo .wp-img{
  position:absolute;inset:0;
  background-size:cover;background-position:center;
  filter:saturate(.97) contrast(.98);
}
#page-home .wall-photo .stroke-layer{position:absolute;inset:0;width:100%;height:100%;z-index:2}
/* 相纸下缘的日期 */
#page-home .wp-cap{
  position:absolute;left:0;right:0;bottom:0;height:22px;
  display:flex;align-items:center;justify-content:center;
  font-family:var(--font-mono);font-size:calc(10px * var(--fs));
  letter-spacing:.04em;color:rgba(60,60,67,.45);
  white-space:nowrap;pointer-events:none;
}

/* =====================================================
   轨迹页（浅色 · 水平展开的点阵地图）
   ===================================================== */
#page-track{
  background:var(--page-bg);
  color:var(--ink);
}
.globe-wrap{
  position:relative;flex:1;min-height:0;
  margin:0;
  overflow:hidden;
  background:var(--page-bg);
}
/* MapLibre 地图容器 */
.map{
  position:absolute;inset:0;z-index:0;
  background:var(--page-bg);
  touch-action:none;
}
.map.maplibregl-map{
  background:var(--page-bg);
  font-family:var(--font-serif);
}
.map .maplibregl-ctrl-container{display:none!important}
.maplibregl-canvas{outline:none}
.maplibregl-marker{display:grid;place-items:center;cursor:pointer}
/* 注意：.map-pin / .map-loc 会被当作 MapLibre 的标记元素复用，
   必须保持 position:absolute。写成 relative 会让它们回到文档流：
   每个标记被上一个 5px 的高度往下顶，缩到全世界时肉眼就是「地标整体漂移」。 */
.map-pin{
  position:absolute;left:0;top:0;
  display:grid;place-items:center;
}
/* 点只有 5px，补一块透明热区方便手指点中（绝对定位，不参与网格排版） */
.map-pin::after{content:'';position:absolute;inset:-9px;border-radius:50%}
/* 当前定位点：与地址足迹点同尺寸的纯圆 + 水波扩散（仅系统已授权定位时显示） */
.map-loc{
  position:absolute;left:0;top:0;width:5px;height:5px;
  pointer-events:none;
}
.map-loc .core{
  position:absolute;left:50%;top:50%;width:5px;height:5px;margin:-2.5px 0 0 -2.5px;
  border-radius:50%;background:#4aa8d8;
}
.map-loc .ripple{
  position:absolute;left:50%;top:50%;width:5px;height:5px;margin:-2.5px 0 0 -2.5px;
  border-radius:50%;background:rgba(74,168,216,.5);
  animation:loc-ripple 2.2s ease-out infinite;
}
.map-loc .ripple:nth-child(2){animation-delay:1.1s}
@keyframes loc-ripple{
  0%  {transform:scale(1);opacity:.6}
  80% {transform:scale(4.2);opacity:0}
  100%{transform:scale(4.2);opacity:0}
}
.map-pin i{
  display:block;width:5px;height:5px;border-radius:50%;
  background:var(--pin-c,var(--accent));
  transition:transform .22s cubic-bezier(.34,1.56,.64,1);
}
.map-pin.on i{transform:scale(1.6)}
.map-pin .tip{
  position:absolute;bottom:calc(100% + 7px);left:50%;
  transform:translateX(-50%);
  padding:3px 7px;border-radius:0;
  background:rgba(255,255,255,.96);
  border:1px solid var(--card-border);
  box-shadow:0 6px 18px -12px rgba(30,30,70,.45);
  color:var(--ink);
  font-family:var(--font-serif);font-size:calc(clamp(9.5px,2.3cqw,11px) * var(--fs));
  letter-spacing:.1em;white-space:nowrap;
  opacity:0;pointer-events:none;transition:opacity .18s;
}
.map-pin:hover .tip,.map-pin.on .tip{opacity:1}
.map-fail{
  position:absolute;left:0;right:0;top:calc(50% - 8px);z-index:5;
  text-align:center;pointer-events:none;
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.14em;color:var(--ink-3);
  opacity:0;transition:opacity .35s;
}
.map-fail.on{opacity:1}
/* 底图加载中：盖住浅色底图，等瓦片和配色都到位再淡出。
   深色模式下切到轨迹页时，底图要先拉样式再重刷配色（走网络），
   这层用当前主题的页面底色铺着，就不会先闪一下白再变暗。
   出现要「零延迟」（.on 那一下不加过渡），否则淡入的那几帧会透出浅色底图；
   消失才淡出。 */
.map-load{
  position:absolute;inset:0;z-index:6;
  display:grid;place-content:center;justify-items:center;gap:14px;
  background:var(--page-bg);
  opacity:0;pointer-events:none;
  transition:opacity .36s ease .04s,background .35s;
}
.map-load.on{opacity:1;transition:opacity 0s linear}
/* 加载标记：logo 的两个方框 —— 前框墨色、后框主题红，后框右下错位半个框；
   循环里两框沿对角互换再归位（同帧 = 同一帧的两个面） */
.map-load-mark{
  position:relative;width:26px;height:26px;
}
.map-load-mark i{
  position:absolute;left:0;top:0;
  width:14px;height:14px;box-sizing:border-box;
  border:1.4px solid var(--ink);
}
.map-load-mark i:last-child{
  left:7px;top:7px;
  border-color:var(--accent);
  animation:map-frame-b 1.9s cubic-bezier(.55,0,.35,1) infinite;
}
.map-load-mark i:first-child{
  animation:map-frame-a 1.9s cubic-bezier(.55,0,.35,1) infinite;
}
/* 0–14% 原样停顿 → 14–44% 滑到对角（互换）→ 44–62% 停一下 → 62–92% 滑回来 */
@keyframes map-frame-a{
  0%,14%   {transform:translate(0,0)}
  44%,62%  {transform:translate(7px,7px)}
  92%,100% {transform:translate(0,0)}
}
@keyframes map-frame-b{
  0%,14%   {transform:translate(0,0)}
  44%,62%  {transform:translate(-7px,-7px)}
  92%,100% {transform:translate(0,0)}
}
.map-load-txt{
  font-family:var(--font-mono);
  font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.18em;color:var(--ink-3);
}
@media (prefers-reduced-motion:reduce){
  .map-load-mark i{animation-duration:3.4s}
}
/* ===== 地址抽屉（可拖动卡片） =====
   收起：只露把手 + 搜索框；向上拖全屏展开，向下拖关闭 */
.addr-sheet{
  position:absolute;left:0;right:0;
  top:33.333%;
  /* 卡片要一直铺到屏幕底：展开后底部不再留出一条页面底色
     （原先 bottom 停在悬浮导航上沿，展开时下方空出一条 70px 的空白）。
     收起态的「把手 + 搜索框」仍坐在导航上方，位置由 JS 的 sheetClosedY() 减去 dock 高度得出 */
  bottom:0;
  z-index:15;
  border-radius:18px 18px 0 0;
  display:flex;flex-direction:column;
  transform:translateY(100%);
  transition:transform .38s cubic-bezier(.22,1,.36,1);
  background:var(--card-bg);
  /* 只朝上投：卡片像是从导航后面浮起来的一层 */
  box-shadow:
    0 -2px 6px -2px rgba(28,28,30,.10),
    0 -10px 30px -12px rgba(28,28,30,.20);
  will-change:transform;
}
.addr-sheet.dragging{transition:none}
.addr-sheet{user-select:none;-webkit-user-select:none}
.addr-sheet input{user-select:text;-webkit-user-select:text}
.addr-sheet .sheet-grip{
  flex:0 0 auto;
  height: 22px;
  padding: 0;
  display:grid;place-items:center;
  position:relative;
  cursor:grab;touch-action:none;
}
.sheet-grip:active{cursor:grabbing}
.grip-arrow{
  display:block;width:28px;height:10px;
  fill:none;stroke:#c4c4c8;stroke-width:4.5;   /* 原 rgba(28,28,30,.26)：半透明在卡片上会透底，换成等效实色 */
  stroke-linecap:round;stroke-linejoin:round;
}
.addr-sheet.open .grip-arrow{transform:rotate(180deg)}
/* 与 .trash-back 同一套：白圆底 + 柔和投影，只是尺寸贴着抽屉把手行收小一档 */
.sheet-back{
  display:none;
  position:absolute;left:2.4cqw;top:50%;transform:translateY(-50%);
  width:32px;height:32px;place-items:center;
  background:var(--card-bg);
  border:none;border-radius:50%;
  box-shadow:0 2px 10px -3px rgba(28,28,30,.18), 0 1px 3px rgba(28,28,30,.06);
  cursor:pointer;color:var(--ink-2);
}
.sheet-back svg{
  width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
}
/* 标题与返回按钮同样以行高中线定位，保证同一水平线 */
.sheet-title{
  display:none;
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  max-width:56cqw;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
  font-family:var(--font-serif);
  font-size:calc(clamp(13px,3.4cqw,15px) * var(--fs));letter-spacing:.14em;color:var(--ink);
}
.addr-sheet.place .sheet-back{display:grid;animation:pp-fade .28s ease}
.addr-sheet.place .sheet-title{display:block;animation:pp-fade .28s ease}
.addr-sheet.place .grip-arrow{display:none}
.addr-sheet.place .sheet-search{display:none}
/* 地址合集模式：返回按钮 + 地址名坐在把手行里，
   比收起态的紧凑把手高一些，上边距给足 */
.addr-sheet.place .sheet-grip{height:46px}
/* 进入/退出地址回忆的过渡动画 */
@keyframes pp-in{from{opacity:0;transform:translateX(26px)}to{opacity:1;transform:none}}
@keyframes pp-back-in{from{opacity:0;transform:translateX(-26px)}to{opacity:1;transform:none}}
@keyframes pp-fade{from{opacity:0}to{opacity:1}}
.addr-sheet.place .sheet-body{animation:pp-in .32s cubic-bezier(.22,1,.36,1)}
.addr-sheet.grid-in .sheet-body{animation:pp-back-in .3s cubic-bezier(.22,1,.36,1)}
.sheet-search{
  flex:0 0 auto;
  padding:0 4cqw 1.2cqh;
  touch-action:none;
}
.sheet-search input{
  width:100%;box-sizing:border-box;
  min-height:40px;
  padding:1.1cqh 3.2cqw;
  background:rgba(28,28,30,.035);
  border:none;
  border-radius:10px;
  font-family:var(--font-serif);
  font-size:calc(clamp(11.5px,3cqw,13px) * var(--fs));
  letter-spacing:.08em;color:var(--ink);
  outline:none;
  transition:background .18s;
}
.sheet-search input::placeholder{color:var(--ink-3)}
/* 回弹时位移加在 .sheet-body 上，必须由外层裁剪 —— 否则内容会盖住搜索行/把手 */
.sheet-body-wrap{
  flex:1;min-height:0;
  position:relative;overflow:hidden;
}
.sheet-body{
  height:100%;
  overflow-y:auto;
  touch-action:pan-y;
  padding:1.2cqh 4cqw calc(76px + 0px);
  overscroll-behavior-y: contain;
  will-change:transform;
}
.sheet-cap{
  margin:0 0 1.2cqh;
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.16em;color:var(--ink-3);
}
.sheet-empty{
  margin:2.4cqh 0;text-align:center;
  font-size:calc(clamp(11px,2.8cqw,12.5px) * var(--fs));color:var(--ink-3);letter-spacing:.1em;
}
/* 地址胶囊：宽度跟地名走（flex 自动排），不再固定三等分 ——
   「西湖」只有两个字却被撑成三分之一的宽格子，右边一大片空白很难看。 */
.sheet-grid{
  display:flex;flex-wrap:wrap;
  gap:2cqw;
}
.sheet-card{
  display:flex;align-items:center;gap:1.6cqw;
  flex:0 1 auto;
  min-width:70px;
  max-width:100%;
  /* 高度固定 40px：原来用 cqh 做上下 padding，屏幕越高格子越胖，
     一屏只放得下三行地址 —— 现在按「一行一个地址」的密度排 */
  height:40px;
  padding:0 3cqw;
  background:#fff;
  border:1px solid var(--card-border);
  border-radius:12px;
  cursor:pointer;text-align:left;
  transition:border-color .18s,transform .18s;
}
/* 点击态用中性墨色描边，不用主题红——一整片红边在这里太抢眼 */
.sheet-card:active{border-color:rgba(28,28,30,.22);transform:scale(.985)}
.sc-name{
  flex:0 1 auto;min-width:0;
  font-family:var(--font-serif);
  font-size:calc(clamp(11.5px,2.9cqw,13.5px) * var(--fs));letter-spacing:.08em;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.sheet-card b{
  flex:0 0 auto;
  font-family:var(--font-mono);font-weight:400;
  font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  color:var(--ink-3);letter-spacing:.04em;
}
/* ===== 地址回忆页的点位列表 ===== */
.pp-row{
  display:flex;align-items:center;gap:3.2cqw;
  width:100%;padding:1.1cqh 0;
  background:none;border:0;border-bottom:1px solid var(--card-border);
  cursor:pointer;text-align:left;
  transition:background .16s;
}
.pp-row:active{background:rgba(28,28,30,.045)}
.pp-thumb{
  position:relative;flex:0 0 auto;
  width:16cqw;height:16cqw;max-width:72px;max-height:72px;
  overflow:hidden;background:rgba(28,28,30,.05);
}
.pp-row:last-child{border-bottom:none}
.pp-thumb .photo-img{position:absolute;inset:0}
.pp-info{flex:1;min-width:0}
.pp-cap{
  display:block;
  font-size:calc(clamp(12px,3.1cqw,14px) * var(--fs));color:var(--ink);
  letter-spacing:.07em;line-height:1.5;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.pp-date{
  display:block;margin-top:.6cqw;
  font-family:var(--font-mono);font-size:calc(clamp(8.5px,2.1cqw,10px) * var(--fs));
  letter-spacing:.12em;color:var(--accent);
}
.pp-row svg{
  flex:0 0 auto;width:13px;height:13px;
  stroke:var(--icon-3);fill:none;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round;
}
.track-detail{
  position:absolute;left:4cqw;right:4cqw;
  bottom:calc(66px + 76px + 0px);
  z-index:20;
  background:rgba(255,255,255,.94);
  border:1px solid var(--card-border);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  box-shadow:0 24px 48px -24px rgba(30,30,70,.35);
  padding:3cqw;
  opacity:0;visibility:hidden;transform:translateY(16px);
  transition:opacity .28s,visibility .28s,transform .32s cubic-bezier(.22,1,.36,1);
}
.track-detail.on{opacity:1;visibility:visible;transform:none}
.td-close{
  position:absolute;top:2cqw;right:2cqw;z-index:2;
  width:30px;height:30px;display:grid;place-items:center;
  background:none;border:none;cursor:pointer;
  color:var(--icon-3);
}
.td-close svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round}
.td-main{display:flex;align-items:center;gap:3.4cqw;cursor:pointer;padding-right:8cqw}
.td-thumb{
  position:relative;flex:0 0 auto;
  width:17cqw;height:17cqw;max-width:76px;max-height:76px;
  overflow:hidden;background:rgba(28,28,30,.05);
}
.td-thumb .photo-img{position:absolute;inset:0}
.td-info{flex:1;min-width:0;text-align:left}
.td-place{
  display:block;margin-bottom:.8cqw;
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.16em;color:var(--accent);
}
.td-cap{
  font-size:calc(clamp(12px,3.1cqw,14px) * var(--fs));color:var(--ink);
  letter-spacing:.07em;line-height:1.6;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.td-date{
  display:block;margin-top:.8cqw;
  font-family:var(--font-mono);font-size:calc(clamp(8.5px,2.1cqw,10px) * var(--fs));
  letter-spacing:.12em;color:var(--ink-3);
}

/* ===== 地点弹层：定位状态（没内容时不占位） ===== */
.loc-status{
  min-width:0;flex:1;
  font-family:var(--font-mono);font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.08em;color:var(--ink-3);line-height:1.5;
}
.loc-status:empty{display:none}
.loc-status.warn{color:var(--accent)}

/* 状态 + 「使用当前位置」一行：状态靠左，按钮靠右（状态空着时按钮保持右位） */
.loc-sub{
  display:flex;align-items:center;justify-content:space-between;gap:3cqw;
  margin-top:2.2cqw;min-height:5.6cqw;
}
.loc-sub:has(.loc-status:empty){justify-content:flex-end}


/* ===== 拼图弹窗：选图（3 列）→ 选版式 → 导出 ===== */
.pz-hint{
  margin:0 0 10px;text-align:center;
  font-size:calc(clamp(10px,2.5cqw,11px) * var(--fs));
  letter-spacing:.08em;color:var(--ink-3);
}
.pz-hint.warn{color:var(--accent,#e8452f)}
/* pt-inner 默认 touch-action:none：上拉全屏 / 下滑关闭的拖拽归 JS，
   网格与版式条自己声明滚动方向，浏览器不会中途抢手势（pointercancel） */
#puzzle-inner{touch-action:none;display:flex;flex-direction:column}
/* 版式横条：自己声明滚动方向，横向手势由浏览器滚动接管 */
#pz-layouts{touch-action:auto}
/* 全屏态：卡片占满整个弹层背景，内容区吃掉剩余高度，按钮组钉在底部 */
/* 全屏时内容区改为纵向 flex：网格/版式条用 flex:1 吃满剩余高度；
   非 full 态保持 block，不影响常态高度 */
#puzzle-sheet.full .pt-inner{height:100%;max-height:100%;border-radius:0;display:flex;flex-direction:column}
/* 全屏 = 沉浸式：内容铺到状态栏底下（视觉上整屏一张卡），但要给状态栏图标让出高度，
   否则把手和「拼图」标题会被时间/电量压住 */
html[data-shell="android"] #puzzle-sheet.full .pt-inner,
html[data-shell="ios"] #puzzle-sheet.full .pt-inner{
  padding-top:calc(8px + var(--sf-sat, env(safe-area-inset-top, 0px)));
}
#puzzle-sheet.full .pz-step{flex:1;min-height:0}
/* display:flex 会盖掉 hidden 属性的 UA 样式，必须显式补回，
   否则第 1/2 步会同时显示在一页上 */
.pz-step[hidden]{display:none}
#puzzle-sheet.full .pz-grid{max-height:none;flex:1;min-height:0}
/* 第 2 步：宫格预览吃掉剩余高度，版式条钉在它下面 */
#puzzle-sheet.full .pz-step[data-step="2"]{justify-content:flex-start}
.pz-stage-wrap{
  position:relative;flex:1;min-height:0;
  display:flex;align-items:center;justify-content:center;
  padding:2px 0 8px;
}
.pz-stage{
  position:relative;
  width:min(100%, 70cqw, 40cqh);
  aspect-ratio:1/1;
  background:#fff;overflow:hidden;
  box-shadow:0 14px 34px -22px rgba(40,35,30,.55), 0 2px 8px -4px rgba(40,35,30,.12);
  touch-action:none;      /* 手势全归 JS：单指移位 / 双指缩放旋转，别让浏览器接管 */
}
#puzzle-sheet.full .pz-stage{width:min(100%, 84cqw, 56cqh)}
/* 每一格：绝对定位按版式比例摆。格子是固定的蒙版，照片在后面动。 */
.pz-stage .pz-slot{
  position:absolute;padding:0;border:2px solid #fff;box-sizing:border-box;
  background:#fff;overflow:hidden;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
/* 正在调整的格子给一圈细描边，看得出动的是哪一格 */
.pz-stage .pz-slot.editing{outline:1.5px solid var(--accent,#e8452f);outline-offset:-2px}
/* 格子留白：图片缩小/旋转时露出的边角就是纯白，不做虚化底 */
.pz-stage .pz-slot{background:#fff}
/* 面：一张「按自己原图比例、等比放大到刚好铺满格子」的完整照片，
   尺寸（width/height px）由 JS 按 naturalWidth/Height 算出来写进 style，
   所以元素本身就保持了原图比例 —— 不是被压成格子形状再裁。
   超出格子的部分由外层 .pz-slot 的 overflow:hidden 这条蒙版边切掉；
   缩放/旋转/平移全部作用在这张整图上，看不到任何「预裁」痕迹。 */
.pz-stage .pz-slot img.pz-img{
  display:block;position:absolute;left:50%;top:50%;
  width:auto;height:auto;max-width:none;max-height:none;
  transform-origin:50% 50%;pointer-events:none;will-change:transform;
  /* 跟手要紧：拖动期间任何过渡都会造成「松手后图片还在动」的错觉 */
  transition:none;
}
.pz-stage .pz-slot::after{
  content:'';position:absolute;inset:0;background:rgba(0,0,0,0);
  transition:background .18s;pointer-events:none;
}
.pz-stage .pz-slot:active::after{background:rgba(0,0,0,.1)}
#puzzle-sheet.full .pt-actions{margin-top:auto;padding-top:16px}
/* 步骤容器纵向布局：全屏时网格/版式条才能真正长高（常态不受影响） */
.pz-step{display:flex;flex-direction:column;min-height:0}
.pz-step .pz-hint{flex:0 0 auto}
.pz-grid{
  display:grid;grid-template-columns:repeat(3,1fr);gap:8px;
  /* 行高按格子自身（1:1）撑，不允许压扁：卡片被拖矮时行不会挤到比格子还小，
     否则格子会互相叠在一起；放不下就滚动 */
  align-content:start;grid-auto-rows:max-content;
  max-height:44vh;overflow-y:auto;touch-action:pan-y;
  scrollbar-width:none;
}
.pz-grid::-webkit-scrollbar{display:none}
.pz-cell{
  position:relative;aspect-ratio:1;border:none;padding:0;
  border-radius:12px;overflow:hidden;cursor:pointer;
  background:#f0efec center/cover no-repeat;
  transition:transform .18s;
}
.pz-cell:active{transform:scale(.96)}
.pz-cell::after{
  content:'';position:absolute;top:6px;right:6px;
  width:20px;height:20px;border-radius:50%;
  border:1.5px solid rgba(255,255,255,.9);
  background:rgba(20,20,28,.25);
  transition:background .18s;
}
.pz-cell.sel::after{display:none}
/* 选中序号：拼图顺序 = 点选顺序，所以给个看得见的 1/2/3… */
.pz-no{
  position:absolute;top:6px;right:6px;z-index:2;
  width:20px;height:20px;border-radius:50%;
  display:grid;place-items:center;
  font-style:normal;font-size:11px;line-height:1;
  font-family:var(--font-mono);letter-spacing:0;
  color:#fff;background:var(--accent,#e8452f);
}
/* 版式条：只有「当前张数」的一组，一行横排（id 挂在 .pz-row 上，滚动交给它自己） */
.pz-row-wrap{position:relative}
/* 一行放得下 4 张（76px×4 + 8px 间隙 ≈ 328），超出的第 5 张被裁在右侧，
   这里给一道渐隐 + 小箭头，让人知道能往左滑；滑到最右时整块提示收掉 */
.pz-row-wrap.has-more::after{
  content:'';position:absolute;right:-24px;top:0;bottom:2px;width:58px;
  background:linear-gradient(90deg,rgba(255,255,255,0) 0%,#fff 68%);
  pointer-events:none;
}
.pz-row-wrap.has-more::before{
  content:'';position:absolute;right:4px;top:50%;
  width:8px;height:8px;margin-top:-5px;
  border-right:1.5px solid rgba(28,28,30,.42);
  border-top:1.5px solid rgba(28,28,30,.42);
  transform:rotate(45deg);
  pointer-events:none;
}
.pz-row-wrap.at-end::after,
.pz-row-wrap.at-end::before{display:none}
.pz-row{
  display:flex;gap:8px;
  overflow-x:auto;overflow-y:hidden;
  touch-action:auto;                /* 与 .pz-layouts 一起交给浏览器判方向，不再和纵向滚动打架 */
  scroll-snap-type:x proximity;
  scrollbar-width:none;
  padding-bottom:2px;
  overscroll-behavior-x:contain;    /* 滑到头不把外层的纵向列表带着晃 */
}
.pz-row::-webkit-scrollbar{display:none}
/* 当天照片不够的张数组：整组置灰 */
.pz-layout.off{opacity:.38;pointer-events:none}
/* 单张版式卡：固定宽度排在横向条里，全部直角，不铺底色 */
.pz-layout{
  flex:0 0 auto;width:76px;cursor:pointer;
  border:1.5px solid transparent;border-radius:0;
  padding:4px;background:transparent;
  scroll-snap-align:start;
  transition:border-color .18s,background .18s;
}
.pz-layout.on{border-color:var(--accent,#e8452f);background:#fff}
.pz-lay{
  position:relative;display:block;width:100%;aspect-ratio:1;   /* 导出是正方形 1200×1200，预览同比 */
  border-radius:0;overflow:hidden;background:none;
}
/* 版式块：中性灰直角线条，不填色 */
.pz-lb{
  position:absolute;background:none;
  border:1.5px solid rgba(28,28,30,.24);border-radius:0;
  box-sizing:border-box;
}
.device.night .pz-lb{border-color:rgba(255,255,255,.28)}
.device.night .pz-lay{background:none}
.device.night .pz-layout.on{background:rgba(255,255,255,.06)}
/* ============================================================
   数据清空页（#page-wipe）
   我的 → 清空数据进入：顶部栏右侧选年月 → 直接铺该月全部图片（4 列）。
   平时是干净图墙，长按任意一张 420ms 进入多选（复选框/全选/底部栏此时才出现），
   所选永久删除（不进回收站）。头部复用 trash-head；年月弹窗复用 date-pop。
   ============================================================ */

#page-wipe{z-index:55}

/* 年月弹窗沿用 .year-picker-panel，但这一页的层级更靠前，顶角再放大一点，
   与「清空所选」等按钮的圆角语言一致 */
#wipe-pop .year-picker-panel{border-radius:22px 22px 0 0}

/* 顶部栏右侧：年月胶囊；进入多选后它淡出，同一角落浮出「全选」
   （多选态下切月会作废选择，所以干脆把月份入口收起来） */
.wipe-head-end{
  position:relative;
  margin-left:auto;
  flex:0 0 auto;
  display:flex;align-items:center;
  min-height:34px;
}

/* 顶部栏右侧的年月按钮：纯图标（日历），点开年月选择弹窗 */
.wipe-ym-btn{
  display:grid;place-items:center;
  flex:0 0 auto;
  width:34px;height:34px;
  padding:0;
  background:rgba(28,28,30,.055);    /* 去描边，改用浅灰底把按钮托出来 */
  border:none;
  border-radius:50%;                 /* 和顶栏其他图标按钮同为圆形 */
  color:var(--ink-2);
  cursor:pointer;appearance:none;
  transition:background .35s,color .35s,opacity .2s,visibility .2s,transform .2s;
}
#page-wipe.selecting .wipe-ym-btn{
  opacity:0;visibility:hidden;pointer-events:none;
  transform:translateX(6px);         /* 略微右移淡出，让位得自然些 */
}

/* 全选：和回收站同一枚图标按钮，只是这一页要绝对定位到年月胶囊的位置 */
.wipe-select-all{
  position:absolute;right:0;top:50%;
  transform:translateY(-50%);
  margin:0;padding:0;
  width:34px;height:34px;
  display:grid;place-items:center;
  transition:opacity .18s;
}
.wipe-select-all:active{transform:translateY(-50%) scale(.92)}
.wipe-ym-btn:active{background:rgba(28,28,30,.1)}
.wipe-ym-btn svg{
  width:18px;height:18px;flex:0 0 auto;
  fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
}
.wipe-ym-btn.is-open{background:rgba(28,28,30,.1)}

.wipe-body{
  flex:1;min-height:0;overflow-y:auto;
  padding:2.4cqh 5cqw calc(24px + 0px);
  transition:padding-bottom .28s cubic-bezier(.22,1,.36,1);
  scrollbar-width:none;
  -ms-overflow-style:none;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
}
/* 多选态底部栏升起，图墙同步多留一屏底距，最后一行仍能滚到栏上方 */
#page-wipe.selecting .wipe-body{padding-bottom:calc(92px + 0px)}
.wipe-body::-webkit-scrollbar{width:0;height:0;display:none}

/* 该月图片：4 列网格 */
.wipe-grid{
  display:grid;
  grid-template-columns:repeat(4,1fr);
  gap:2.4cqw;
}
.wipe-shot{
  width:100%;
  aspect-ratio:1/1;
  border:1px solid var(--card-border);
  background-color:var(--panel-bg);
  background-size:cover;
  background-position:center;
  cursor:pointer;appearance:none;
  position:relative;
  /* 纵向手势留给页面滚动，长按/轻点归选中；长按别弹系统选字/复制菜单 */
  touch-action:pan-y;
  -webkit-touch-callout:none;-webkit-user-select:none;user-select:none;
  transition:border-color .2s,background-color .35s,box-shadow .2s,opacity .2s;
}
/* 选中：压一层暗纱（复选框和日期角标 z-index 抬上来，保持清晰） */
.wipe-shot.sel::after{
  content:'';position:absolute;inset:0;
  background:rgba(0,0,0,.26);
  pointer-events:none;
}
/* 复选框：平时藏起来，长按进入多选后才浮出（与回收站同一节奏） */
.wipe-shot .wipe-check{
  position:absolute;right:4px;top:4px;z-index:2;
  width:17px;height:17px;
  border:1.5px solid rgba(255,255,255,.95);
  border-radius:50%;                 /* 圆形复选框，选中红底打勾 */
  background:rgba(0,0,0,.18);
  box-shadow:0 1px 3px rgba(0,0,0,.3);
  pointer-events:none;
  opacity:0;transform:scale(.55);
  transition:opacity .18s,transform .18s,background .15s,border-color .15s;
}
.wipe-grid.sel .wipe-shot .wipe-check,
.wipe-shot .wipe-check.on{
  opacity:1;transform:none;pointer-events:auto;
}
.wipe-shot .wipe-check.on{
  background:#e0342f;
  border-color:#e0342f;
  -webkit-mask:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7' fill='none' stroke='white' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-size:78% 78%;
  background-position:center;
  background-repeat:no-repeat;
}
/* 图上的日期角标：右上角（原来在左下，被实况角标挤着，也压住了画面主体） */
.wipe-shot .wipe-day{
  position:absolute;right:4px;top:3px;z-index:2;
  font-style:normal;
  font-size:calc(clamp(9px,2.2cqw,10.5px) * var(--fs));
  letter-spacing:.04em;
  color:#fff;
  text-shadow:0 1px 3px rgba(0,0,0,.55);
  transition:opacity .18s;
}
/* 多选态：同一角落要让给复选框，日期先淡出 */
.wipe-grid.sel .wipe-shot .wipe-day{opacity:0}

.wipe-empty{
  grid-column:1 / -1;
  padding:9cqh 0 5cqh;
  text-align:center;
  font-size:calc(clamp(11px,2.8cqw,12.5px) * var(--fs));
  letter-spacing:.12em;
  color:var(--ink-3);
  transition:color .35s;
}

/* 底部操作栏：默认收在屏幕下沿之外，有选中才上滑。
   与回收站一致——不铺整条白底，只让那颗胶囊按钮浮在中间。 */
.wipe-bar{
  position:absolute;left:0;right:0;bottom:0;z-index:20;
  display:flex;align-items:center;justify-content:center;gap:12px;
  padding:12px 5cqw calc(12px + env(safe-area-inset-bottom, 0px));
  background:none;border-top:none;
  pointer-events:none;
  transform:translateY(140%);
  transition:transform .28s cubic-bezier(.22,1,.36,1);
}
.wipe-bar.on{transform:none}
.wipe-bar > span{display:none}        /* 计数已并入标题（只藏直接子级的那颗，别误伤按钮里的文字） */
.wipe-bar .btn-solid{
  flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;gap:7px;
  height:44px;
  padding:0 24px;
  border:1px solid var(--card-border);border-radius:999px;cursor:pointer;
  pointer-events:auto;
  font-family:var(--font-sans);
  font-size:calc(clamp(12.5px,3.1cqw,14px) * var(--fs));
  letter-spacing:.16em;line-height:1;
  background:var(--card-bg);color:var(--ink);
  box-shadow:var(--float-shadow);
  transition:background .35s,color .35s,opacity .2s;
}
.wipe-bar .btn-solid svg{
  width:16px;height:16px;flex:0 0 auto;
  fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;
}
/* 清空所选：不再红底/黑底，跟列表页那次「恢复 / 删除」同一套浅底 + 细描边 */
.wipe-bar .btn-solid.danger{background:var(--card-bg);color:var(--ink)}
/* 清空所选：点按不做任何反馈动画（原来会掉透明度，并继承 .btn-solid 的 scale(.96)） */
.wipe-bar .btn-solid:active{opacity:1;transform:none}
.wipe-bar .btn-solid:disabled{opacity:.45;cursor:default}

/* ============================================================
   批量导入页：照片横排在顶 + 拍立得预览 + 模板行 + 应用到全部
   （顶栏 / 工具区复用编辑页的类，外观由下方深色块统一接管）
   ============================================================ */
.batch-strip-wrap{position:relative;flex:0 0 auto;padding:.4cqh 0 0}
.batch-strip{
  display:flex;gap:2.6cqw;overflow-x:auto;
  margin:0 5cqw;padding:1.4cqw .6cqw;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
.batch-strip::-webkit-scrollbar{display:none}
.bth{
  flex:0 0 auto;width:13.5cqw;height:13.5cqw;max-width:64px;max-height:64px;
  border:none;border-radius:2cqw;cursor:pointer;
  background-size:cover;background-position:center;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.16);
  transition:box-shadow .16s;
}
.bth.on{box-shadow:0 0 0 2px var(--accent)}
.batch-count{
  position:absolute;top:.9cqh;right:5cqw;
  font-family:var(--font-mono);font-size:calc(clamp(10px,2.6cqw,11.5px) * var(--fs));
  letter-spacing:.12em;color:rgba(232,230,225,.38);pointer-events:none;
}
/* 预览里的卡是「成片示意」：照片本身可拖动调整，没有「换照片」这个动作 */
.batch-stage #batch-slot{cursor:grab}
#batch-date-text{
  font-family:var(--font-serif);color:var(--ink);
  font-size:calc(clamp(12px,3.2cqw,14px) * var(--fs));letter-spacing:.1em;
}
/* 星期：与回忆页卡片 .card-week 同一套（1px 分隔线 + 浅色衬线小字） */
.ed-week{
  position:relative;padding-left:1.7cqw;
  font-family:var(--font-serif);font-weight:500;
  font-size:calc(clamp(10.5px,2.8cqw,12.5px) * var(--fs));
  letter-spacing:.06em;color:var(--ink-3);
  white-space:nowrap;
}
.ed-week::before{
  content:'';position:absolute;left:0;top:50%;
  width:1px;height:8px;margin-top:-4px;background:rgba(28,28,30,.26);
}
.ed-week:empty{display:none}
/* 预览卡信息区：日期（+星期）贴左、地点贴右；两个按钮改实线细边（不要虚线） */
#page-batch .date-wrap{
  justify-content:space-between;align-items:center;
  gap:2cqw;margin:0 0 1.2cqw;
}
#page-batch .date-btn,
#page-batch .loc-btn{
  margin:0;border-style:solid;border-color:rgba(28,28,30,.14);background:transparent;
}
#page-batch .date-btn{flex:0 0 auto}
/* 地点胶囊：从「只有图标」改成「图标 + 地名」；地名太长就省略号截断。
   宽度上限控在整行一半，长地名不会把日期挤到换行。 */
#page-batch .loc-btn{
  display:inline-flex;align-items:center;gap:1.1cqw;
  flex:0 1 auto;   /* 空间不够时允许收缩，省略号接手 —— 不然长地名会把整行顶出去 */
  width:auto;height:auto;min-width:0;max-width:50%;
  padding:.34em 2.2cqw .34em 1.8cqw;
}
#page-batch .loc-btn svg{width:12px;height:12px;flex:0 0 auto}
#page-batch #batch-loc-text{
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-family:var(--font-serif);
  font-size:calc(clamp(11px,2.9cqw,12.5px) * var(--fs));
  letter-spacing:.06em;color:var(--accent);
}
/* 没地址 → 退回纯图标的小胶囊 */
#page-batch .loc-btn.empty{padding-left:.9em;padding-right:.9em}
#page-batch .loc-btn.empty #batch-loc-text{display:none}
#page-batch .loc-btn.has{border-color:rgba(var(--accent-rgb),.5)}
/* 写下此刻：贴左，与日期按钮同一起点 */
#page-batch .caption{text-align:left}
.batch-apply{
  display:block;width:100%;margin-top:2.8cqw;padding:2.5cqw 0;
  background:transparent;border:1px solid rgba(255,255,255,.14);border-radius:2.2cqw;
  color:rgba(232,230,225,.72);cursor:pointer;
  font-size:calc(clamp(12px,3.1cqw,13.5px) * var(--fs));letter-spacing:.1em;
  transition:opacity .15s,background .15s;
}
.batch-apply:active{background:rgba(255,255,255,.08)}
.batch-apply[disabled]{opacity:.38;cursor:default}
/* 单条模式拆成两个状态：
   · batch-single（< 2 张）：只藏「应用到所有」—— 没有第二张，应用没有意义；
     缩略条要留着：条上有清除钮和「继续添加」的 + 格
   · batch-edit（编辑老条目）：缩略条整个藏掉 —— 单条覆盖保存，增删照片无意义 */
#page-batch.batch-single #batch-apply-all{display:none}
#page-batch.batch-edit .batch-strip-wrap{display:none}
/* 预览卡放大：批量页更大（两侧 padding 7cqw，可用宽 86cqw，卡片吃 84cqw）
   照片格改 4:5 后卡片整体变高，宽度按「高度也得装得下」算：
   舞台高度减去日期行 / 题注 / 卡片内边距（约 100px）后，留给照片的 1.25 倍。 */
#page-batch .polaroid{max-width:min(93cqw, calc((100cqh - 235px) / 1.25))}

/* ============ 编辑页：底部模板区改直角 ============
   模板缩略卡原来是 6px 圆角、应用按钮 12px —— 这一屏改成直角语系：
   模板卡 / 「应用到所有」都去圆角（顶栏两颗按钮仍是 12px，不动） */
#page-batch .tpl-frame{border-radius:0}
#page-batch .batch-apply{border-radius:0}
#page-batch .date-btn,
#page-batch .loc-btn{border-radius:999px;padding-left:2.6cqw;padding-right:2.6cqw}
/* 信息行两端贴齐照片边缘：日期左边、地址右边都不留内边距
   （这条必须排在上面那条之后 —— 同特异性，靠顺序覆盖） */
#page-batch .date-btn{padding-left:0}
#page-batch .loc-btn{padding-right:0}
.batch-strip .bth{border-radius:10px}
/* 缩略格右上角清除钮：深色半透明小圆底 + 白 ✕，压在图上（16px，不抢缩略格） */
.bth{position:relative}
.bth-x{
  position:absolute;top:3px;right:3px;z-index:2;
  width:16px;height:16px;
  display:grid;place-items:center;padding:0;
  background:rgba(20,18,16,.62);
  border:none;border-radius:50%;
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  box-shadow:0 1px 3px rgba(0,0,0,.35);
  transition:transform .15s;
}
.bth-x svg{width:9px;height:9px;fill:none;stroke:#fff;stroke-width:2.6;stroke-linecap:round}
.bth-x:active{transform:scale(.85)}
/* 条尾「继续添加」格：淡白底的 + 号，与照片格同尺寸（.bth 类自带） */
.bth-add{display:grid;place-items:center;background:rgba(255,255,255,.05)}
.bth-add svg{width:38%;height:38%;fill:none;stroke:rgba(232,230,225,.6);stroke-width:2;stroke-linecap:round}
.bth-add:active{background:rgba(255,255,255,.12)}
/* 弹层里的输入：跟地点卡片同一档圆角 */
#loc-input{border-radius:12px}


/* 批量导入页：同一套深色外观 */
#page-batch{
  --ed-bg:#1b1b1f;
  --ed-card:#232327;
  --ed-line:rgba(255,255,255,.09);
  --ed-ink:#e8e6e1;
  --ed-ink2:rgba(232,230,225,.62);
  --ed-ink3:rgba(232,230,225,.38);
  background:var(--ed-bg);color:var(--ed-ink);
}
#page-batch .editor-bar{background:var(--ed-bg)}
#page-batch .btn-ghost{color:var(--ed-ink2);background:transparent;border-color:var(--ed-line)}
#page-batch .btn-ghost:active{background:rgba(255,255,255,.08)}
#page-batch .btn-solid{background:var(--ed-ink);color:#1b1b1f;border-color:transparent;box-shadow:none}
#page-batch .editor-tools{background:var(--ed-card);border-top-color:var(--ed-line)}
#page-batch .tpl{color:var(--ed-ink3);background:none;border:none}
#page-batch .tpl.active{color:#ffffff}

/* ============ 编辑页：所有选择一律白色边框 ============
   这一屏的选择型控件都在深色底上，统一白描边，不再用主色红圈：
     · 模板缩略卡：默认卡片自带白纸，选中环由红改纯白
     · 缩略图条：默认淡白描边，选中纯白 + 2px
     · 「应用到所有」：白色细边
     · 顶栏「取消」：白色细边（原来 9% 白，几乎看不见）
   —— 日期 / 地点两枚胶囊落在白色拍立得卡上，白边不可见，保留深色细边 */
#page-batch .tpl.active .tpl-frame{box-shadow:0 0 0 1.5px #ffffff,0 2px 8px rgba(0,0,0,.38)}
#page-batch .tpl[data-tpl="none"] .tpl-frame{box-shadow:inset 0 0 0 1px rgba(255,255,255,.28)}
#page-batch .tpl[data-tpl="none"].active .tpl-frame{box-shadow:inset 0 0 0 1px rgba(255,255,255,.28),0 0 0 1.5px #ffffff}
#page-batch .bth{box-shadow:inset 0 0 0 1px rgba(255,255,255,.38)}
#page-batch .bth.on{box-shadow:0 0 0 2px #ffffff}
#page-batch .batch-apply{border-color:rgba(255,255,255,.66)}
#page-batch .btn-ghost{border-color:rgba(255,255,255,.66)}

/* ============================================================
   意见反馈页（我的 → 意见反馈）
   —— 顶栏直接复用 .trash-head（与「关于 / 账号安全」同一套），
      下面按「类型 / 正文 / 截图 / 联系方式 / 历史」分段，
      每段 = 极紧的小标签 + 一张白卡；底部提交条常驻，不随滚动跑。
   ============================================================ */
.fb-body{
  flex:1;min-height:0;overflow-y:auto;
  padding:1.2cqh 5cqw calc(92px + 0px);
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
}
.fb-body::-webkit-scrollbar{display:none}

.fb-sec{margin-top:3.2cqh}
.fb-sec:first-child{margin-top:1.2cqh}
/* 段落头：左标签、右辅注（可多选 / 字数 / 可选），与设置行同样的字距语系 */
.fb-sec-head{
  display:flex;align-items:center;justify-content:space-between;gap:3cqw;
  padding:0 .4cqw 1.4cqh;
}
.fb-label{
  font-size:calc(clamp(12px,3.1cqw,13.5px) * var(--fs));
  font-weight:500;letter-spacing:.12em;color:var(--ink);
  transition:color .35s;
}
.fb-opt,.fb-count{
  flex:0 0 auto;
  font-family:var(--font-mono);
  font-size:calc(clamp(10px,2.5cqw,11px) * var(--fs));
  letter-spacing:.08em;color:var(--ink-3);
  transition:color .35s;
}
/* 字数到顶：换成主题红，提示再写就截断了 */
.fb-count.max{color:var(--accent)}
.fb-count + .fb-count{margin-left:auto}

/* ---------- 正文 ---------- */
.fb-text-wrap{
  padding:2.4cqw 3.4cqw;
  background:var(--card-bg);
  border:1px solid var(--card-border);
  border-radius:16px;
  transition:background .35s,border-color .2s;
}
/* 聚焦：描边换成主题红的淡描边，不至于让整块卡片跳动 */
.fb-text-wrap:focus-within{border-color:rgba(var(--accent-rgb),.42)}
.fb-text{
  display:block;width:100%;
  min-height:17cqh;max-height:44cqh;
  background:none;border:none;outline:none;resize:none;
  font-family:var(--font-serif);
  font-size:calc(clamp(13px,3.3cqw,14.5px) * var(--fs));
  letter-spacing:.06em;line-height:1.85;color:var(--ink);
  transition:color .35s;
}
.fb-text::placeholder{color:var(--ink-3);letter-spacing:.05em;line-height:1.85}

/* ---------- 截图：3 张 + 加号（同一行四列，缺的图位不塌） ---------- */
.fb-shots{
  display:grid;grid-template-columns:repeat(4,1fr);
  gap:2.4cqw;
}
.fb-shot{
  position:relative;aspect-ratio:1;
  border-radius:12px;overflow:hidden;
  background:rgba(28,28,30,.06);
  transition:background .35s;
}
.fb-shot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.fb-shot-del{
  position:absolute;right:1.6cqw;top:1.6cqw;z-index:2;
  width:20px;height:20px;padding:0;
  display:grid;place-items:center;cursor:pointer;
  border-radius:50%;border:none;
  background:rgba(0,0,0,.5);color:#fff;
  opacity:0;transform:scale(.7);pointer-events:none;
  transition:opacity .18s,transform .18s;
}
.fb-shot-del svg{width:10px;height:10px;stroke:currentColor;fill:none;stroke-width:2.4;stroke-linecap:round}
/* 有图时删除钮常显；空位不加 */
.fb-shot:not(.empty) .fb-shot-del{opacity:1;transform:none;pointer-events:auto}
.fb-add{
  appearance:none;cursor:pointer;
  aspect-ratio:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.8cqw;
  background:none;
  border:1px dashed rgba(28,28,30,.22);
  border-radius:12px;
  color:var(--ink-3);
  transition:border-color .2s,color .2s,background .2s;
}
.fb-add:active{background:rgba(28,28,30,.04)}
.fb-add svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.fb-add span{
  font-size:calc(clamp(9px,2.4cqw,10px) * var(--fs));
  letter-spacing:.1em;color:var(--ink-3);
  transition:color .35s;
}
/* 已满 3 张：加号位收起来（.fb-shots 只剩三列图） */
.fb-shots.full .fb-add{display:none}



/* ---------- 反馈历史页：整卡列表，行间 hairline ---------- */
.fb-history-list{
  background:var(--card-bg);
  border-radius:16px;overflow:hidden;
  transition:background .35s;
}
.fb-hist{
  display:flex;align-items:flex-start;gap:3cqw;
  padding:2.6cqw 4cqw;
  border-bottom:var(--hairline);
}
.fb-hist:last-child{border-bottom:none}
.fb-hist-main{flex:1;min-width:0}
.fb-hist-top{display:flex;align-items:center;gap:2cqw}
.fb-hist-type{
  flex:0 0 auto;
  padding:.3em .7em;
  border-radius:999px;
  background:rgba(var(--accent-rgb),.08);
  font-size:calc(clamp(9px,2.4cqw,10px) * var(--fs));
  letter-spacing:.08em;color:var(--accent);line-height:1.4;
  transition:background .35s,color .35s;
}
.fb-hist-date{
  font-family:var(--font-mono);
  font-size:calc(clamp(9px,2.4cqw,10px) * var(--fs));
  letter-spacing:.06em;color:var(--ink-3);
  transition:color .35s;
}
/* 状态：已收到 = 灰字；已回复 = 主题红 */
.fb-hist-status{
  flex:0 0 auto;
  font-size:calc(clamp(10px,2.5cqw,11px) * var(--fs));
  letter-spacing:.08em;color:var(--ink-3);
  transition:color .35s;
}
.fb-hist-status.replied{color:var(--accent)}
.fb-hist-text{
  margin-top:.9cqw;
  font-size:calc(clamp(11.5px,2.9cqw,12.5px) * var(--fs));
  letter-spacing:.05em;line-height:1.75;color:var(--ink-2);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;
  transition:color .35s;
}
.fb-hist-empty{
  padding:4.4cqw;
  text-align:center;
  font-size:calc(clamp(11px,2.8cqw,12px) * var(--fs));
  letter-spacing:.08em;color:var(--ink-3);
  transition:color .35s;
}

/* ---------- 底部提交条：与回收站 / 清空数据同一套——不铺整条白底，
   只让提交按钮自己悬浮居中（白底 + 大圆角 + 统一柔和投影） ---------- */
.fb-bar{
  position:absolute;left:0;right:0;bottom:0;z-index:20;
  display:flex;align-items:center;justify-content:center;
  padding:12px 5cqw calc(12px + env(safe-area-inset-bottom, 0px));
  background:none;border-top:none;
  pointer-events:none;
}
.fb-submit{
  pointer-events:auto;
  flex:0 0 auto;
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  height:44px;padding:0 28px;
  border-radius:999px;
  background:var(--card-bg);color:var(--ink);
  border:1px solid var(--card-border);
  box-shadow:var(--float-shadow);
}
.fb-submit svg{
  width:15px;height:15px;flex:0 0 auto;
  fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round;
}
/* 未填完：只降透明度，不做成"灰按钮"以免看起来像禁用态文字也糊掉 */
.fb-submit[disabled]{opacity:.34;box-shadow:none;cursor:default}
.fb-submit[disabled]:active{transform:none}

/* ============================================================
   意见反馈首页：常见问题列表；反馈历史在顶栏右上角，底部只留「我要反馈」
   —— 问题列表是一张整卡（行间用 hairline 分隔），点一行展开答案；
      答案用 max-height 过渡，比计算 scrollHeight 慢一拍但老内核也稳。
   ============================================================ */
.faq-body{
  flex:1;min-height:0;overflow-y:auto;
  padding:1.2cqh 5cqw calc(88px + 0px);
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
}
.faq-body::-webkit-scrollbar{display:none}

/* 问题列表：无卡片底、无圆角、无边框线，直接落在页面底色上，靠行距区分条目 */
.faq-list{
  background:none;
  border:none;
  border-radius:0;
  transition:background .35s,border-color .35s;
}
/* 去掉卡片后，问题行与上方「常见问题」标签同一竖线（清掉表头那 .4cqw 的微缩进） */
.faq-body .fb-sec-head{padding-left:0;padding-right:0}
/* 条目间只留一道极淡的间隔线（0.5px + 低对比，别显成黑线）；首尾不加 */
.faq-item + .faq-item{border-top:var(--hairline)}

/* 空状态：后台还没发布 FAQ（FAQ 已全部走后台发布，前端不内置文案） */
.faq-empty{
  padding:2.1cqh 0;
  font-family:var(--font-serif);
  font-size:calc(clamp(12px,3cqw,13.5px) * var(--fs));
  letter-spacing:.08em;line-height:1.6;color:var(--ink-3);
  text-align:center;
}

.faq-q{
  appearance:none;width:100%;cursor:pointer;
  display:flex;align-items:center;gap:3cqw;
  padding:1.3cqh 0;   /* 无卡片：左右不留内边距，与上方「常见问题」标签同一竖线；行距收紧让列表更密 */
  background:none;border:none;text-align:left;
  font-family:var(--font-serif);
  font-size:calc(clamp(12.5px,3.1cqw,14px) * var(--fs));
  letter-spacing:.06em;line-height:1.6;color:var(--ink);
  transition:color .2s;
}
.faq-q:active{color:var(--ink-2)}
.faq-q span{flex:1;min-width:0}
.faq-caret{
  flex:0 0 auto;width:12px;height:12px;
  stroke:var(--icon-2);fill:none;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round;
  transition:transform .2s ease,stroke .2s;
}
/* 箭头指右：示意「进入详情」而非原地展开；按下时轻推一下给方向感 */
.faq-q:active .faq-caret{transform:translateX(2px);stroke:var(--accent)}

/* FAQ 解答页（复用文档页）：顶栏固定「常见问题」，问题原文放正文最上方，
   与答案之间用一道 hairline 分开 —— 问题属于内容，不再顶到标题栏里去。
   选择器带 .doc-prose 前缀压过 .doc-prose h2 的默认字号/外边距 */
.doc-prose .faq-doc-q{
  font-family:var(--font-serif);
  font-size:calc(clamp(15px,3.7cqw,17px) * var(--fs));
  font-weight:600;color:var(--ink);
  letter-spacing:.02em;line-height:1.6;
  margin:4px 0 14px;
  padding-bottom:12px;
  border-bottom:var(--hairline);
}

.faq-more{
  margin-top:3cqh;
  text-align:center;
  font-size:calc(clamp(10.5px,2.6cqw,11.5px) * var(--fs));
  letter-spacing:.08em;color:var(--ink-3);
  transition:color .35s;
}

/* ---------- 右上角图标按钮：反馈历史（.trash-head 是 flex，margin-left:auto 推到最右） ---------- */
.fb-icon-btn{
  flex:0 0 auto;margin-left:auto;margin-right:-8px;
  width:34px;height:34px;padding:0;
  display:grid;place-items:center;
  background:none;border:none;cursor:pointer;color:var(--icon-2);
  transition:transform .2s,color .2s;
}
.fb-icon-btn svg{
  width:19px;height:19px;
  stroke:currentColor;fill:none;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
}
.fb-icon-btn:active{transform:scale(.9);color:var(--ink)}

/* ---------- 底部入口：与回收站 / 清空数据同一套——不铺整条白底，
   「我要反馈」自己悬浮居中（白底 + 大圆角 + 统一柔和投影） ---------- */
.fb-home-bar{
  position:absolute;left:0;right:0;bottom:0;z-index:20;
  display:flex;align-items:center;justify-content:center;
  padding:12px 5cqw calc(12px + env(safe-area-inset-bottom, 0px));
  background:none;border-top:none;
  pointer-events:none;
}
.fb-hbtn{
  appearance:none;cursor:pointer;
  pointer-events:auto;
  height:44px;padding:0 30px;
  display:flex;align-items:center;justify-content:center;gap:2.2cqw;
  border-radius:999px;
  border:1px solid var(--card-border);
  background:var(--card-bg);
  color:var(--ink);
  font-size:calc(clamp(12px,3cqw,13.5px) * var(--fs));
  letter-spacing:.14em;
  box-shadow:var(--float-shadow);
  transition:background .2s,border-color .2s,color .2s,transform .12s;
}
.fb-hbtn:active{transform:scale(.97)}
.fb-hbtn.primary svg{
  flex:0 0 auto;width:15px;height:15px;
  stroke:currentColor;fill:none;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
}

/* ============================================================
   下拉选择（自己画）
   —— 不用原生 <select>：安卓各版本弹出的 picker 长得都不一样，
      也没法把选项排成跟页面同一套字距。这里就是「触发条 + 浮层」。
   ============================================================ */
.fb-select{position:relative}
.fb-select-btn{
  appearance:none;cursor:pointer;width:100%;
  display:flex;align-items:center;gap:3cqw;
  padding:1.9cqh 3.2cqw;
  background:var(--card-bg);
  border:1px solid var(--card-border);
  border-radius:14px;
  text-align:left;
  transition:background .35s,border-color .2s;
}
.fb-select.open .fb-select-btn{border-color:rgba(var(--accent-rgb),.42)}
.fb-select-val{
  flex:1;min-width:0;
  font-family:var(--font-serif);
  font-size:calc(clamp(12.5px,3.1cqw,14px) * var(--fs));
  letter-spacing:.08em;color:var(--ink-3);
  transition:color .2s;
}
/* 选过之后再变主体色：空白时是占位灰 */
.fb-select.picked .fb-select-val{color:var(--ink)}
.fb-select-caret{
  flex:0 0 auto;width:12px;height:12px;
  stroke:var(--icon-2);fill:none;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;
  transition:transform .26s ease;
}
.fb-select.open .fb-select-caret{transform:rotate(180deg)}

.fb-select-menu{
  position:absolute;left:0;right:0;top:calc(100% + 1.2cqw);z-index:30;
  padding:1cqw;
  background:var(--card-bg);
  border:1px solid var(--card-border);
  border-radius:14px;
  box-shadow:0 12px 32px -10px rgba(30,30,70,.28);
  opacity:0;visibility:hidden;transform:translateY(-4px);
  transition:opacity .18s,visibility .18s,transform .18s;
}
.fb-select.open .fb-select-menu{opacity:1;visibility:visible;transform:translateY(0)}
.fb-select-opt{
  appearance:none;width:100%;cursor:pointer;
  display:flex;align-items:center;gap:3cqw;
  padding:1.6cqh 2.4cqw;
  border:none;border-radius:10px;
  background:none;text-align:left;
  font-family:var(--font-serif);
  font-size:calc(clamp(12.5px,3.1cqw,14px) * var(--fs));
  letter-spacing:.08em;color:var(--ink);
  transition:background .18s,color .18s;
}
.fb-select-opt:active{background:rgba(28,28,30,.05)}
.fb-select-opt.on{color:var(--accent);background:rgba(var(--accent-rgb),.07)}
.fb-select-opt i{flex:1;min-width:0;font-style:normal}
.fb-select-opt svg{
  width:11px;height:11px;
  stroke:currentColor;fill:none;stroke-width:2.2;
  stroke-linecap:round;stroke-linejoin:round;
  opacity:0;
}
.fb-select-opt.on svg{opacity:1}

/* 历史页右上角的条数（.trash-head 是 flex，靠 margin-left:auto 推到最右） */
.fb-head-count{margin-left:auto}

/* ============================================================
   个人信息页（我的 → 个人信息）
   —— 上：圆形头像 + 右下角相机角标（点击进裁剪页）
   —— 下：一张信息卡，行间 hairline；昵称是右侧可直接输入的框
   ============================================================ */
.pi-body{
  flex:1;min-height:0;overflow-y:auto;
  padding:1.6cqh 5cqw calc(40px + 0px);
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
}
.pi-body::-webkit-scrollbar{display:none}

.pi-ava-wrap{
  display:flex;flex-direction:column;align-items:center;
  padding:2.4cqh 0 .6cqh;
}
.pi-ava{
  position:relative;width:92px;height:92px;
  padding:0;border:none;background:none;cursor:pointer;border-radius:50%;
  transition:transform .2s;
}
.pi-ava:active{transform:scale(.96)}
/* 没换过头像时是人在灰底上；换过之后 svg 隐藏、背景图铺满 */
.pi-ava-img{
  display:grid;place-items:center;
  width:100%;height:100%;border-radius:50%;
  background-color:#e5e5e7;
  background-size:cover;background-position:center;
  color:rgba(60,60,67,.55);
  box-shadow:0 0 0 1px rgba(28,28,30,.06);
  transition:background-color .35s,color .35s,box-shadow .35s;
}
.pi-ava-img svg{
  width:46px;height:46px;
  stroke:currentColor;fill:none;stroke-width:1.4;
  stroke-linecap:round;stroke-linejoin:round;
}
.pi-ava.has-img .pi-ava-img svg{display:none}
/* 角标：墨黑圆点 + 白色描边环，环色跟页面底色走（夜间自动变深） */
.pi-ava-badge{
  position:absolute;right:-1px;bottom:-1px;
  width:28px;height:28px;border-radius:50%;
  display:grid;place-items:center;
  background:rgba(0,0,0,.55);color:#fff;
  box-shadow:0 0 0 2.5px var(--page-bg);
  transition:background .35s;
}
.pi-ava-badge svg{
  width:15px;height:15px;
  stroke:currentColor;fill:none;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;
}
.pi-ava-tip{
  margin-top:2.4cqw;
  font-size:calc(clamp(10.5px,2.7cqw,11.5px) * var(--fs));
  letter-spacing:.12em;color:var(--ink-3);
  transition:color .35s;
}
/* 头像下方不再写「点击更换头像」（相机角标已经说明可点），改成账号 UID */
.pi-uid{
  display:flex;align-items:baseline;gap:.62em;
  margin-top:calc(2.4cqw + 2px);
}
.pi-uid-k{font-size:.86em;color:var(--ink)}
.pi-uid-v{
  font-weight:500;color:var(--ink-2);
  letter-spacing:.18em;                 /* 6 位数字拉开，像编号而不是数字 */
  font-variant-numeric:tabular-nums;    /* 等宽数字：0/1 不跳动，切换账号也不左右晃 */
}

.pi-card{
  margin-top:3.6cqh;
  border-radius:16px;overflow:hidden;
  background:var(--card-bg);
  transition:background .35s;
}
.pi-row{
  display:flex;align-items:center;gap:3cqw;
  width:100%;min-height:54px;
  padding:3.4cqw 4.2cqw;
  border:none;border-bottom:var(--hairline);
  background:none;cursor:pointer;text-align:left;
  font-family:var(--font-serif);
  transition:background .2s,border-color .35s;
}
.pi-row:last-child{border-bottom:none}
.pi-row.static{cursor:default}
button.pi-row:active{background:#f6f6f4}
.pi-label{
  flex:0 0 auto;
  font-size:calc(clamp(13px,3.3cqw,14.5px) * var(--fs));
  letter-spacing:.1em;color:var(--ink);
  transition:color .35s;
}
.pi-value{
  flex:1;min-width:0;text-align:right;
  font-size:calc(clamp(12px,3.1cqw,13.5px) * var(--fs));
  letter-spacing:.06em;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:color .35s;
}
.pi-value.dim{color:var(--ink-3)}
.pi-arrow{
  flex:0 0 auto;width:13px;height:13px;
  stroke:var(--icon-3);fill:none;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
}
/* 昵称：右侧输入框，无边框无底色，光标就在文字末端 */
.pi-input{
  flex:1;min-width:0;padding:0;
  background:none;border:none;outline:none;
  text-align:right;
  font-family:var(--font-serif);
  font-size:calc(clamp(12px,3.1cqw,13.5px) * var(--fs));
  letter-spacing:.06em;color:var(--ink);
  transition:color .35s;
}
.pi-input::placeholder{color:var(--ink-3)}

/* ============================================================
   头像裁剪弹窗（#ava-crop-sheet）
   —— 从底部升起的深色面板：标题 → 裁剪舞台 → 提示 → 底部取消/完成
   —— 照片四周压暗（.ac-box 的巨型 box-shadow），框内保留原色
   —— 自由裁剪：四个角拖动改宽高、框内拖动改位置，不锁比例
   ============================================================ */
.ac-sheet{
  position:absolute;inset:0;z-index:460;
  display:flex;align-items:flex-end;
  background:rgba(0,0,0,.52);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .26s,visibility .26s;
}
.ac-sheet.on{opacity:1;visibility:visible;pointer-events:auto}
.ac-panel{
  width:100%;height:90%;
  display:flex;flex-direction:column;
  background:#111113;
  border-radius:20px 20px 0 0;
  transform:translateY(100%);
  transition:transform .34s cubic-bezier(.22,1,.36,1);
  box-shadow:0 -14px 44px -16px rgba(0,0,0,.55);
}
.ac-sheet.on .ac-panel{transform:none}
.ac-title{
  flex:0 0 auto;margin:0;text-align:center;
  padding:18px 0 2px;
  font-weight:400;
  font-size:calc(clamp(13px,3.2cqw,14.5px) * var(--fs));
  letter-spacing:.16em;color:rgba(255,255,255,.9);
}
.ac-stage{
  flex:1;min-height:0;
  display:grid;place-items:center;
  padding:2cqh 6cqw;
  overflow:hidden;              /* 巨型 box-shadow 只压暗舞台内 */
}
.ac-wrap{position:relative;line-height:0;touch-action:none}
.ac-img{
  display:block;width:100%;height:100%;
  -webkit-user-drag:none;user-select:none;
}
.ac-box{
  position:absolute;
  outline:1px solid rgba(255,255,255,.9);
  box-shadow:0 0 0 9999px rgba(0,0,0,.58);
  cursor:move;touch-action:none;
  will-change:left,top,width,height;
}
/* 四个角的 L 形把手：细白线，够粗但不喧宾夺主 */
.ac-h{
  position:absolute;width:20px;height:20px;
  border:0 solid #fff;
}
.ac-h.tl{left:-1px;top:-1px;border-left-width:2.5px;border-top-width:2.5px}
.ac-h.tr{right:-1px;top:-1px;border-right-width:2.5px;border-top-width:2.5px}
.ac-h.bl{left:-1px;bottom:-1px;border-left-width:2.5px;border-bottom-width:2.5px}
.ac-h.br{right:-1px;bottom:-1px;border-right-width:2.5px;border-bottom-width:2.5px}
.ac-tip{
  flex:0 0 auto;text-align:center;
  padding:0 6cqw 16px;
  font-size:calc(clamp(10.5px,2.7cqw,11.5px) * var(--fs));
  letter-spacing:.1em;color:rgba(255,255,255,.42);
}
/* 底部两颗按钮：取消=描边、完成=白底（原先在顶栏，现在固定在面板底部） */
.ac-actions{
  flex:0 0 auto;
  display:flex;gap:10px;
  padding:0 20px calc(22px + 0px);
}
.ac-btn{
  flex:1;height:48px;cursor:pointer;
  appearance:none;border-radius:12px;
  border:1px solid rgba(255,255,255,.16);
  background:transparent;color:rgba(255,255,255,.72);
  font-family:var(--font-serif);
  font-size:calc(clamp(12.5px,3.1cqw,14px) * var(--fs));
  letter-spacing:.14em;
  transition:opacity .2s,background .2s,transform .12s;
}
.ac-btn:active{opacity:.72}
.ac-btn.solid{
  background:#fff;color:#141416;border-color:#fff;
  letter-spacing:.12em;
}
.ac-btn.solid:active{opacity:1;transform:scale(.985)}

/* ============================================================
   绑定手机号弹层（.sheet 骨架 + .pt-* 排版，只多一个手机号输入框）
   ============================================================ */
.ph-input{
  width:100%;height:48px;padding:0 16px;
  background:#f7f7f9;border:none;border-radius:12px;
  font-family:var(--font-mono);
  font-size:calc(clamp(15px,3.9cqw,17px) * var(--fs));
  letter-spacing:.16em;color:var(--ink);
  outline:none;text-align:center;
  transition:background .2s,color .35s;
}
.ph-input::placeholder{
  font-family:var(--font-serif);letter-spacing:.1em;color:var(--ink-3);
}
.ph-input:focus{background:#f2f2f5}
.ph-status{
  min-height:17px;margin-top:8px;
  text-align:center;
  font-size:calc(clamp(10.5px,2.6cqw,11.5px) * var(--fs));
  letter-spacing:.06em;color:var(--ink-3);
  transition:color .2s;
}
.ph-status.err{color:var(--danger)}

/* ===== 协议 / 政策文档页（#page-doc）：正文来自后台发布的简化 Markdown ===== */
.doc-body{height:100%;overflow-y:auto;padding:6px 22px 46px;-webkit-overflow-scrolling:touch}
.doc-prose{max-width:620px;margin:0 auto;padding-top:6px}
.doc-prose h2{
  font-family:var(--font-serif);
  font-size:calc(clamp(15px,3.6cqw,17px) * var(--fs));
  font-weight:600;color:var(--ink);
  margin:26px 0 8px;letter-spacing:.02em;
}
.doc-prose h2:first-child{margin-top:4px}
.doc-prose p{
  font-size:calc(clamp(12.5px,3cqw,13.5px) * var(--fs));
  line-height:1.95;color:var(--ink-2);margin:0 0 12px;
}
.doc-prose ul{margin:0 0 12px;padding-left:20px}
.doc-prose li{
  font-size:calc(clamp(12.5px,3cqw,13.5px) * var(--fs));
  line-height:1.95;color:var(--ink-2);
}
.doc-prose strong{font-weight:600;color:var(--ink)}
.doc-loading{padding:40px 0;text-align:center;color:var(--ink-3);font-size:12.5px}

/* ===== 详情页加载骨架（#page-doc：协议正文拉取期间与 FAQ 详情共用同一页面） ===== */
.doc-skeleton{max-width:620px;margin:0 auto;padding-top:16px}
.doc-sk{
  height:11px;border-radius:4px;margin-bottom:9px;
  background:var(--hairline);
  animation:doc-sk-pulse 1.15s ease-in-out infinite;
}
.doc-sk-gap{height:16px}
@keyframes doc-sk-pulse{0%,100%{opacity:.5}50%{opacity:1}}

/* ===== 更新弹窗 / 协议更新弹窗（#upd / #agr）
     骨架与 .confirm 同一套：暗遮罩 + 白卡 + 投影，z-index 560 压在确认弹窗之上；
     卡顶的品牌双框取景框与关于页 logo 同源（品牌标记不随夜间模式反色） ===== */
.upd{
  position:absolute;inset:0;z-index:560;
  display:grid;place-items:center;
  padding:0 8cqw;
  background:rgba(0,0,0,.5);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .22s,visibility .22s;
}
.upd.on{opacity:1;visibility:visible;pointer-events:auto}
.upd-card{
  width:100%;max-width:330px;
  padding:8cqw 6.4cqw 5.6cqw;
  background:var(--card-bg);
  border:none;
  border-radius:18px;
  /* 卡片不带投影：白色卡片浮在暗遮罩上已经够分离，再压一层厚阴影显脏 */
  box-shadow:none;
  transform:translateY(14px) scale(.98);
  transition:transform .26s cubic-bezier(.2,.7,.2,1);
}
.upd.on .upd-card{transform:none}
.upd-mark{
  display:block;width:13cqw;height:13cqw;max-width:56px;max-height:56px;
  margin:0 auto;
  padding:2.4cqw;box-sizing:border-box;
  border-radius:22%;
  background:var(--panel-bg);
}
.upd-mark svg{display:block;width:100%;height:100%}
.upd-title{
  margin-top:4.4cqw;
  font-family:var(--font-serif);
  font-size:calc(clamp(15px,3.9cqw,17px) * var(--fs));
  font-weight:400;letter-spacing:.14em;
  color:var(--ink);text-align:center;
}
.upd-ver{
  margin-top:1.6cqw;text-align:center;
  font-family:var(--font-mono);
  font-size:calc(clamp(10.5px,2.7cqw,12px) * var(--fs));
  letter-spacing:.14em;color:var(--accent);
}
.upd-notes{
  margin-top:4.6cqw;
  max-height:30vh;overflow-y:auto;-webkit-overflow-scrolling:touch;
  padding:3.4cqw 4cqw;
  background:var(--panel-bg);border-radius:12px;
}
.upd-notes p{
  margin:0;
  font-family:var(--font-serif);
  font-size:calc(clamp(11.5px,3cqw,13px) * var(--fs));
  line-height:1.9;letter-spacing:.05em;
  color:var(--ink-2);
}
.upd-notes p + p{margin-top:1.4cqw}
.upd-actions{display:flex;gap:2.4cqw;margin-top:6cqw}
.upd-actions button{
  flex:1;height:11cqw;min-height:44px;cursor:pointer;
  font-family:var(--font-serif);font-size:calc(clamp(12px,3.1cqw,13.5px) * var(--fs));
  letter-spacing:.14em;
  border:none;border-radius:12px;background:var(--panel-bg);color:var(--ink-2);
  transition:opacity .2s,background .2s,color .2s;
}
.upd-actions button:active{opacity:.7}
.upd-actions .solid{background:var(--ink);color:#fff}

/* 应用内下载进度条：贴在操作按钮上方，细长一条，跟主色 */
.upd-bar{
  margin-top:4.6cqw;height:5px;border-radius:99px;
  background:var(--panel-bg);overflow:hidden;
}
.upd-bar i{
  display:block;height:100%;width:0%;border-radius:99px;
  background:var(--accent);
  transition:width .18s linear;
}
.upd-bar.undet i{width:36%;animation:upd-undet 1.1s ease-in-out infinite alternate}
@keyframes upd-undet{from{margin-left:0}to{margin-left:64%}}

/* 崩溃日志弹窗：等宽小字号堆栈，可滚动、可复制 */
.crash-log{
  margin:4.6cqw 0 0;
  max-height:34vh;overflow:auto;-webkit-overflow-scrolling:touch;
  padding:3.4cqw 4cqw;
  background:var(--panel-bg);border-radius:12px;
  font-family:var(--font-mono);
  font-size:calc(clamp(9.5px,2.5cqw,11px) * var(--fs));
  line-height:1.7;letter-spacing:0;
  color:var(--ink-2);
  white-space:pre;word-break:break-all;
}

/* 协议更新弹窗的差异部分：协议链接列表（进文档页看全文） */
.upd.agr .upd-title{margin-top:1cqw}
.agr-sub{
  margin-top:2.6cqw;
  font-family:var(--font-serif);
  font-size:calc(clamp(11.5px,3cqw,13px) * var(--fs));
  line-height:1.9;letter-spacing:.05em;
  color:var(--ink-2);text-align:center;
}
/* 两份协议并排一行：竖排两行在这个只有标题+两行文案的小弹窗里太占地方，
   也显得郑重其事；横排一行、点谁进谁。 */
.agr-list{
  margin-top:4.4cqw;
  display:flex;justify-content:center;align-items:baseline;gap:10cqw;
}
.agr-link{
  flex:none;display:inline-flex;align-items:center;gap:2cqw;
  padding:2.6cqw 1cqw;cursor:pointer;
  background:none;border:none;
  font-family:var(--font-serif);text-align:center;
}
.agr-link b{
  font-size:calc(clamp(12.5px,3.2cqw,14px) * var(--fs));
  font-weight:600;letter-spacing:.04em;color:var(--ink);
}
.agr-link:active b{color:var(--accent)}
.agr-tip{
  margin-top:1cqw;
  font-family:var(--font-mono);
  font-size:calc(clamp(8.5px,2.2cqw,10px) * var(--fs));
  letter-spacing:.1em;color:var(--ink-3);text-align:center;
}

/* ===== 原生壳安全区（只在 Capacitor 包里生效） =====
   html[data-shell] 由 js/cap-bridge.js 开机就写上：
     ios / android = 原生包      → 下面两条命中
     web           = 浏览器/PWA  → 一条都不命中（iPhone Safari 也会报
                     env(safe-area-inset-bottom)，所以绝不能写成 html[data-shell]）
   .page 是 flex 列，padding 把内容整体推离状态栏；
   .tabbar 是绝对定位，单独抬起；预览页（#viewer）故意不做，照片要满屏。
   安卓走沉浸式：WebView 铺满整屏（内容画到状态栏底下），状态栏透明只留图标，
   WebView 里 env(safe-area-inset-*) 恒为 0，所以高度由原生量好塞进
   --sf-sat / --sf-sab（js/cap-bridge.js 写入）；没拿到时回落到 env()。 */
html[data-shell="ios"] .page,
html[data-shell="android"] .page{
  padding-top:var(--sf-sat, env(safe-area-inset-top, 0px));
}
/* 足迹页例外：地图不做避让，直接通到状态栏底下 —— 状态栏本身透明
   （MainActivity / cap-bridge 都设了透明），时间/电量浮在地图上才是真沉浸。
   地图页顶部没有任何可点控件，最下面的地址抽屉从 1/3 高度起，都碰不到状态栏。 */
html[data-shell="ios"] #page-track,
html[data-shell="android"] #page-track{
  padding-top:0;
}
html[data-shell="ios"] .tabbar,
html[data-shell="android"] .tabbar{
  bottom:calc(var(--sf-sab, env(safe-area-inset-bottom, 0px)) + 10px);
}


/* ===== 字体分层（table.csv） =====
   内容层（叙事、有阅读感）保留宋体：卡片正文/星期/地点、月份标题、照片墙与
   地址抽屉标题、关于页、空状态、FAQ 问题、文档正文、那年今日、字体弹窗演示卡
   —— 走 body 默认的 --font-serif，不在此覆盖。
   标注层（数据、编号）等宽不变：日期 / 计数 / 眉标 / UID / 状态行 已是 --font-mono。
   工具层（操作、控件）统一切黑体：所有按钮、输入框、下拉、分段/菜单/设置行、
   弹窗标题。老规则里特异性更高的在块内原样镜像（同特异性、靠后取胜）。 */
.btn-solid,.btn-ghost,.trash-del,.fb-submit,.pt-btn,
.confirm-actions button,.upd-actions button,.auth-submit,
.auth-input,.pi-input,#search-input,#loc-input,
.ph-input,.ph-input::placeholder,
.fb-select-btn,.fb-select-opt,.sheet-search input,
.p-toggle-info span,.p-row-label,
.upd-title,.ac-title,.sheet-title,
.view-tabs .vs-btn,.year-btn,.search-submit,.history-clear,.month-more,
.p-entry,.seg-btn,#page-profile .pf-me,.p-row,.trash-all,
.viewer.ops .v-actions,.pt-actions,.menu.on .menu-card,.ls-actions,.loc-use,
.wipe-ym-btn,.wipe-bar .btn-solid,.btn-ghost:active,.trash-del:active,
.fb-text-wrap,.fb-text-wrap textarea,.fb-hbtn,.ac-btn,.agr-link{
  font-family:var(--font-sans);
}
.upd.agr .upd-title,
.fb-select.open .fb-select-btn,
.fb-select.open .fb-select-menu,
.ls-head b,.acct-static,.about-check,.about-link,
.loc-btn,.date-btn,.ph-status.err,.pt-title,
.wipe-select-all,.pz-layout{
  font-family:var(--font-sans);
}

/* ===== 更新日志页（#page-changelog：关于页右上角日志按钮进入，
     GET /api/app/releases 拉全部发布版本，每版一张卡。
     复用文档页的 .doc-body / .doc-skeleton，这里只补版本卡的样式） ===== */
.cl-list{max-width:620px;margin:0 auto;padding-top:6px}
.cl-card{padding:16px 0 20px;border-bottom:var(--hairline)}
.cl-card:first-child{padding-top:10px}
.cl-head{display:flex;align-items:baseline;gap:2.4cqw;margin-bottom:8px}
.cl-ver{
  font-family:var(--font-mono);
  font-size:calc(clamp(14px,3.5cqw,15.5px) * var(--fs));
  font-weight:600;color:var(--ink);letter-spacing:.04em;
}
.cl-date{
  font-family:var(--font-mono);
  font-size:calc(clamp(9.5px,2.3cqw,11px) * var(--fs));
  letter-spacing:.1em;color:var(--ink-3);
}
.cl-card ul{list-style:none;margin:0;padding:0}
.cl-card li{
  position:relative;padding-left:14px;
  font-size:calc(clamp(12.5px,3cqw,13.5px) * var(--fs));
  line-height:1.9;color:var(--ink-2);letter-spacing:.02em;
}
.cl-card li::before{
  content:"";position:absolute;left:2px;top:.85em;
  width:4px;height:4px;border-radius:50%;background:var(--ink-3);
}

/* ===== 无字条目占位：编辑页「写下此刻」没写就保存的条目不再显示
     「无言的此刻」，但标题行保留一行高度（不塌版面） ===== */
.card-cap:empty::before{content:"\00a0"}
.pp-cap:empty::before{content:"\00a0"}
.td-cap:empty::before{content:"\00a0"}
