/* ===============================================================
   模块 02 · 摄影集（横向卡片 + 滚轮缩放）
   所有选择器挂在 .ph 根节点下，不污染其他模块
   =============================================================== */

/* Inter 自托管：一个可变字体文件覆盖 100–900 全部字重，只含拉丁子集。
   中文不在这个文件里，靠字体栈后面的系统中文字体接住。 */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("assets/fonts/inter-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("assets/fonts/inter-italic.woff2") format("woff2");
}

.ph {
  /* 版式常量：设计稿 1200×720，卡片间距 40 */
  --fw: 1200px;
  --fh: 720px;
  --gap: 40px;

  /* 颜色 */
  --bg: #ffffff;
  --sheet: #ffffff;
  --line: rgba(23, 23, 23, 0.20);      /* 卡片细边框 */
  --line-w: 2px;
  --line-hover: rgba(23, 23, 23, 0.45);
  --ink: #171717;
  --ink-2: #6f6f6f;
  --ink-3: #a3a3a3;
  --dot: #c3c3c3;
  --accent: #1b3bff;

  /* 字体：与其余四个模块同一串，Inter 自托管，中文走系统 */
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", "Source Han Sans SC", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  position: relative;
  min-height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
}

.ph *,
.ph *::before,
.ph *::after { box-sizing: border-box; }

html { overflow-x: hidden; }
body {
  margin: 0;
  background: #ffffff;
  overscroll-behavior-y: none;
}

/* ---------- 面包屑（全局统一组件，规格与 03/04/05 完全一致） ---------- */

.page-trail {
  position: fixed;
  top: 40px;
  left: 40px;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5em;
  margin: 0;
  font-size: 14.5px;
  line-height: 1.4;
  letter-spacing: 0.01em;
  color: var(--ink-3);
}

.page-trail__item {
  color: inherit;
  text-decoration: none;
  transition: color 0.2s ease;
}

a.page-trail__item:hover {
  color: var(--ink);
}

.page-trail__sep {
  color: var(--line);
}

.page-trail__item--current {
  color: var(--ink-2);
}

/* 移动端收边：四个模块统一在 680px 换到 (20,20)，保证绝对坐标一致 */
@media (max-width: 680px) {
  .page-trail {
    top: 20px;
    left: 20px;
  }
}

/* ---------- 舞台与轨道 ---------- */

.ph-stage {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  touch-action: pan-y;          /* 竖划交给页面，横划由脚本接管 */
}

.ph-track {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--fw);
  height: var(--fh);
  margin: calc(var(--fh) / -2) 0 0 calc(var(--fw) / -2);
  transform-origin: 50% 50%;
  will-change: transform;
}

/* ---------- 卡片 ---------- */

.ph-card {
  position: absolute;
  top: 0;
  left: calc(var(--i) * (var(--fw) + var(--gap)));
  width: var(--fw);
  height: var(--fh);
  display: block;
  -webkit-user-select: none;
  user-select: none;
  transform: scale(1);
  transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1),
              box-shadow 0.55s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}

/* 带链接的卡片（<a>）：外观不变，只还原锚点默认样式 */
a.ph-card {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

/* 悬停效果统一写在文件末尾（用 @media (hover:hover) 包起来，
   避免手机点一下就卡在放大状态） */

/* 卡片上沿的说明文字：反向缩放，屏幕上永远是 14px / 上移 28px */
.ph-card__label {
  position: absolute;
  left: 0;
  top: calc(-28px * var(--inv, 1));
  transform: scale(var(--inv, 1));
  transform-origin: 0 0;
  font-family: var(--font-mono);
  font-size: 14.5px;
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--ink-2);
  white-space: nowrap;
  transition: color 0.2s ease;
}
.ph-card__label b {
  font-weight: 400;
  color: var(--ink-3);
}

/* 内容窗口：真正裁切的那一层（label 在它外面，所以不会被裁） */
.ph-card__body {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--sheet);
  border: var(--line-w) solid var(--line);
  transition: filter 0.55s cubic-bezier(0.16, 1, 0.3, 1),
              border-color 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---------- 照片位（纯色占位，后期换成真图） ---------- */

.ph-media {
  position: absolute;
  left: -12%;
  top: 0;
  width: 124%;
  height: 100%;
  background: var(--tone, #c9c9c9);
  will-change: transform;
}
.ph-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.5s ease;
}
.ph-media img.is-loaded { opacity: 1; }

/* 占位层：大序号 + 文件名，真图到位后自动藏在图下面 */
.ph-ph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
}
.ph-ph__num {
  font-family: var(--font-sans);
  font-size: 300px;
  line-height: 0.8;
  font-weight: 200;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.05em;
  color: var(--ph-ink, rgba(255, 255, 255, 0.5));
  transition: opacity 0.4s ease;
}
.ph-ph__file {
  position: absolute;
  right: 32px;
  bottom: 28px;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--ph-ink, rgba(255, 255, 255, 0.5));
  opacity: 0.75;
}
.ph-media.has-image .ph-ph { opacity: 0; }

/* ---------- 首帧：自述卡 ---------- */

.ph-intro {
  position: relative;
  width: 100%;
  height: 100%;
  padding: 64px;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: var(--sheet);
}
/* 首帧底图：铺满整卡。宽 124% + left -12% 是为了给左右各 144px 的视差留余量，
   和照片卡同一套算式，漂到极限也不会露出白边 */
.ph-intro__media {
  position: absolute;
  left: -12%;
  top: 0;
  width: 124%;
  height: 100%;
  z-index: 0;
  will-change: transform;
}
.ph-intro__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.8s ease;
}
.ph-intro__media img.is-loaded { opacity: 1; }

.ph-intro__text {
  position: relative;
  z-index: 1;
  margin: 0;
  font-size: 200px;
  /* 中文字体只有「常规 / 粗体」两档，写 600~900 都是同一个粗体，
     想要比粗体轻就只能落回常规（500 及以下）。2026-10-29 用户嫌粗，退到常规。 */
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -0.03em;
  color: #fff;
}
/* 底图是有细节的油画，纯黑大字直接压上去，靠字重和字号拉开层次就够，
   不再给白雾 —— 试过一层白色椭圆，在画面中间会形成一块脏掉的雾。（2026-10-29）
   注意不能写 text-shadow：.ph-intro__line 为了进场动画有 overflow:hidden，
   光晕会被那一行裁断。 */
.ph-intro__line {
  display: block;
  overflow: hidden;
  padding-right: 0.08em;      /* 避免斜体/字身被裁 */
}
.ph-intro__line[data-offset] { margin-left: 1.15em; }
.ph-intro__line span {
  display: block;
  transform: translateY(105%);
}
.ph.is-ready .ph-intro__line span {
  transform: translateY(0);
  transition: transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--d, 0) * 90ms + 120ms);
}

/* ---------- 顶部圆球进度 ---------- */

.ph-dots {
  position: fixed;
  left: 50%;
  top: 64px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 15px;
  z-index: 4;
}
.ph-dot {
  position: relative;
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--dot);
  cursor: pointer;
  transition: background 0.25s ease, border-radius 0.25s ease,
              transform 0.25s ease;
}
.ph-dot::after {                 /* 放大点击热区 */
  content: "";
  position: absolute;
  inset: -9px;
}
.ph-dot:hover { background: var(--ink-2); }
.ph-dot[aria-current="true"] {
  background: var(--accent);
  border-radius: 1px;
  transform: scale(1.55);
}
.ph-dot:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 5px;
}

/* ---------- 中心准星 ---------- */

.ph-cross {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  mix-blend-mode: difference;
  pointer-events: none;
  z-index: 3;
}

/* ---------- 首次提示 ---------- */

.ph-hint {
  position: fixed;
  left: 50%;
  bottom: 36px;
  transform: translateX(-50%);
  margin: 0;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  white-space: nowrap;
  z-index: 4;
  transition: opacity 0.5s ease;
}
.ph-hint__touch { display: none; }

@media (hover: none) and (pointer: coarse) {
  .ph-hint__desk { display: none; }
  .ph-hint__touch { display: inline; }
}
.ph-hint.is-gone { opacity: 0; }

/* ---------- 撑高度 ---------- */

.ph-ghost {
  width: 1px;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}

/* ---------- 进场 ---------- */

.ph-card--intro { --inv: 1; }
.ph-card:not(.ph-card--intro) { opacity: 0; }
.ph.is-ready .ph-card:not(.ph-card--intro) {
  opacity: 1;
  transition: opacity 0.4s ease-in-out;
  transition-delay: calc(var(--d, 0) * 60ms + 260ms);
}

/* ---------- 窄屏 ---------- */

@media (max-width: 700px) {
  .ph-dots { top: 40px; gap: 13px; }
  .ph-dot { width: 6px; height: 6px; }
  .ph-hint { bottom: 28px; }
  .ph-intro { padding: 56px; }
  .ph-ph__num { font-size: 210px; }
}

@media (max-width: 480px) {
  .ph-intro { padding: 48px; }
}

/* ---------- 悬停：微微放大 + 四周亮起 ---------- */

@media (hover: hover) and (pointer: fine) {
  .ph-card:hover {
    z-index: 2;
    transform: scale(1.038);
    box-shadow:
      0 0 0 1px rgba(23, 23, 23, 0.08),
      0 0 58px 5px rgba(27, 59, 255, 0.20),
      0 30px 66px -24px rgba(0, 0, 0, 0.26);
  }
  .ph-card:hover .ph-card__label { color: var(--ink); }
  .ph-card:hover .ph-card__body {
    filter: brightness(1.045) saturate(1.03);
    border-color: var(--line-hover);
  }
}

/* ---------- 无障碍：减少动效 ---------- */

@media (prefers-reduced-motion: reduce) {
  .ph-intro__line span { transform: none; transition: none; }
  .ph-card:not(.ph-card--intro) { opacity: 1; transition: none; }
  .ph-dot, .ph-card__label, .ph-card, .ph-card__body { transition: none; }
  .ph-card:hover { transform: none; }
  .ph-hint { display: none; }
}

/* ---------- 深色模式（2026-10-28） ----------
   这页纸色是纯白，反推就取中性黑，不掺暖色 ——
   摄影集的照片本身颜色很重，背景再发暖会打架。 */
[data-theme="dark"] .ph {
  --bg: #0e0e0e;
  --sheet: #171717;
  --line: rgba(255, 255, 255, 0.20);
  --line-hover: rgba(255, 255, 255, 0.45);
  --ink: #f2f2f2;
  --ink-2: #9d9d9d;
  --ink-3: #6d6d6d;
  --dot: #4a4a4a;
  --accent: #5a74ff;
  color-scheme: dark;
}

html[data-theme="dark"] body { background: #0e0e0e; }

/* 悬停那圈亮边原本按浅底调的白线，深色下要换成亮线 */
[data-theme="dark"] .ph-card:hover {
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.10),
    0 0 58px 5px rgba(90, 116, 255, 0.22),
    0 30px 66px -24px rgba(0, 0, 0, 0.7);
}

/* 切换时淡一下，别硬切 */
.ph,
body { transition: background-color 0.4s ease, color 0.4s ease; }
