/* =========================================================
   ZHENGYANG LI — portfolio  (dark minimalist, self-contained)
   No external fonts / CDNs — everything loads locally.
   ========================================================= */

:root {
  /* Dark gallery recolored into the main site's NIGHT palette family
     (zhengyangli.com sceneThemes night gradient bottoms out at #0a0a1a),
     so the gallery reads as "the dark room of the same house" instead of
     an unrelated pure-black site. */
  --bg: #0a0a1a;
  --bg-elev: #14142b;
  --text: #f2f2f2;
  --muted: #9a9a9a;
  --line: rgba(255, 255, 255, 0.10);
  --maxw: 1280px;
  --gap: 14px;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; }

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px clamp(18px, 5vw, 48px);
  background: rgba(10, 10, 26, 0.72);
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line);
}
.brand {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  white-space: nowrap;
  /* 拇指可点：扩大命中区但不动视觉位置 */
  padding: 13px 13px 13px 0;
  margin: -13px -13px -13px 0;
}
.nav { display: flex; gap: 28px; }
.nav a {
  font-size: 13px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  transition: color 0.25s var(--ease);
  /* 拇指可点：扩大命中区但不动视觉位置（gap 28px 容得下左右各 10px） */
  padding: 14px 10px;
  margin: -14px -10px;
}
.nav a:hover, .nav a.active { color: var(--text); }
/* the way back to the main site — domain stays lowercase, like the SPA's
   own wordmark; narrow screens swap in the short label */
.nav .nav-back { text-transform: none; letter-spacing: 0.08em; white-space: nowrap; }
.nav .nav-back .nav-back-short { display: none; }
@media (max-width: 560px) {
  .nav .nav-back .nav-back-long { display: none; }
  .nav .nav-back .nav-back-short { display: inline; }
}

/* ---------- Hero ---------- */
.hero {
  min-height: 76vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 64px 24px 40px;
}
.hero h1 {
  margin: 0;
  font-weight: 600;
  font-size: clamp(2rem, 6.2vw, 4.6rem);
  letter-spacing: 0.01em;
  line-height: 1.08;
}
.hero p {
  margin: 22px 0 0;
  color: var(--muted);
  font-size: clamp(0.95rem, 2.2vw, 1.15rem);
  letter-spacing: 0.04em;
}
.scroll-cue {
  margin-top: 46px;
  color: var(--muted);
  font-size: 26px;
  line-height: 1;
  animation: bob 1.8s var(--ease) infinite;
}
@keyframes bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(8px); } }

/* ---------- Scene-linked hero (the doorway from the main site) ----------
   The scene-* class on <html> is set by a tiny inline head script using the
   SAME owner-timezone time bands as zhengyangli.com (it reads the main
   site's localStorage — same origin), so the doorway sky matches the page
   the visitor just left. Each gradient reuses the main palette's upper
   stops and falls into the gallery's dark bg, so the scroll seam is clean.
   Without a scene class (script blocked) the hero stays the dark bg. */
html.scene-night .hero { background: linear-gradient(180deg, #08081a 0%, #0d0d25 30%, #121230 60%, #0a0a1a 100%); }
html.scene-dawn  .hero { background: linear-gradient(180deg, #3f4d71 0%, #6d6f9e 30%, #c48a82 58%, #0a0a1a 100%); }
html.scene-day   .hero { background: linear-gradient(180deg, #b5daf9 0%, #d7ecfb 36%, #eef5f9 64%, #8fa3bd 82%, #0a0a1a 100%); }
html.scene-dusk  .hero { background: linear-gradient(180deg, #263456 0%, #5c527c 30%, #b77574 58%, #0a0a1a 100%); }
/* hero copy adopts the matching scene ink (the day sky is light) */
html.scene-day  .hero h1 { color: #38506a; }
html.scene-day  .hero p { color: rgba(58, 78, 100, 0.92); }
/* the cue sits at the gradient's dark end, so it stays light even by day */
html.scene-day  .hero .scroll-cue { color: rgba(255, 255, 255, 0.6); }
html.scene-dawn .hero h1 { color: #fff3e8; }
html.scene-dawn .hero p, html.scene-dawn .hero .scroll-cue { color: rgba(255, 236, 216, 0.9); }
html.scene-dusk .hero h1 { color: #f3dfd9; }
html.scene-dusk .hero p, html.scene-dusk .hero .scroll-cue { color: rgba(238, 216, 214, 0.82); }

/* ---------- Work grid ---------- */
.section-wrap { max-width: var(--maxw); margin: 0 auto; padding: 40px clamp(18px, 5vw, 48px) 72px; }
.section-title {
  font-size: 13px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 26px;
  text-align: center;
}

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gap);
}
.card {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--bg-elev);
}
.card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}
.card .overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 16px;
  text-align: center;
  background: linear-gradient(180deg, rgba(0,0,0,0.15), rgba(0,0,0,0.55));
  opacity: 0;
  transition: opacity 0.4s var(--ease);
}
.card .overlay .t {
  font-size: clamp(1.05rem, 2vw, 1.4rem);
  font-weight: 600;
  letter-spacing: 0.02em;
}
.card .overlay .y {
  font-size: 12px;
  letter-spacing: 0.2em;
  color: rgba(255,255,255,0.78);
}
.card:hover img { transform: scale(1.06); }
.card:hover .overlay { opacity: 1; }
/* keyboard parity: focused cards reveal the same title overlay as hover */
.card:focus-visible img { transform: scale(1.06); }
.card:focus-visible .overlay { opacity: 1; }

/* keyboard access to the gallery + lightbox controls */
.gallery .g-item:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; }
.lb button:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }

/* "new" badges — quiet pills in the site's label voice; rendered only for
   photos inside the display window (app.js), so they retire themselves */
.gallery .g-item .new-tag,
.card .card-new {
  position: absolute;
  z-index: 2;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  background: rgba(10, 10, 26, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 999px;
  padding: 3px 8px;
  pointer-events: none;
}
.gallery .g-item .new-tag { top: 10px; left: 10px; }
.card .card-new { top: 10px; right: 10px; }

/* ---------- Project (gallery) page ---------- */
.project-head {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(40px, 8vw, 90px) clamp(18px, 5vw, 48px) 30px;
  text-align: center;
}
.project-head h1 {
  margin: 0;
  font-weight: 600;
  font-size: clamp(1.7rem, 5vw, 3rem);
  letter-spacing: 0.02em;
}
.project-head .y {
  margin-top: 12px;
  color: var(--muted);
  font-size: 13px;
  letter-spacing: 0.22em;
}
.back-link {
  display: inline-block;
  margin-top: 26px;
  color: var(--muted);
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition: color 0.25s var(--ease);
}
.back-link:hover { color: var(--text); }

.gallery {
  /* 中线挂画（equal visual weight）：每张图宽 = 基准 × √宽高比，数学上保证
     横图竖图面积相等（横图宽而矮、竖图窄而高）。行内垂直居中对齐中线、
     行整体水平居中。基准随视口缩放，手机和桌面的"重量"观感一致。 */
  --g-unit: clamp(200px, 26vw, 330px);
  max-width: 1280px;
  margin: 0 auto;
  padding: 20px clamp(14px, 4vw, 24px) 60px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  justify-content: center;
}
.gallery .g-item {
  position: relative;
  margin: 0;
  padding: 0;
  overflow: hidden;
  background: var(--bg-elev);
  cursor: zoom-in;
  flex: none;
  width: calc(var(--g-unit) * var(--sqar, 1.22));
  max-width: 100%;
}
.gallery .g-item img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.5s var(--ease);
}
.gallery .g-item img.loaded { opacity: 1; }
/* last-row spacer: absorbs leftover width so the final row keeps its natural
   size instead of stretching edge-to-edge (mirrors the original site) */
/* 旧 justified 布局的末行占位符——居中布局下已无用，留规则只为兼容旧缓存页面 */
.gallery .g-spacer { display: none; }

/* 拍摄月份分段标题——整行换行（flex-basis 100%），editorial mono 小字。
   首个分段不要顶部大留白（紧贴画廊起始）。 */
.gallery .g-divider {
  flex: 1 1 100%;
  margin: 26px 0 4px;
  font-size: 12px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: left;
}
.gallery .g-divider:first-child { margin-top: 0; }

/* 日期时间线 → 序号组 的交界细线（整行，无文字） */
.gallery .g-rule {
  flex: 1 1 100%;
  border: 0;
  border-top: 1px solid var(--line);
  margin: 30px 0 14px;
}

/* 窄屏：短边归一布局。所有图的短边 = 3:2 横图铺满时的短边（2/3 屏宽）：
   宽 = max(宽高比, 1) × 66.667% 容器宽。
   3:2 横图 → 1.5×2/3 = 100% 铺满；4:3 横图 → 8/9 宽（长边相对缩短）；
   竖图 → 2/3 宽，高随 aspect-ratio（4:3 竖图高 8/9，与 4:3 横图长边一致）。
   超宽全景被 max-width:100% 截顶。 */
@media (max-width: 560px) {
  .gallery { gap: 8px; }
  .gallery .g-item { width: calc(var(--armax, 1.5) * 66.667%); }
}

/* 比例标签 — 右上角，比 NEW 更安静的一档 */
.gallery .g-item .ratio-tag {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  font-size: 9.5px;
  letter-spacing: 0.1em;
  color: rgba(242, 242, 242, 0.78);
  background: rgba(10, 10, 26, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  padding: 2px 7px;
  pointer-events: none;
}
.empty-note {
  flex: 1 1 100%;
  text-align: center;
  color: var(--muted);
  padding: 40px 20px;
  line-height: 1.8;
}

/* ---------- "You may also like" ---------- */
.related {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 28px clamp(18px, 5vw, 48px) 80px;
  border-top: 1px solid var(--line);
}
.related[hidden] { display: none; }
.related-title {
  text-align: center;
  font-size: 13px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 40px 0 28px;
}

/* ---------- Lightbox ---------- */
.lb {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(8, 8, 20, 0.96);
  -webkit-user-select: none;
  user-select: none;
}
.lb.open { display: flex; }
.lb img {
  max-width: 92vw;
  max-height: 88vh;
  width: auto;
  height: auto;
  object-fit: contain;
  box-shadow: 0 10px 60px rgba(0,0,0,0.6);
}
.lb button {
  position: absolute;
  background: none;
  border: none;
  color: rgba(255,255,255,0.8);
  cursor: pointer;
  transition: color 0.2s var(--ease), transform 0.2s var(--ease);
}
.lb button:hover { color: #fff; }
.lb .lb-close { top: 18px; right: 22px; font-size: 34px; line-height: 1; }
.lb .lb-prev, .lb .lb-next {
  top: 50%;
  transform: translateY(-50%);
  width: 54px;
  height: 54px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  line-height: 1;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.10);
  color: rgba(255, 255, 255, 0.92);
}
.lb .lb-prev { left: 20px; }
.lb .lb-next { right: 20px; }
.lb .lb-prev:hover, .lb .lb-next:hover { background: rgba(255, 255, 255, 0.20); color: #fff; }
.lb .lb-prev:hover { transform: translateY(-50%) translateX(-2px); }
.lb .lb-next:hover { transform: translateY(-50%) translateX(2px); }
/* loading spinner — previews can take seconds on a slow cross-border link;
   without feedback the viewer assumes the lightbox is broken. The 0.25s
   transition delay keeps cached/instant loads from flashing it. Under
   prefers-reduced-motion the ring still appears (opacity is a transition,
   which degrades to instant), it just doesn't spin. */
.lb::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border: 2px solid rgba(255, 255, 255, 0.18);
  border-top-color: rgba(255, 255, 255, 0.85);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
}
.lb.lb-loading::after {
  opacity: 1;
  transition: opacity 0.2s ease 0.25s;
  animation: lb-spin 0.9s linear infinite;
}
@keyframes lb-spin { to { transform: rotate(360deg); } }
.lb .lb-count {
  position: absolute;
  bottom: 22px;
  left: 0; right: 0;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  letter-spacing: 0.16em;
}

/* ---------- Footer ---------- */
.site-footer {
  border-top: 1px solid var(--line);
  padding: 30px 20px;
  text-align: center;
  color: var(--muted);
  font-size: 12px;
  letter-spacing: 0.14em;
}

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .grid { grid-template-columns: 1fr; }
  .card .overlay { opacity: 1; background: linear-gradient(180deg, rgba(0,0,0,0), rgba(0,0,0,0.6)); justify-content: flex-end; }
  .nav { gap: 18px; }
  .lb .lb-prev, .lb .lb-next { font-size: 36px; padding: 8px 12px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; scroll-behavior: auto; }
}
