:root {
  --bg: #000000;
  --fg: #f0f0f0;
  --muted: #9a9a96;
  --line: #2a2a2a;
  --accent: #b08d57;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* 确保 hidden 属性永远生效，不被下面的 display:flex 等覆盖 */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

/* 前台全站禁止选中文字：反复点 LuckZhang 也不会把字选蓝。
   只管这个文件（前台），后台用的是 admin.css，文字照常可选（要复制 GPS）。 */
html, body {
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
}
/* 例外：页脚邮箱要能划选复制（选择器比上面更具体才压得住） */
.footer .email-link {
  -webkit-user-select: text;
  -moz-user-select: text;
  user-select: text;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  background: var(--bg);
  color: var(--fg);
  -webkit-font-smoothing: antialiased;
  /* 竖向弹性布局：配合页脚的 margin-top:auto，作品不满一屏时页脚也贴在屏幕最下面 */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* ---------- 顶部导航 ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 40px;
  background: rgba(0, 0, 0, 0.85);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}

.brand { display: flex; flex-direction: column; gap: 2px; }
.brand h1 {
  font-family: "Segoe UI", "Helvetica Neue", Arial, "PingFang SC", "Microsoft YaHei", sans-serif;
  font-weight: 700;
  font-size: 34px;
  letter-spacing: 2px;
}
.brand .subtitle { font-size: 12px; color: var(--muted); letter-spacing: 2px; }

.nav { display: flex; gap: 8px; }
.nav-btn {
  appearance: none;
  border: none;
  background: transparent;
  font: inherit;
  font-size: 15px;
  color: var(--muted);
  padding: 8px 18px;
  border-radius: 999px;
  cursor: pointer;
  transition: color .2s, background .2s;
}
.nav-btn:hover { color: var(--fg); }
.nav-btn.active {
  color: #000;
  background: #fff;
}

/* ---------- 分类导航（横向，与后台目录分类一致） ---------- */
.filter-tree {
  position: relative;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 40px 2px;
}
.ft-level {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.ft-chip {
  appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  font: inherit;
  font-size: 13px;
  color: var(--muted);
  padding: 5px 14px;
  border-radius: 999px;
  cursor: pointer;
  transition: all .15s;
}
.ft-chip:hover { border-color: var(--accent); color: var(--fg); }
.ft-chip.active {
  border-color: #fff;
  background: #fff;
  color: #000;
}

/* ---------- 画廊（两端对齐行）----------
   JS 按原始宽高比排行：每行内所有图等高、整行填满宽度，从左往右读；
   格子比例 = 图片比例，所以 cover 裁不掉画面 */
.gallery {
  position: relative;
  padding: 24px 40px 8px;
  flex: none;   /* 高度由排版脚本写死，别让弹性布局压缩它 */
}
.photo {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  border-radius: 6px;
  background: #1a1a1a;
  cursor: pointer;
}
.photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity .5s ease;   /* 只淡入，不做任何缩放 */
  opacity: 0;
  /* 点开大图那一瞬间的蓝色选中高亮：浏览器把这张 img 当成可选中的内容 / 可拖出的对象。
     只关图和图上的文字选区，不碰 body，页面其它文字照常可选中复制；
     右键菜单（保存图像/复制图像）不受这两个属性影响，不做任何 contextmenu 拦截 */
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}
.photo img.loaded { opacity: 1; }

/* ---------- 悬停聚光：压暗照片以外的区域，选中照片保持原亮度（不提亮） ---------- */
.spotlight {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, 0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity .6s ease;
}
body:has(.photo:hover) .spotlight { opacity: 1; }
.photo:hover { z-index: 41; }

.photo figcaption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 28px 14px 12px;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.55));
  color: #fff;
  font-size: 13px;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .25s, transform .25s;
  pointer-events: none;
}
.photo:hover figcaption { opacity: 1; transform: translateY(0); }
.photo figcaption .meta { display: block; font-size: 11px; opacity: .8; margin-top: 2px; }
.photo figcaption .exif { display: block; font-size: 11px; opacity: .62; margin-top: 2px; }

/* ---------- 空提示 / 加载哨兵 ---------- */
.empty-tip { text-align: center; color: var(--muted); padding: 80px 0; }
.sentinel { height: 1px; }

/* ---------- 页脚 ---------- */
.footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 40px;
  margin-top: auto;   /* 始终贴底：不跟着作品数量往上跑 */
  color: var(--muted);
  font-size: 13px;
}
.admin-link, .email-link {
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color .2s, border-color .2s;
}
.admin-link:hover, .email-link:hover { color: var(--fg); border-color: var(--fg); }

/* ---------- 开场大字 ---------- */
.intro {
  position: fixed;
  inset: 0;
  width: 100vw; /* 不跟着滚动条出现而变窄，否则居中的 logo 会横移一下 */
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
  cursor: pointer;
  transition: opacity 1s ease; /* 溶解这层黑幕 = 内容淡入，只有一个合成层在动 */
  will-change: opacity;
}
/* 淡出这 0.6 秒里不再吃点击，底下照片可以直接点 */
body.intro-out .intro { opacity: 0; pointer-events: none; }
.intro-title {
  font-family: "Segoe UI", "Helvetica Neue", Arial, "PingFang SC", "Microsoft YaHei", sans-serif;
  font-weight: 700;
  font-size: clamp(64px, 16vw, 200px);
  color: #fff;
  will-change: transform, opacity;
}
.intro-word {
  display: inline-block;
  letter-spacing: .05em;   /* 静态字距：以前放在关键帧里逐帧改，会导致文字每帧重排、看着抖 */
  animation: introIn 2s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes introIn {
  from { opacity: 0; transform: scale(1.35); }
  to   { opacity: 1; transform: scale(1); }
}

/* 开场期间内容只是藏在黑幕后面：不给它做 opacity 动画（整幅多列画廊逐帧重绘很贵），
   黑幕溶解就等于内容淡入 —— 底下本来就是纯黑底，视觉一致 */
body.intro-active .site-header,
body.intro-active .filter-tree,
body.intro-active .gallery,
body.intro-active .empty-tip,
body.intro-active .footer {
  visibility: hidden;
}

/* logo 退场：放大 + 渐隐；黑幕溶解紧随其后（解锁重排已提前一帧做完） */
.intro-title { transition: opacity .9s ease, transform .9s cubic-bezier(0.22, 1, 0.36, 1); }
body.intro-out .intro-title { opacity: 0; transform: scale(2.2); }
/* 可点击提示：只加辉光，transform 被入场动画占着，别去抢 */
.intro-word { transition: text-shadow .18s ease; }
.intro:hover .intro-word { text-shadow: 0 0 26px rgba(255, 255, 255, 0.35); }

@media (prefers-reduced-motion: reduce) {
  .intro-word { animation: none; }
  .intro-title { transition: none; }
  .intro { transition: none; }
  .lb-img .lb-skeleton { animation: none; } /* 骨架不流光，留静态灰块 */
}

/* ---------- 灯箱 ---------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(10, 10, 10, 0.94);
  animation: fadeIn .24s linear;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

.lb-figure {
  max-width: 88vw;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  /* 进场只淡入：全站不对图片做缩放 */
  animation: lbFigureIn .24s linear;
}
/* 进场 / 退场：只动透明度（图片一律不做放大） */
@keyframes lbFigureIn {
  from { opacity: .85; }
  to { opacity: 1; }
}
@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }
@keyframes lbFigureOut {
  from { opacity: 1; }
  to { opacity: .85; }
}
.lightbox.closing { animation: fadeOut .24s linear both; }
.lightbox.closing .lb-figure { animation: lbFigureOut .24s linear both; }

.lb-figure figcaption { color: #ddd; font-size: 14px; text-align: center; }
.lb-figure figcaption .meta { display: block; font-size: 12px; color: #999; margin-top: 4px; }
.lb-figure figcaption .exif { display: block; font-size: 12px; color: #8a8a8a; margin-top: 4px; }

.lb-img {
  position: relative;
  flex: none;
  width: 88vw;
  height: 78vh;
  /* 舞台尺寸跟着交叉淡入一起渐变，否则切到不同画幅时旧图会被瞬间重新缩放 → 抽动 */
  transition: width .45s ease, height .45s ease;
}
/* 双图层交叉淡入：两张都绝对定位叠在一起，只动 opacity；旧图在新图就绪前一直显示。
   选择器写成 .lb-img .lb-layer（两级）以保证优先级，别改回单类名
   关键：元素盒子必须等于图片本身（按自身比例居中，靠 max-* 受舞台约束），
   圆角才永远落在图的真实四角上；铺满舞台会让圆角落在留白区 → 看到直角 */
.lb-img .lb-layer {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  border-radius: 16px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity .45s ease;
  will-change: opacity;
}
.lb-img .lb-layer.active { opacity: 1; }
.lb-img .lb-layer { z-index: 1; }
/* 骨架占位：新图没下载完之前占住这一块（尺寸就是舞台＝这张图自己的比例），
   图淡进来的同时它淡出 → 不会出现纯黑空档，也不会露出上一张 */
.lb-img .lb-skeleton {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: 16px;
  background: linear-gradient(100deg, #1b1b1d 32%, #2b2b2f 50%, #1b1b1d 68%) 0 0 / 220% 100%;
  animation: lbSkel 1.2s linear infinite;
  opacity: 1;
  transition: opacity .45s ease;
}
.lb-img .lb-skeleton.off { opacity: 0; animation-play-state: paused; }
@keyframes lbSkel {
  from { background-position: 120% 0; }
  to { background-position: -120% 0; }
}
/* 打开灯箱的那一个瞬间：尺寸与图层一律瞬移到位，不留半动画状态
   （否则上一张残影会带着新舞台的直角出现） */
.lb-img.no-anim,
.lb-img.no-anim .lb-layer,
.lb-img.no-anim .lb-skeleton { transition: none !important; }
.lb-loading {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  /* 行高写死在这里：以前父级 .lb-img 的 line-height: 0 会继承进来，把内容盒压成 0 高，
     字上下各溢出半个行高，正好吃掉内边距 → 看着像黑底太小 */
  line-height: 1.5;
  padding: 7px 14px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  font-size: 13px;
  letter-spacing: .04em;
}
/* 旧版单层淡入遗留的 .lb-swap / .fading / .no-tr 规则已删除（JS 不再使用这些类名） */
.lb-figure figcaption { transition: opacity .2s linear; }
.lb-figure figcaption.hide { opacity: 0; }
.lb-close {
  position: absolute;
  top: 16px;
  right: 20px;
  font-size: 28px;
  line-height: 1;
  color: #fff;
  background: none;
  border: none;
  cursor: pointer;
  opacity: .7;
  transition: opacity .2s;
}
.lb-close:hover { opacity: 1; }

/* 左右切换按钮：固定在图片外侧（不随图片大小变化），高亮圆钮 */
.lb-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 46px;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 30px;
  line-height: 1;
  color: #fff;
  background: rgba(0, 0, 0, 0.42);
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 50%;
  cursor: pointer;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5), 0 0 0 3px rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(3px);
  text-shadow: 0 0 8px rgba(255, 255, 255, 0.55);
  transition: background .2s, border-color .2s, transform .15s;
}
.lb-nav:hover {
  background: rgba(0, 0, 0, 0.72);
  border-color: rgba(255, 255, 255, 0.9);
  transform: translateY(-50%) scale(1.06);
}
.lb-prev { left: 48px; }
.lb-next { right: 48px; }

@media (max-width: 640px) {
  .site-header { padding: 16px 20px; }
  .gallery { padding: 20px 20px 4px; }
  .filter-tree { padding: 12px 20px 0; }
  .footer { padding: 32px 20px; }
  .lb-nav { width: 38px; height: 38px; font-size: 24px; }
  .lb-prev { left: 8px; }
  .lb-next { right: 8px; }
  .lb-close { font-size: 22px; top: 12px; right: 14px; }
}

/* ===== 全站自定义鼠标指针（小女仆）===== */
html, body, body * {
  cursor: url("../ui/cursor.png") 2 2, auto !important;
}

/* ===== 左上角名字的彩蛋贴纸：从上方砸下来，点任意处收掉 ===== */
.sticker {
  position: fixed;
  inset: 0;
  z-index: 90;              /* 顶栏 60 之上、照片灯箱 100 之下 */
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;  /* 不压暗页面，只要一整层接住「点任意处」 */
}
.sticker img {
  display: block;
  /* 手机上就是 70% 屏宽；桌面封顶到原图 782px，再放大会糊 */
  width: min(70vw, 72vh, 782px);
  height: auto;
  border-radius: 12px;
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.55);
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
  transform-origin: 50% 50%;
  will-change: transform;
  animation: none;
}
/* 4 种入场，JS 每次点击随机挂一种（平移的三种只滑进来、不回弹） */
.sticker img.a-drop        { animation: stickerDrop .72s both; }
.sticker img.a-from-bottom { animation: stickerFromBottom .42s cubic-bezier(.2, .7, .3, 1) both; }
.sticker img.a-from-left   { animation: stickerFromLeft .42s cubic-bezier(.2, .7, .3, 1) both; }
.sticker img.a-from-right  { animation: stickerFromRight .42s cubic-bezier(.2, .7, .3, 1) both; }
/* 逐段配 timing：下落加速、撞地回弹逐次衰减 */
@keyframes stickerDrop {
  0%   { transform: translateY(-125vh) rotate(-7deg); animation-timing-function: cubic-bezier(.5, 0, .9, .4); }
  52%  { transform: translateY(0) rotate(0deg);       animation-timing-function: cubic-bezier(.1, .7, .3, 1); }
  68%  { transform: translateY(-13%) rotate(2.5deg);  animation-timing-function: cubic-bezier(.5, 0, .9, .4); }
  82%  { transform: translateY(0) rotate(0deg);       animation-timing-function: cubic-bezier(.1, .7, .3, 1); }
  91%  { transform: translateY(-4.5%) rotate(-1deg);  animation-timing-function: cubic-bezier(.5, 0, .9, .4); }
  100% { transform: translateY(0) rotate(0deg); }
}
@keyframes stickerFromBottom {
  from { transform: translateY(125vh); }
  to   { transform: translateY(0); }
}
@keyframes stickerFromLeft {   /* 从左往右平移 */
  from { transform: translateX(-125vw); }
  to   { transform: translateX(0); }
}
@keyframes stickerFromRight {  /* 从右往左平移 */
  from { transform: translateX(125vw); }
  to   { transform: translateX(0); }
}
@keyframes stickerFade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  /* 四种全退化成淡入（选择器要带上类名才压得过上面那四条的优先级） */
  .sticker img,
  .sticker img.a-drop,
  .sticker img.a-from-bottom,
  .sticker img.a-from-left,
  .sticker img.a-from-right { animation: stickerFade .2s linear both; }
}
