/* zyphotos — 常规摄影图库样式
   主题：浅色 / 深色 / 跟随系统（html[data-theme]），主题色由 --accent 驱动 */

/* 水印字体：与后端服务端渲染（internal/watermark，Go）用的是**同一个字体文件**，
   由 ops/extract_ttf.py 从系统的 wqy-microhei.ttc 抽出第 0 个 face（常规体），
   ops/font_check.py 校验 web 端与 Go 内嵌那份逐字节一致。
   微米黑只有常规字重 —— 水印统一用常规字重，不再让浏览器合成粗体（合成粗体和
   服务端成品不一致）。 */
@font-face {
  font-family: 'WQY MicroHei';
  src: url('/fonts/wqy-microhei.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root,
[data-theme="light"] {
  --bg: #f7f8fa;
  --surface: #ffffff;
  --surface-2: #f1f3f6;
  --surface-3: #e8ebef;
  --border: #e5e7eb;
  --border-strong: #d3d8e0;
  --text: #111827;
  --text-muted: #626d7a;
  --text-soft: #8d96a3;
  --header-bg: #ffffff;
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05);
  --shadow-md: 0 2px 8px rgba(16, 24, 40, .07);
  --shadow-lg: 0 10px 28px rgba(16, 24, 40, .12);
  --skeleton: #eef0f3;
  --skeleton-hi: #e3e6ea;
}

[data-theme="dark"] {
  --bg: #0e1014;
  --surface: #161a20;
  --surface-2: #1c2027;
  --surface-3: #242932;
  --border: #282d36;
  --border-strong: #3d4450;
  --text: #e9ebef;
  --text-muted: #9aa2b0;
  --text-soft: #737c8a;
  --header-bg: #161a20;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .35);
  --shadow-md: 0 2px 10px rgba(0, 0, 0, .40);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, .50);
  --skeleton: #1c2027;
  --skeleton-hi: #242932;
}

:root {
  /* 圆角四档：小标记 / 交互件 / 按钮输入 / 容器浮层。
     圆形（50%）只留给头像与步骤序号 —— 那是功能性圆形，不是装饰。 */
  --radius-xs: 6px;
  --radius-sm: 8px;
  --radius: 10px;
  --radius-lg: 14px;
  --radius-pill: 999px;

  /* 间距阶梯：8 起、相邻比 ≈1.5~1.6（接近黄金分割），替代原先随手写的 14/12/10 */
  --sp-1: 8px;
  --sp-2: 12px;
  --sp-3: 16px;
  --sp-4: 24px;
  --sp-5: 40px;
  --sp-6: 64px;

  --accent: #2563eb;
  --accent-soft: rgba(37, 99, 235, .12);
  --accent-ring: rgba(37, 99, 235, .35);
  --accent-contrast: #ffffff;
  --accent-deep: rgba(37, 99, 235, .85);
  --header-h: 60px;
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* 各页高度不同时，滚动条出现/消失不再把整页横向推一下 */
  scrollbar-gutter: stable;
  /* 移动端点击不再闪一个灰色高亮块（自己有 :active 反馈） */
  -webkit-tap-highlight-color: transparent;
  /* 刻意**不设**全局 scroll-behavior: smooth —— 站内没有页内锚点，需要平滑滚动的两处
     （上传步骤切换、个人中心定位）都显式传了 behavior；全局设置反而会让浏览器
     前进/后退时的"滚动位置恢复"也变成动画滚动，观感更慢更怪。 */
}

/* ---------------- 跨页转场（流畅度核心） ----------------
   本站是多页应用（每个 HTML 一次完整导航）。这里启用跨文档 View Transitions：
   新旧页面之间做一次极短的交叉淡入，并且把页头/页脚单独命名——它们在新旧页面里
   几乎一致，于是会被"原地保留"而不参与淡入，观感是"外壳不动、内容换"，
   不会出现整屏闪白。不支持的浏览器自动退化为普通跳转，功能不受影响。 */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: .16s;
  animation-timing-function: ease-out;
}
/* 页头/页脚：不淡入，直接沿用旧位置，避免"跳一下" */
header.site { view-transition-name: site-header; }
.footer { view-transition-name: site-footer; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  transition: background-color .18s ease, color .18s ease;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: none; opacity: .85; }

img { max-width: 100%; }

.container { width: 100%; max-width: 1240px; margin: 0 auto; padding: 0 var(--sp-4); }

/* ---------------- 顶部导航 ---------------- */

header.site {
  position: sticky; top: 0; z-index: 40;
  background: var(--header-bg);
  border-bottom: 1px solid var(--border);
  /* 页头由 JS 渲染，先占住高度，避免脚本执行前"零高度→突然撑开"把正文顶下去 */
  min-height: calc(var(--header-h) + 1px);
}

header.site .header-inner {
  display: flex; align-items: center; gap: 20px;
  height: var(--header-h);
}

.logo { display: flex; align-items: center; gap: 10px; color: var(--text); flex: 0 0 auto; }
.logo:hover { opacity: 1; }
.logo-mark {
  width: 32px; height: 32px; border-radius: var(--radius-sm); flex: 0 0 auto;
  display: grid; place-items: center;
  background: var(--accent); color: var(--accent-contrast);
  font-weight: 800; font-size: 14px; letter-spacing: -.5px;
}
.logo-text { font-weight: 700; font-size: 16.5px; letter-spacing: -.2px; line-height: 1.1; }
.logo-text small {
  display: block; font-weight: 400; font-size: 11.5px;
  color: var(--text-muted); letter-spacing: .3px; margin-top: 1px;
}

.main-nav { display: flex; align-items: center; gap: 4px; flex: 1 1 auto; min-width: 0; overflow-x: auto; }
.main-nav a {
  padding: 7px 12px; border-radius: var(--radius-sm); color: var(--text-muted);
  font-size: 14px; white-space: nowrap;
}
.main-nav a:hover { background: var(--surface-2); color: var(--text); opacity: 1; }
.main-nav a.active { color: var(--accent); background: var(--accent-soft); font-weight: 600; }

.header-actions { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.header-user { display: flex; align-items: center; gap: 8px; color: var(--text-muted); font-size: 13px; }

/* ---------------- 按钮 ---------------- */

button, .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer; border-radius: var(--radius); border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text);
  padding: 9px 16px; font-size: 14px; font-family: inherit; line-height: 1.4;
  /* 悬停反馈刻意做"短促"：光标在一排按钮之间扫过时，上一颗要立刻落下去、下一颗立刻亮起来。
     原来 150ms 会看到两道半透明底色交叠，这正是"不丝滑"的来源。 */
  transition: background-color .12s ease-out, border-color .12s ease-out,
              color .12s ease-out, box-shadow .12s ease-out, transform .08s ease;
}
button:hover, .btn:hover { background: var(--surface-2); box-shadow: var(--shadow-sm); }
button:active, .btn:active { transform: translateY(1px); box-shadow: none; }
button.primary, .btn-primary {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); font-weight: 600;
}
button.primary:hover, .btn-primary:hover { background: var(--accent-deep); border-color: var(--accent-deep); }
button.danger, .btn-danger { color: #b42318; border-color: #f5c6c2; background: #fef3f2; }
button.danger:hover, .btn-danger:hover { background: #fee4e2; }
[data-theme="dark"] button.danger,
[data-theme="dark"] .btn-danger { color: #ffb4ab; border-color: #5a2626; background: #2b1a1a; }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }
.btn-sm { padding: 6px 12px; font-size: 13px; border-radius: var(--radius-sm); }
.btn-block { width: 100%; }
button:disabled, .btn:disabled { opacity: .5; cursor: not-allowed; box-shadow: none; }

.icon-btn {
  width: 36px; height: 36px; padding: 0; border-radius: var(--radius-sm);
  border-color: transparent; background: transparent; color: var(--text-muted);
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }
.icon-btn svg { width: 19px; height: 19px; display: block; }

/* 主题控件 */
.theme-widget { position: relative; display: flex; align-items: center; gap: 2px; }
.theme-icon { display: none; align-items: center; justify-content: center; }
[data-theme-mode="system"] .theme-icon[data-icon="system"],
[data-theme-mode="light"] .theme-icon[data-icon="light"],
[data-theme-mode="dark"] .theme-icon[data-icon="dark"],
html:not([data-theme-mode]) .theme-icon[data-icon="system"] { display: flex; }
#accent-toggle .theme-icon { display: flex; }

/* 行内主题色兜底：脚本正常时由 JS 覆盖 --accent-soft 等派生变量 */
@supports (color: color-mix(in srgb, red 10%, transparent)) {
  :root {
    --accent-soft: color-mix(in srgb, var(--accent) 12%, transparent);
    --accent-ring: color-mix(in srgb, var(--accent) 35%, transparent);
  }
}

.accent-panel {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  width: 224px; padding: 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  /* 展开/收起：淡入淡出 + 极轻微下移，不再"啪"地出现与消失。
     用 visibility（而非 display）保证收起后不可聚焦、不进入无障碍树。 */
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(-4px) scale(.985);
  transform-origin: top right;
  transition: opacity .16s ease, transform .16s ease, visibility 0s linear .16s;
}
.accent-panel.open {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: none;
  transition: opacity .16s ease, transform .16s ease, visibility 0s;
}
.accent-panel__title { font-size: 12px; color: var(--text-muted); margin-bottom: 10px; }
.accent-presets { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin-bottom: 10px; }
.accent-swatch {
  height: 28px; padding: 0; border-radius: var(--radius-xs); border: 2px solid transparent;
  background: var(--sw); cursor: pointer;
}
.accent-swatch.on { border-color: var(--text); box-shadow: 0 0 0 2px var(--surface) inset; }
.accent-custom { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 13px; color: var(--text-muted); }
.accent-custom input[type="color"] {
  width: 40px; height: 28px; padding: 2px; border-radius: var(--radius-xs);
  border: 1px solid var(--border-strong); background: var(--surface-2); cursor: pointer;
}
.accent-panel__foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 12px; }
.accent-panel__hint { font-size: 11px; color: var(--text-soft); }

/* ---------------- 主区域 ---------------- */

main {
  flex: 1 1 auto; width: 100%;
  max-width: 1200px; margin: 0 auto;
  padding: var(--sp-4) var(--sp-4) var(--sp-6);
}
/* 页面已在 main 内自带 .container 时不再重复计算内边距 */
main > .container { max-width: none; padding-left: 0; padding-right: 0; }

/* 窄栏页面（登录 / 注册 / 找回密码 / 邮箱验证 / 账号申诉）。
   原先这五页各自写内联 style="max-width:520px;padding-left:20px"，两处问题：
   ① 绕过 --sp-* 间距令牌；② 内联样式优先级高于媒体查询，移动端给的
   内边距被它盖掉，小屏上内容离屏幕边只有 20px。统一收到这里。 */
main.narrow { max-width: 560px; padding-left: var(--sp-4); padding-right: var(--sp-4); }

.crumbs { color: var(--text-soft); font-size: 13px; margin-bottom: var(--sp-2); }
.crumbs a { color: var(--text-muted); }
.crumbs span.sep { margin: 0 6px; opacity: .6; }

/* 字号阶梯：13 / 15 / 17 / 21 / 27 / 32 —— 每级都肉眼可辨。
   刻意不用 1.618 做字号：15×1.618=24.3、再上一级直接跳到 39，在 1240px 容器里会头重脚轻，
   且非整数更容易渲染发糊。黄金分割留给"版式比例与间距"（见上面的 --sp-*）。 */
h1, h2, h3 { line-height: 1.28; margin: 0 0 12px; letter-spacing: -.2px; }
h1 { font-size: 27px; font-weight: 700; }
h2 { font-size: 21px; font-weight: 650; }
h3 { font-size: 17px; font-weight: 600; }

/* 首页头图 */
.hero { padding: var(--sp-3) 0 var(--sp-1); }
.hero h1 { font-size: 32px; margin-bottom: 8px; letter-spacing: -.5px; }
.hero p { color: var(--text-muted); margin: 0 0 var(--sp-4); font-size: 15px; max-width: 62ch; }

.search-bar { display: flex; gap: 8px; max-width: 560px; }
.search-bar input { flex: 1 1 auto; }

/* 过滤条 */
.filter-bar {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  margin: var(--sp-4) 0 var(--sp-3); padding-bottom: var(--sp-2); border-bottom: 1px solid var(--border);
}
.tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.tabs button, .tabs .btn {
  border-color: transparent; background: transparent; color: var(--text-muted);
  padding: 7px 13px; border-radius: var(--radius-sm); font-size: 14px;
}
.tabs button:hover, .tabs .btn:hover { background: var(--surface-2); color: var(--text); }
.tabs button.active, .tabs .btn.active {
  background: var(--accent-soft); color: var(--accent); border-color: transparent; font-weight: 600;
}
.filter-bar .spacer { flex: 1 1 auto; }

/* ---------------- 图库网格 ---------------- */

.gallery-grid {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(252px, 1fr));
}
/* 切分区 / 换搜索词 / 后台换页签：整块内容快速淡入 + 4px 上移，避免"闪一下"。
   位移只给 4px：这是在**已经铺满的网格**上重播一遍，位移给大了整屏会晃（v1.51）。 */
.gallery-grid.swap, .content-swap { animation: gridSwap .2s ease-out; }
@keyframes gridSwap { from { opacity: .4; transform: translateY(4px); } to { opacity: 1; transform: none; } }
/* 正在取新内容（换分区 / 搜新词）：给一点弱反馈，慢网下不至于像"点了没反应"。
   只降不透明度、不动布局，比换成骨架屏更不容易造成闪动。 */
.gallery-grid { transition: opacity .12s ease-out; }
.gallery-grid.is-loading { opacity: .55; }

.photo-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  overflow: hidden;
  /* 悬停只做"边框加深 + 浮一层极淡阴影"：仍然**不上浮、不放大图片**（§9.2 的约束） */
  transition: border-color .14s ease, box-shadow .14s ease;
}
.photo-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }

.photo-card .thumb {
  position: relative; display: block; width: 100%; aspect-ratio: 3 / 2;
  background: var(--surface-2) center/cover no-repeat; overflow: hidden;
}
.photo-card .thumb img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  opacity: 1; transition: opacity .22s ease;
}
/* 懒加载未命中的图片先隐藏，解码完成后淡入（JS 不可用时不会加这个类，图片照常显示） */
.photo-card .thumb img.lazy-pending { opacity: 0; }

/* 卡片入场：淡入 + 从下方 6px 浮上来（v1.51）。
   位移刻意压得很小 —— 首屏一次进场十来张，位移给大了整屏会"跳"一下；
   配合 AB.enterCards 的 18ms 错峰，读起来才是"一页接上一页"，而不是"换了一批"。
   只动 opacity / transform（合成器动画，不触发布局）。 */
@keyframes cardRiseIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
/* 入场动画只在"新出现的卡片"上播（JS 加 .enter）：
   整块重渲染时若每张都重播，会看到"刷"地闪一下，反而不流畅 */
.photo-card.enter { animation: cardRiseIn .24s cubic-bezier(.2, .7, .3, 1) both; }
/* 长列表（反复"加载更多"后可达上百张）跳过屏外卡片的渲染，滚动更稳。
   估高按 3:2 缩略图 + meta 重算：桌面 252px 宽 → 168 + 约 67 = 235px */
.photo-card { content-visibility: auto; contain-intrinsic-size: auto 235px; }
.photo-card .thumb .chip {
  position: absolute; left: 10px; top: 10px;
  background: rgba(0, 0, 0, .58); color: #fff; font-size: 11.5px;
  padding: 3px 8px; border-radius: var(--radius-xs);
}
/* 人工编排角标（v1.52：置顶 / 精选）挪到右上角 —— 分区角标已经占了左上角，
   两个都写 left:10px 会叠在一起。只挪位置，颜色仍沿用 .chip 那套黑底白字。 */
.photo-card .thumb .chip--right { left: auto; right: 10px; }

.photo-card .meta { padding: var(--sp-2) var(--sp-3) var(--sp-3); }
.photo-card .meta .t { font-weight: 600; font-size: 15px; margin-bottom: 6px; line-height: 1.45; }
.photo-card .meta .t a { color: var(--text); }
.photo-card .meta .s { color: var(--text-muted); font-size: 12.5px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.avatar {
  width: 18px; height: 18px; border-radius: 50%; flex: 0 0 auto;
  display: inline-grid; place-items: center; font-size: 10px; font-weight: 700;
  background: var(--accent-soft); color: var(--accent); text-transform: uppercase;
}

/* 自定义头像：图片覆盖原首字母样式 */
.avatar-img {
  object-fit: cover; display: inline-block;
  background: var(--surface-3);
}
.avatar.avatar-sm { width: 22px; height: 22px; font-size: 11px; }
.header-user { display: inline-flex; align-items: center; gap: 6px; }

/* 头像编辑器（拖动 + 缩放裁成 1:1） */
.av-canvas {
  width: 240px; height: 240px; max-width: 100%; display: block;
  border-radius: 50%; background: var(--surface-2); border: 1px solid var(--border);
  cursor: grab; touch-action: none;
}
.av-canvas:active { cursor: grabbing; }

/* 邮箱验证码输入（6 位，等宽 + 字距） */
.code-input {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 20px; letter-spacing: 9px; text-align: center;
}

/* 文字按钮（用于"重新发送验证码"这类轻量操作） */
.link-btn {
  border: none; background: none; padding: 0; margin: 0;
  color: var(--accent); font: inherit; cursor: pointer; text-decoration: underline;
}
.link-btn:disabled { color: var(--text-soft); cursor: default; text-decoration: none; }

.like {
  border: none; background: transparent; color: var(--text-soft);
  padding: 3px 8px; font-size: 12.5px; gap: 4px; border-radius: var(--radius-xs);
}
.like:hover { background: var(--surface-2); color: var(--accent); }
.like.on { color: #e5484d; font-weight: 600; }
.like.on:hover { color: #c62a2f; }
/* 心形与数字都固定宽度：♡ / ♥ 与 1 位→2 位数字的字宽差异会让同一行的其它元素左右抖 */
.like .h { font-size: 13px; display: inline-block; width: 1em; text-align: center; }
.like .n { display: inline-block; min-width: 1.1em; font-variant-numeric: tabular-nums; }

/* 浏览数等只读统计 */
.stat { color: var(--text-soft); font-size: 12.5px; }

/* 徽标 */
.badge {
  display: inline-block; padding: 1px 7px; border-radius: var(--radius-xs);
  font-size: 12px; line-height: 1.7;
  border: 1px solid var(--border-strong); color: var(--text-muted); background: var(--surface-2);
}
.badge.aviation { color: #0b6bcb; border-color: #b6dcff; background: #eff8ff; }
.badge.railway { color: #7a3fc4; border-color: #dcc7f5; background: #f7f1fe; }
[data-theme="dark"] .badge.aviation { color: #8ec9ff; border-color: #1d3a55; background: #12212e; }
[data-theme="dark"] .badge.railway { color: #c9a6f5; border-color: #3d2b55; background: #1e1729; }
.badge.ok { color: #067647; border-color: #abefc6; background: #ecfdf3; }
.badge.pending { color: #b54708; border-color: #fedf89; background: #fffaeb; }
.badge.bad { color: #b42318; border-color: #fecdca; background: #fef3f2; }
[data-theme="dark"] .badge.ok { color: #75e0a7; border-color: #1e4d33; background: #10231a; }
[data-theme="dark"] .badge.pending { color: #fec84b; border-color: #5a4416; background: #241c0c; }
[data-theme="dark"] .badge.bad { color: #ffb4ab; border-color: #5a2626; background: #2b1a1a; }

/* ---------------- 卡片 / 面板 ---------------- */

.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--sp-4);
}
.card + .card { margin-top: var(--sp-2); }

.panel-title {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  margin-bottom: var(--sp-3); padding-bottom: var(--sp-2); border-bottom: 1px solid var(--border);
}
.panel-title h2, .panel-title h3 { margin: 0; }

.grid { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fill, minmax(236px, 1fr)); }

/* 详情页主次栏用黄金分割（1.618 : 1）—— 这是 φ 真正好用的地方：版式比例 */
.stack { display: grid; gap: var(--sp-4); grid-template-columns: minmax(0, 1.618fr) minmax(0, 1fr); align-items: start; }
@media (max-width: 880px) { .stack { grid-template-columns: 1fr; } }

.empty { text-align: center; color: var(--text-muted); padding: var(--sp-5) var(--sp-3); }
.empty strong { display: block; color: var(--text); font-size: 16px; margin-bottom: 6px; font-weight: 600; }

/* 首页两个人工编排展示区（v1.52）：置顶区 / 精选区，压在普通图片流上方。
   间距沿用既有阶梯；标题只要两个字那么大就行，不抢图片的注意力。 */
.zone { margin-bottom: var(--sp-4); }
.zone__hd { margin: 0 0 var(--sp-2); font-size: 17px; }

.load-more-wrap { text-align: center; margin-top: var(--sp-4); }
.load-more-wrap button { min-width: 160px; }

/* 「加载更多」按钮（前台三处共用 .more-btn，保证三处的手感一致）—— v1.51
   按下比全局那一下 translateY(1px) 再多收一点点（scale .985），给"这一下点到了"的触感。
   只动 transform，不改尺寸、不影响排版。这里刻意**不写 transition**：全局 button 的过渡
   里已经带了 transform，再写一条 transition 会把 color / box-shadow 的过渡一并覆盖掉。 */
.more-btn:active { transform: translateY(1px) scale(.985); }

/* 到底了：按钮淡出 + 轻微下沉，**播完再收起**（不是"啪"地消失）。
   与后台 §27.11 的"退场要播完再摘节点"同一口径；退场期间挡住点击，
   避免"正在消失还能点到"。类名由 AB.moreRetire / AB.moreShow 管理。 */
.is-retiring { animation: moreOut .18s ease-in both; pointer-events: none; }
@keyframes moreOut { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(4px); } }

/* ---------------- 表单 ---------------- */

input, textarea, select {
  width: 100%; padding: 9px 12px; border-radius: var(--radius);
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
  font: inherit; transition: border-color .12s ease-out, box-shadow .12s ease-out;
}
input:focus, textarea:focus, select:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring);
}
input[type="color"] { padding: 2px; }
textarea { min-height: 88px; resize: vertical; }

label.field { display: block; margin-bottom: var(--sp-3); }
label.field > span { display: block; margin-bottom: 6px; color: var(--text-muted); font-size: 13px; font-weight: 500; }

/* ---------------- 机场代码自动补全（2026-09-25，站内反馈 #14） ----------------
   结构由 common.js 的 AB.airportPick() 把输入框包一层 .ac-wrap（**用 div 而不是 span**：
   label.field > span 是"字段标题"的样式，套在输入框外层会把输入框变成灰色小字）。
   下拉用 absolute 贴着输入框下沿，z-index 40 —— 高于卡片内容、低于模态框（300）。 */
.ac-wrap { position: relative; display: block; }
.ac-list {
  position: absolute; z-index: 40; left: 0; right: 0; top: calc(100% + 4px);
  max-height: 264px; overflow-y: auto; padding: 4px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.ac-item {
  display: flex; align-items: baseline; gap: var(--sp-2); width: 100%;
  padding: 7px 9px; border: 0; background: none; color: var(--text);
  font: inherit; text-align: left; border-radius: var(--radius-xs); cursor: pointer;
}
.ac-item:hover, .ac-item.is-active { background: var(--surface-2); box-shadow: none; }
.ac-item__cn { flex: 1 1 auto; }
.ac-item__code {
  flex: 0 0 auto; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; color: var(--text-muted);
}

/* ---------------- 通用"丝滑"件（v2.40） ----------------

   三条原则（与后台 §27.11 一致）：只动 transform/opacity（不触发布局）、
   动画只做"进场/状态切换"不拦路、prefers-reduced-motion 下全部降级为静态。 */

/* ① 顶部加载进度条：任何在途 API 请求都会点亮它（由 common.js 统一计数）。
      延迟 160ms 才现身 —— 秒回的请求不该闪一下进度条。 */
.ab-progress {
  position: fixed; left: 0; right: 0; top: 0; height: 2px; z-index: 1500;
  opacity: 0; pointer-events: none;
  transition: opacity .2s ease-out;
  background: transparent;
}
.ab-progress.on { opacity: 1; }
.ab-progress > i {
  display: block; height: 100%; width: 100%;
  transform-origin: 0 50%; transform: scaleX(0);
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent) 82%, transparent 100%);
  animation: abBarRun 1.4s cubic-bezier(.2, .7, .3, 1) infinite;
}
.ab-progress.done > i {
  animation: none; transform: scaleX(1); opacity: 0;
  transition: transform .2s ease-out, opacity .34s ease-out .1s;
}
@keyframes abBarRun {
  0% { transform: scaleX(0); }
  55% { transform: scaleX(.72); }
  100% { transform: scaleX(.94); }
}

/* ② 按钮忙态：在标签前加一圈转动的环（保留原文案，不改变按钮尺寸） */
.is-busy { opacity: .72; pointer-events: none; }
.is-busy::before {
  content: ''; display: inline-block; width: 12px; height: 12px; margin-right: 6px;
  vertical-align: -1px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: abSpin .6s linear infinite;
}
@keyframes abSpin { to { transform: rotate(360deg); } }

/* ③ 列表项错峰进场：给容器加 .ab-stagger，子项按 --i 依次淡入上移 */
.ab-stagger > * { animation: abRiseIn .34s cubic-bezier(.2, .7, .3, 1) both; animation-delay: calc(var(--i, 0) * 35ms); }
@keyframes abRiseIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

/* ④ 评论区骨架（加载中就占住位置，避免"先空一块再顶下来"） */
.cm-skel { padding: 8px 0; border-bottom: 1px dashed var(--line); }
.cm-skel i {
  display: block; height: 11px; border-radius: var(--radius-xs); background: var(--surface-2);
  background-image: linear-gradient(90deg, transparent, rgba(255, 255, 255, .35), transparent);
  background-size: 220px 100%; background-repeat: no-repeat;
  animation: cmSweep 1.5s linear infinite;
}
.cm-skel i + i { margin-top: 8px; width: 62%; }
.cm-skel i:first-child { width: 34%; }
@keyframes cmSweep { from { background-position: -220px 0; } to { background-position: 320px 0; } }

@media (prefers-reduced-motion: reduce) {
  .ab-progress { display: none; }
  .is-busy::before { animation: none; }
  .ab-stagger > * { animation: none; }
  .cm-skel i { animation: none; }
}

.row { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.row > * { flex: 1 1 200px; }
.row.tight { flex: 0 0 auto; align-items: center; gap: var(--sp-1); }
.row.tight > * { flex: 0 0 auto; }
.spacer { flex: 1 1 auto; }

/* ---------------- 表格 ---------------- */

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { padding: 8px 10px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; }
th { color: var(--text-muted); font-weight: 600; white-space: nowrap; background: var(--surface-2); }
tbody tr:hover { background: var(--surface-2); }
td.wrap { word-break: break-all; max-width: 320px; }

/* ---------------- 标签云 ---------------- */

.tagcloud { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.tagcloud a {
  color: var(--text-muted); padding: 4px 10px; border-radius: var(--radius-xs);
  background: var(--surface-2); border: 1px solid var(--border);
}
.tagcloud a:hover { color: var(--accent); border-color: var(--accent-ring); opacity: 1; }

/* ---------------- 详情 / 回答 ---------------- */

.answer-block { border-left: 3px solid var(--accent-soft); padding: 2px 0 2px 14px; margin-bottom: 16px; }
.answer-block .q { color: var(--text-muted); font-size: 13px; margin-bottom: 4px; }
.answer-block .a { white-space: pre-wrap; }

.meta-list { display: grid; gap: 10px; margin: 0; }
.meta-list div { display: flex; gap: 10px; font-size: 14px; }
.meta-list dt, .meta-list .k { color: var(--text-muted); flex: 0 0 84px; }
.meta-list dd, .meta-list .v { margin: 0; flex: 1 1 auto; word-break: break-word; }

/* ---------------- 上传页 ---------------- */


/* 分区切换（航空 / 铁路） */
.seg { display: inline-flex; gap: 5px; flex-wrap: wrap; }
.seg button {
  padding: 8px 16px; border-radius: var(--radius-sm); border: 1px solid var(--border-strong);
  background: var(--surface-2); color: var(--text-muted); font-size: 14px;
}
.seg button.on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }

/* 首页顶部的分区切换 */
.seg-lg { margin-bottom: var(--sp-1); }
.seg-lg button { padding: 10px 22px; font-size: 15px; }

/* 分区角标 */
.seg-badge {
  display: inline-block; padding: 1px 8px; border-radius: var(--radius-xs); font-size: 12.5px;
  background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-ring);
}

/* 标签多选 */
.tagpick { display: flex; flex-wrap: wrap; gap: 6px; }
.tagpick button {
  padding: 6px 12px; border-radius: var(--radius-sm); font-size: 13.5px;
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text-muted);
}
.tagpick button.on {
  border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600;
}
/* 勾选标记始终占位、只切透明度：否则每次选中都让整行标签重新换行排布（肉眼可见地跳） */
.tagpick button::after { content: ' ✓'; opacity: 0; }
.tagpick button.on::after { opacity: 1; }

.field-label { display: block; margin-bottom: 5px; color: var(--text-muted); font-size: 12.5px; font-weight: 500; }

/* 编号展示 */
.uuid-badge {
  display: inline-block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; padding: 2px 8px; border-radius: var(--radius-xs);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted);
  letter-spacing: .3px;
}

canvas.preview {
  width: 100%; max-width: 520px; border-radius: var(--radius-lg);
  border: 1px solid var(--border); background: var(--surface-2); display: block;
  touch-action: none;            /* 允许用指针拖动水印，避免触发页面滚动 */
  cursor: grab;
  -webkit-user-select: none; user-select: none;
}
canvas.preview.dragging { cursor: grabbing; }

.progress { height: 6px; background: var(--surface-3); border-radius: var(--radius-pill); overflow: hidden; }
/* 进度用 transform: scaleX：走合成器。旧实现改 width，每个进度事件都要重排一次 */
.progress > i {
  display: block; height: 100%; background: var(--accent);
  transform: scaleX(0); transform-origin: left center;
  transition: transform .18s ease-out;
}

/* FilePond 适配主题 */
.filepond--root { margin-bottom: 0; font-family: inherit; }
.filepond--panel-root { background: var(--surface-2); border: 1px dashed var(--border-strong); }
.filepond--drop-label { color: var(--text-muted); }
.filepond--label-action { color: var(--accent); }

/* ---------------- 通知 / 提示 ---------------- */

/* 详情页主图：与列表一致的淡入，避免大图"跳"出来 */
#shot { opacity: 1; transition: opacity .22s ease; }
#shot.lazy-pending { opacity: 0; }

.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  background: var(--surface); border: 1px solid var(--border-strong); color: var(--text);
  padding: 10px 16px; border-radius: var(--radius); z-index: 200;
  box-shadow: var(--shadow-md); max-width: 90vw; font-size: 13.5px;
  /* 进出都走 transform/opacity（合成器动画），不再生硬地弹出/消失。
     注意这里不能加 fill-mode（both/forwards）：终态会常驻并盖掉 .out 的退场过渡 */
  animation: toastIn .19s cubic-bezier(.2, .7, .3, 1);
  transition: opacity .17s ease, transform .17s ease;
}
@keyframes toastIn {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
.toast.out { opacity: 0; transform: translateX(-50%) translateY(6px); }

.notice { padding: var(--sp-2) var(--sp-3); border-radius: var(--radius); border: 1px solid var(--border); background: var(--surface-2); }
.notice-info { border-color: var(--accent-ring); background: var(--accent-soft); }
/* 警示提示条（账号封禁提示等）：用既有徽标的语义色系，深浅两套一致 */
.notice-warn { border-color: #fedf89; background: #fffaeb; color: #b54708; }
.notice-warn a { color: inherit; text-decoration: underline; }
[data-theme="dark"] .notice-warn { border-color: #5a4416; background: #241c0c; color: #fec84b; }

/* ---------------- 模态框（后台封禁 / 驳回表单） ---------------- */
.modal-mask {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(16, 24, 40, .45);
  display: grid; place-items: center; padding: 20px;
  animation: maskIn .14s ease-out;
}
@keyframes maskIn { from { opacity: 0; } to { opacity: 1; } }
.modal {
  width: 100%; max-width: 460px; max-height: 86vh; overflow: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  padding: var(--sp-4);
  animation: modalIn .16s cubic-bezier(.2, .7, .3, 1);
}
@keyframes modalIn {
  from { opacity: 0; transform: translateY(8px) scale(.98); }
  to { opacity: 1; transform: none; }
}
.modal-title { font-size: 17px; font-weight: 600; margin-bottom: var(--sp-3); }
.modal-body { font-size: 14px; }
.modal-body textarea { min-height: 84px; }
.modal-foot { display: flex; justify-content: flex-end; gap: var(--sp-1); margin-top: var(--sp-4); }
.modal-foot .btn-primary { min-width: 96px; }

/* ---------------- 页脚 ---------------- */

.footer {
  border-top: 1px solid var(--border); background: var(--surface);
  color: var(--text-muted); font-size: 12.5px; margin-top: 36px;
}
.footer .container { padding-top: 22px; padding-bottom: 18px; }
.footer-grid { display: flex; gap: 24px; flex-wrap: wrap; justify-content: space-between; }
.footer-brand { max-width: 300px; }
.footer-brand .logo-text { font-size: 15px; }
.footer-brand p { margin: 8px 0 0; color: var(--text-soft); font-size: 12.5px; line-height: 1.7; }
.footer-links { display: flex; gap: 32px; flex-wrap: wrap; }
.footer-links h4 { margin: 0 0 8px; font-size: 12.5px; color: var(--text); font-weight: 600; }
.footer-links a { display: block; color: var(--text-muted); font-size: 12.5px; margin-bottom: 6px; }
.footer-bottom {
  border-top: 1px solid var(--border); margin-top: 18px; padding-top: 12px;
  display: flex; gap: 12px; flex-wrap: wrap; justify-content: space-between;
  color: var(--text-soft); font-size: 12px;
}
/* ICP 备案号：法定公示信息，按惯例小字弱化，但必须清晰可读、可点 */
.footer-bottom .icp { color: var(--text-soft); }
.footer-bottom .icp a { color: inherit; }
.footer-bottom .icp a:hover { color: var(--accent); opacity: 1; }

/* ---------------- 分步向导 ---------------- */

.steps { display: flex; gap: 8px; list-style: none; margin: 0; padding: 0; flex-wrap: wrap; }
.steps li {
  display: flex; align-items: center; gap: 7px;
  padding: 6px 12px; border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-muted); font-size: 13px;
}
.steps li b {
  width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center;
  background: var(--border-strong); color: var(--surface); font-size: 11px;
}
.steps li.active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.steps li.active b { background: var(--accent); color: var(--accent-contrast); }
.steps li.done { color: var(--text); }
.steps li.done b { background: var(--accent); color: var(--accent-contrast); }
.steps li[data-clickable="1"] { cursor: pointer; }
.steps li[data-clickable="1"]:hover { border-color: var(--accent-ring); }

.step-panel { margin-top: 16px; }
/* 步骤切换：面板淡入 + 轻微上移，而不是"硬切"一下 */
.step-panel.step-in { animation: stepIn .18s ease-out; }
@keyframes stepIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.step-nav {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 16px;
}
.step-nav .spacer { flex: 1 1 auto; }

/* ---------------- 后台：左菜单栏 + 右操作区 ----------------
   桌面：左侧固定宽度菜单，右侧主区占剩下的全部空间（大头）；
   ≤900px：压成一列，菜单收成一行可横向滑动。所有尺寸走令牌，不写 px 硬编码。 */

main.admin-shell {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: start;
}
.admin-shell__top { grid-column: 1 / -1; }

.admin-side {
  position: sticky; top: calc(var(--header-h) + var(--sp-3));
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--sp-2);
}
.admin-side__head { padding: 0 var(--sp-2) var(--sp-2); border-bottom: 1px solid var(--border); }
.admin-side__title { font-size: 15px; font-weight: 700; letter-spacing: -.2px; }
.admin-side__who {
  display: flex; align-items: center; gap: 6px; margin-top: var(--sp-1);
  min-width: 0; color: var(--text-muted); font-size: 13px;
}
.admin-side__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admin-side__hint { margin: 6px 0 0; color: var(--text-soft); font-size: 11.5px; line-height: 1.5; }
.admin-side__foot { border-top: 1px solid var(--border); margin-top: var(--sp-1); padding: var(--sp-2) var(--sp-2) 0; }
.admin-side__foot a { color: var(--text-muted); font-size: 12.5px; }
.admin-side__foot a:hover { color: var(--accent); }

.admin-nav { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-1) 0; }
.admin-nav__label { padding: 0 var(--sp-2) 4px; color: var(--text-soft); font-size: 11.5px; }
.admin-nav button {
  width: 100%; justify-content: flex-start; gap: var(--sp-1);
  background: transparent; border-color: transparent; color: var(--text-muted);
  padding: 9px var(--sp-2); font-size: 14px; border-radius: var(--radius-sm);
}
.admin-nav button svg { width: 18px; height: 18px; flex: 0 0 auto; opacity: .8; }
.admin-nav button.active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.admin-nav button.active svg { opacity: 1; }
/* 有了滑动高光，未选中项不再自带 hover 底色（否则两道底色交叠，见 §23.4） */
.slide-host.admin-nav button:not(.active):hover { background-color: transparent; }

.admin-main { min-width: 0; }
.admin-page-head { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; margin: 0 0 var(--sp-3); }
.admin-page-head h1 { font-size: 21px; margin: 0; }
.admin-page-head p { margin: 0; color: var(--text-muted); font-size: 13px; }
.admin-loading { padding: var(--sp-5) 0; }
.admin-empty { padding: var(--sp-5) var(--sp-3); }
.admin-form { max-width: 720px; }
.admin-form h2 { margin-top: 0; }
.admin-color { width: 56px; flex: 0 0 auto; }

/* 主区工具条：一行放下筛选条件与操作按钮（原先每个控件都带内联 flex 样式） */
.admin-toolbar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-2); }
.admin-toolbar .field { flex: 0 0 auto; min-width: 140px; margin-bottom: 0; }
.admin-toolbar .field.grow { flex: 1 1 220px; min-width: 0; }
.admin-toolbar select { min-width: 120px; }
.admin-toolbar__end { display: flex; gap: var(--sp-1); margin-left: auto; }
.admin-toolbar__sum { align-self: center; }

/* ---------------- 工具类 ---------------- */

.muted { color: var(--text-muted); }
.small { font-size: 13px; }

/* ---------------- 站点公告浮层（置顶 + 压在所有 UI 之上 + 背后页面模糊） ----------------
   需求原文："强行置顶，在所有 ui 上面，后面的 ui 做模糊化处理"。
   z-index 取 2000：站内最高的是模态框 300、提示条 200（见本文件其它 z-index），公告要盖过它们。
   backdrop-filter 做毛玻璃；不支持该属性的旧浏览器退化为半透明纯色遮罩，仍能看清公告。 */
.notice-mask {
  position: fixed; inset: 0; z-index: 2000;
  display: flex; justify-content: center; align-items: flex-start;
  padding: 6vh var(--sp-3) var(--sp-4);
  overflow: auto;
  background: rgba(12, 15, 20, .42);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
  animation: maskIn .14s ease-out;
}
.notice-panel {
  width: 100%; max-width: 640px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  animation: modalIn .16s cubic-bezier(.2, .7, .3, 1);
}
/* 关闭时的退场（v1.61，站长："公告的关闭也做一个动画更丝滑一点"）：
   与进场对称 —— 遮罩淡出、面板轻微上移收小；只动 opacity/transform，不碰布局。
   时长与 common.js 的 NOTICE_OUT_MS（180ms）对齐：播完 JS 才摘节点，
   否则会看到动画播到一半节点被抽走。forwards 保证这段时间停在"已淡出"的状态。 */
.notice-mask.is-closing { animation: maskOut .18s ease-in forwards; pointer-events: none; }
.notice-mask.is-closing .notice-panel { animation: modalOut .18s cubic-bezier(.4, 0, .7, 1) forwards; }
@keyframes maskOut { from { opacity: 1; } to { opacity: 0; } }
@keyframes modalOut {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(-6px) scale(.985); }
}
.notice-panel__hd {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 13px var(--sp-4); border-bottom: 1px solid var(--border);
  font-weight: 600; font-size: 15px;
}
.notice-panel__hd .spacer { flex: 1; }
.notice-panel__bd { padding: 2px var(--sp-4) var(--sp-4); max-height: 62vh; overflow: auto; }
.notice-item { padding: var(--sp-3) 0; border-bottom: 1px dashed var(--border); }
.notice-item:last-child { border-bottom: 0; }
.notice-item h3 { margin: 0 0 4px; font-size: 15px; }
.notice-time { margin: 0 0 6px; font-size: 12px; color: var(--text-soft); }
.notice-text { margin: 0; font-size: 14px; line-height: 1.7; color: var(--text-muted); }
.center { text-align: center; }
.mt { margin-top: 12px; }
.mb { margin-bottom: 12px; }
.hidden { display: none !important; }
.divider { height: 1px; background: var(--border); margin: 16px 0; border: 0; }

/* 骨架微光：用 transform 平移一条高光带。
   旧实现动的是 background-position —— 每帧都要重绘整块渐变，首屏同时挂着十来块骨架时
   会明显吃掉帧预算；换成 transform 后由合成器处理，主线程不参与。 */
.skeleton { position: relative; overflow: hidden; background: var(--skeleton); }
.skeleton::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--skeleton-hi), transparent);
  transform: translateX(-100%);
  animation: shimmer 1.4s ease-in-out infinite;
}
@keyframes shimmer { 100% { transform: translateX(100%); } }

/* 骨架卡片（首屏数据到达前占位，避免空白跳动） */
.skeleton-card { animation: none; }
.skeleton-card .sk-thumb { display: block; width: 100%; aspect-ratio: 3 / 2; }
.skeleton-card .sk-meta { padding: var(--sp-3); display: grid; gap: var(--sp-1); }
.skeleton-card .sk-line { display: block; height: 12px; border-radius: var(--radius-xs); }
.skeleton-card .sk-line.short { width: 45%; }

.shake { animation: shake .18s linear 2; }
@keyframes shake { 25% { transform: translateX(-2px); } 75% { transform: translateX(2px); } }

/* ---------------- 滑动高亮：一排按钮之间的"丝滑"hover ----------------
   光标在同一排按钮上移动时，由**一块**高光跟着滑过去，而不是让每个按钮各自淡入淡出。
   后者在光标扫过时会看到两道半透明底色交叠，这正是"移过去不丝滑"的来源。
   .slide-host / .slide-hint 由 JS 的 AB.hoverSlide() 添加；脚本不可用或开启了
   "减少动态效果"时这两个类不存在，自动回落成普通 :hover 底色。 */
.slide-host { position: relative; }
.slide-hint {
  position: absolute; left: 0; top: 0; z-index: 0;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  opacity: 0; pointer-events: none;
  transition: transform .19s cubic-bezier(.2, .7, .3, 1),
              width .19s cubic-bezier(.2, .7, .3, 1),
              height .19s cubic-bezier(.2, .7, .3, 1),
              opacity .12s ease;
}
.slide-host > *:not(.slide-hint) { position: relative; z-index: 1; }

/* 有滑块之后，未选中项不再需要自己的 hover 底色（否则两道底色交叠）。
   用 :not(.active/.on) 排除选中项，保证选中态的主题色底不受影响。 */
.slide-host.main-nav a:not(.active):hover,
.slide-host.seg button:not(.on):hover,
.slide-host.tabs button:not(.active):hover,
.slide-host.tabs .btn:not(.active):hover { background-color: transparent; }

/* 响应式 */
@media (max-width: 900px) {
  .main-nav { order: 3; flex-basis: 100%; padding-bottom: 6px; }
  header.site .header-inner { height: auto; padding: 8px 0; flex-wrap: wrap; }
  header.site { min-height: auto; }
  .gallery-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--sp-2); }
  .hero h1 { font-size: 26px; }
  /* 顺带修掉一个既有问题：这里原来是 padding 横向 0，而 main > .container 又被清零，
     等于移动端内容直接贴屏幕边。现在给回内边距。 */
  main { padding: var(--sp-3) var(--sp-3) var(--sp-5); }
  main.narrow { padding-left: var(--sp-3); padding-right: var(--sp-3); }
  .photo-card { contain-intrinsic-size: auto 165px; }
  /* 后台：菜单从左侧栏收成顶部一行（可横向滑动），主区占满宽度 */
  main.admin-shell { grid-template-columns: 1fr; gap: var(--sp-3); }
  .admin-side { position: static; padding: var(--sp-1); }
  .admin-side__head, .admin-side__foot { display: none; }
  .admin-nav { flex-direction: row; gap: 4px; padding: 0; overflow-x: auto; }
  .admin-nav__label { display: none; }
  .admin-nav button { width: auto; white-space: nowrap; padding: 8px var(--sp-2); }
}
@media (max-width: 560px) {
  .container { padding: 0 var(--sp-2); }
  main { padding: var(--sp-3) var(--sp-2) var(--sp-5); }
  main.narrow { padding-left: var(--sp-2); padding-right: var(--sp-2); }
  /* 后台工具条：窄屏让控件各自占满一行，按钮不被挤成小方块 */
  .admin-toolbar .field, .admin-toolbar .field.grow { flex: 1 1 100%; }
  .admin-toolbar__end { margin-left: 0; width: 100%; }
  .admin-toolbar__end button { flex: 1 1 auto; }
  /* 触控目标：移动端主按钮放到 ≥44px，手指点得准 */
  button, .btn { padding: 11px 18px; font-size: 15px; }
  .photo-card .meta { padding: 10px 12px 12px; }
  .photo-card .meta .t { font-size: 14px; }
  .header-user { display: none; }
}

/* ---------------- 政策 / 协议类长文（隐私政策、用户协议、内容规范、免责声明） ----------------
   只用现有令牌，不引入新颜色；版式目标是"能读下去"：行长受 main.narrow 限制、段距拉开、
   小标题带编号（由 HTML 手写序号，便于站内互相引用）。 */
.legal { line-height: 1.8; }
.legal__meta {
  margin: 0 0 var(--sp-4);
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--line);
  color: var(--text-soft); font-size: 13px;
}
.legal h2 { margin: var(--sp-5) 0 var(--sp-2); font-size: 17px; }
.legal h2:first-of-type { margin-top: var(--sp-4); }
.legal h3 { margin: var(--sp-3) 0 var(--sp-1); font-size: 14.5px; }
.legal p { margin: 0 0 var(--sp-2); }
.legal ul, .legal ol { margin: 0 0 var(--sp-2); padding-left: 1.35em; }
.legal li { margin: 0 0 6px; }
.legal li::marker { color: var(--text-soft); }
/* 需要留意的一句：淡底 + 左侧色条，不用感叹号、不用大字（工具风不喊话） */
.legal__note {
  margin: 0 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--accent-soft);
  font-size: 13.5px;
}
.legal table { width: 100%; border-collapse: collapse; font-size: 13.5px; margin: 0 0 var(--sp-3); }
.legal th, .legal td { padding: 8px 10px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
.legal th { color: var(--text-soft); font-weight: 600; font-size: 12.5px; }
.legal code { font-size: 12.5px; }
.legal__foot { margin-top: var(--sp-5); color: var(--text-soft); font-size: 13px; }

/* 注册页的同意条款：复选框 + 说明文字。文字用弱化色、链接用强调色，
   整行不抢"注册"按钮的注意力（这是一条必须看的说明，不是卖点） */
.agree {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 0 var(--sp-2);
  color: var(--text-muted); font-size: 12.5px; line-height: 1.7;
}
.agree input { width: auto; flex: 0 0 auto; margin-top: 3px; }
.agree a { color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  html { scroll-behavior: auto; }
  /* 跨页转场也必须尊重"减少动态效果"：直接切换，不做淡入（伪元素不被 * 命中，要单独写） */
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation-duration: .001ms !important; }
}

/* ---------------- 意见反馈：工单进度（v2.41） ----------------
   列表项 + 时间线气泡。只用到既有令牌（--surface-2 / --border / --accent-ring 等），
   配色与全站一致；气泡用左侧竖线区分"谁说的"，不引入新色。 */
.fb-item { padding: var(--sp-3); }
.fb-item .fb-no { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .3px; }
.fb-thread { margin-top: var(--sp-2); display: flex; flex-direction: column; gap: var(--sp-2); }
.fb-msg {
  border-left: 3px solid var(--border-strong); padding: 8px 10px;
  border-radius: 0 var(--radius) var(--radius) 0; background: var(--surface-2);
}
.fb-msg--me { border-left-color: var(--accent-ring); }
.fb-msg--staff { border-left-color: var(--accent); }
.fb-msg--sys { border-left-style: dashed; background: transparent; opacity: .85; }
.fb-msg--sys .small { font-style: normal; }
.fb-att { max-width: 180px; max-height: 140px; border-radius: var(--radius); border: 1px solid var(--border); display: block; }
