/* ============================================================
   孙茜 · 作品集 —— 网页版样式
   配色取自设计稿：主色 #723FFF，深底 #131313，纸白 #FFFFFF
   ============================================================ */

:root{
  --violet:#723FFF;
  --violet-hi:#8455FF;
  --ink:#131313;
  --paper:#fff;

  --nav-h:60px;
  --ease:cubic-bezier(.22,.61,.36,1);

  --font:-apple-system,BlinkMacSystemFont,"PingFang SC","Noto Sans SC",
         "Hiragino Sans GB","Microsoft YaHei",sans-serif;
}

*,*::before,*::after{box-sizing:border-box}

html{
  /* 刻意不写 scroll-behavior:smooth。全页十万像素高，CSS 平滑滚动会让一次
     锚点跳转变成一分钟的动画、沿途把整站图片都解码一遍，弱显卡机器上就是
     一路卡过去。改由 main.js 判断距离：近的平滑滚，跨屏的直接瞬移。 */
  scroll-padding-top:var(--nav-h);
  -webkit-text-size-adjust:100%;
}

body{
  margin:0;
  background:var(--ink);
  color:#fff;
  font-family:var(--font);
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
}

img{max-width:100%}

a{color:inherit}

/* ── 顶部滚动进度条 ─────────────────────────────────────── */
.progress{
  position:fixed;top:0;left:0;height:3px;width:100%;
  /* 用 scaleX 而不是 width：width 每帧都要重新布局 + 重绘，
     scaleX 只是合成层里的一次变换，交给显卡做，不占主线程。 */
  transform:scaleX(0);transform-origin:0 50%;
  background:linear-gradient(90deg,var(--violet),#B18CFF);
  z-index:60;
  will-change:transform;
}

/* ── 顶部导航 ───────────────────────────────────────────── */
.nav{
  position:fixed;top:0;left:0;right:0;height:var(--nav-h);
  display:flex;align-items:center;gap:18px;
  padding:0 clamp(14px,3vw,34px);
  z-index:50;
  /* 顶部时完全透明，免得压住封面自带的窗口栏；滚动后才浮出毛玻璃底 */
  background:transparent;
  border-bottom:1px solid transparent;
  transition:transform .32s var(--ease),background .3s,border-color .3s;
}
/* 顶部透明时垫一层竖向渐变。封面在桌面是紫底（白字看得见），
   在手机上却是白底（白字全隐形，连汉堡图标都没了），
   垫一层深色渐变才能两种底上都读得出来。 */
.nav::before{
  content:"";position:absolute;inset:0;z-index:-1;
  pointer-events:none;
  background:linear-gradient(180deg,rgba(19,19,19,.78),rgba(19,19,19,0));
  transition:opacity .3s;
}
.nav.is-solid::before,
.nav.is-open::before{opacity:0}
.nav.is-solid,
.nav.is-open{
  /* 这里原来是 backdrop-filter:blur(16px)。毛玻璃在滚动时每帧都要重新
     采样背后的画面，弱显卡（Windows 核显）上很贵，是滚动卡顿的常见来源。
     改成不透明的深色底，观感几乎一样，代价是零。 */
  background:rgba(19,19,19,.95);
  border-bottom-color:rgba(255,255,255,.08);
}
.nav.is-hidden{transform:translateY(-100%)}
.nav.is-open{transform:none}

.nav__brand{
  display:flex;align-items:center;gap:9px;
  color:#fff;text-decoration:none;
  font-weight:700;font-size:15px;letter-spacing:.02em;white-space:nowrap;
}
.nav__dot{
  width:8px;height:8px;border-radius:50%;
  background:var(--violet);
  box-shadow:0 0 0 4px rgba(114,63,255,.22);
}
.nav__brand-sub{font-weight:400;opacity:.5;font-size:13px}

.nav__links{display:flex;gap:3px;margin-left:auto}
.nav__links a{
  color:rgba(255,255,255,.66);text-decoration:none;
  font-size:13.5px;padding:7px 11px;border-radius:8px;
  white-space:nowrap;transition:color .2s,background .2s;
}
.nav__links a:hover{color:#fff;background:rgba(255,255,255,.08)}
.nav__links a.is-active{color:#fff;background:rgba(114,63,255,.24)}
.nav__links-contact{display:none}

.nav__cta{
  margin-left:6px;padding:8px 16px;border-radius:999px;
  background:var(--violet);color:#fff;text-decoration:none;
  font-size:13.5px;font-weight:600;white-space:nowrap;
  box-shadow:0 4px 18px rgba(114,63,255,.4);
  transition:background .2s,transform .2s;
}
.nav__cta:hover{background:var(--violet-hi);transform:translateY(-1px)}

.nav__burger{
  display:none;width:38px;height:38px;margin-left:auto;
  border:0;background:transparent;cursor:pointer;padding:0;
  flex-direction:column;justify-content:center;align-items:center;gap:6px;
}
.nav__burger span{
  display:block;width:20px;height:2px;border-radius:2px;
  background:#fff;transition:transform .25s var(--ease),opacity .2s;
}
.nav__burger[aria-expanded="true"] span:first-child{transform:translateY(4px) rotate(45deg)}
.nav__burger[aria-expanded="true"] span:last-child{transform:translateY(-4px) rotate(-45deg)}

/* ── 区块 ───────────────────────────────────────────────── */
.sec{position:relative}
.sec--paper{background:var(--paper)}
.sec--ink{background:var(--ink)}
.sec--violet{background:#F7F7F7}

/* ── 画面容器 ───────────────────────────────────────────── */
.stage{
  position:relative;
  width:100%;max-width:1920px;
  margin:0 auto;
  /* 让子元素可以用 cqw 单位按画面宽度等比定位 */
  container-type:inline-size;
}
.stage__img{display:block;width:100%;height:auto}

/* ── 封面解锁 ───────────────────────────────────────────── */
/* 视觉光环与点击区域分开：光环要精确贴合画面里画的密码框（否则像多画了一道边），
   点击区域则要够大，手机上也点得中。 */
.unlock-ring{
  position:absolute;
  /* 以下四个值是量出来的，别凭眼睛改：设计稿里那个密码框在
     1920×1080 的画面上是 257×43px，中心 (49.95%, 80.09%)。 */
  left:49.9%;top:80.1%;
  transform:translate(-50%,-50%);
  width:13.4%;
  aspect-ratio:5.98/1;
  border-radius:999px;
  pointer-events:none;
  /* 常亮的柔光：保证动画波谷时这个可点区域也看得见 */
  box-shadow:0 0 16px 3px rgba(114,63,255,.40);
}
/* 脉冲交给 ::after 的 transform + opacity。
   原来直接动画 box-shadow —— 那是每帧重绘，而且 infinite 永不停止，
   等于让浏览器一直有活干。这两个属性只走合成层，不占主线程。 */
.unlock-ring::after{
  content:"";position:absolute;inset:-2px;
  border-radius:inherit;
  border:2px solid rgba(114,63,255,.55);
  animation:breathe 2.6s var(--ease) infinite;
}
.unlock{
  position:absolute;
  left:49.9%;top:80.1%;
  transform:translate(-50%,-50%);
  /* 热区比光环大得多，手机上才点得中 */
  width:26%;min-width:100px;
  height:12%;min-height:56px;
  padding:0;border:0;border-radius:999px;
  background:transparent;cursor:pointer;
}
.unlock:hover ~ .unlock-ring{background:rgba(114,63,255,.10)}
@keyframes breathe{
  0%  {transform:scale(1);   opacity:.85}
  70% {transform:scale(1.22);opacity:0}
  100%{transform:scale(1.22);opacity:0}
}

/* 点击后：画面轻轻推进 + 泛紫光 */
.stage--cover.is-unlocking .stage__img{
  transform:scale(1.035);
  filter:blur(2px) brightness(1.06);
  transition:transform .62s var(--ease),filter .62s var(--ease);
}
.stage--cover.is-unlocking::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(circle at 50% 80%,rgba(114,63,255,.5),transparent 62%);
  animation:flash .62s var(--ease) forwards;
}
@keyframes flash{from{opacity:0}45%{opacity:1}to{opacity:0}}

/* ── 目录四张卡片的点击热区（按画面宽度等比定位）─────────
   数值是从本版 PDF 第 3 页逐行扫描出来的卡片真实边界：四张卡等宽 19.9cqw、
   间距 23.65cqw，纵向 23.8% ~ 75.5%。本版目录页版式和视觉版不同，所以不能
   沿用视觉版那组数；以后换 PDF 若目录页版式又变，要重新量。 */
.toc-hit{
  position:absolute;display:block;
  top:23.8%;height:51.7%;
  border-radius:2.2cqw;
  transition:background .25s,box-shadow .25s;
}
.toc-hit:hover{
  background:rgba(114,63,255,.10);
  box-shadow:inset 0 0 0 2px rgba(114,63,255,.55);
}
.toc-hit--1{left:4.5cqw;  width:19.9cqw}
.toc-hit--2{left:28.2cqw; width:19.9cqw}
.toc-hit--3{left:51.8cqw; width:19.9cqw}
.toc-hit--4{left:75.4cqw; width:19.9cqw}

/* ── 长图切片序列 ───────────────────────────────────────── */
/* max-width 必须和上面 .stage 的一致。少了这一条，在 2560 / 4K 这类宽屏上
   就会出现「目录页居中留黑边、下面的项目却铺满整屏」的错位；而且 main.js 的
   sizes 写的是最大 1920px，浏览器只会取 1920 档，铺满 2560 等于把 1920 的图
   拉大 33%，字会糊。 */
.strip{max-width:1920px;margin:0 auto;font-size:0;line-height:0}
.strip img{
  display:block;width:100%;height:auto;
  vertical-align:top;
  /* 消除相邻切片之间可能出现的 1px 缝 */
  margin-bottom:-1px;
}

/* ── 尾页联系区 ─────────────────────────────────────────── */
.sec--end{padding-bottom:0}

.contact{
  max-width:760px;margin:0 auto;
  padding:clamp(56px,9vw,110px) clamp(20px,5vw,40px) clamp(40px,6vw,72px);
  text-align:center;
}
.contact__eyebrow{
  margin:0 0 14px;font-size:11px;letter-spacing:.34em;
  color:var(--violet);font-weight:700;
}
.contact__title{
  margin:0 0 12px;
  font-size:clamp(30px,5.2vw,46px);
  font-weight:800;letter-spacing:-.02em;color:#0B0B0F;
}
.contact__lead{
  margin:0 0 clamp(30px,4.5vw,46px);
  font-size:clamp(14px,1.7vw,16px);color:#6B6B74;
}

.contact__rows{
  display:flex;flex-direction:column;gap:10px;
  text-align:left;
}
.contact__row{
  display:flex;align-items:center;gap:16px;
  padding:16px 22px;border-radius:16px;
  background:#F4F3F7;text-decoration:none;
  transition:background .24s var(--ease),transform .24s var(--ease),box-shadow .24s;
}
.contact__row:hover{
  background:#fff;transform:translateY(-2px);
  box-shadow:0 12px 34px rgba(20,12,60,.12);
}
.contact__k{
  flex:0 0 auto;width:44px;
  font-size:12px;font-weight:700;color:var(--violet);
  letter-spacing:.08em;
}
.contact__v{
  font-size:clamp(14.5px,1.9vw,17px);font-weight:600;color:#15151A;
  word-break:break-all;
}
.contact__v i{font-style:normal;color:var(--violet);margin-left:6px}

.foot{
  display:flex;flex-wrap:wrap;justify-content:center;gap:8px;
  padding:26px 20px 34px;
  font-size:12.5px;color:#9A9AA4;
  border-top:1px solid #ECECF0;
  max-width:760px;margin:0 auto;
}
.foot__sep{opacity:.5}

/* ── 回到顶部 ───────────────────────────────────────────── */
.totop{
  position:fixed;right:clamp(10px,1.6vw,22px);bottom:26px;
  width:44px;height:44px;border-radius:50%;border:0;
  background:var(--violet);color:#fff;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 8px 26px rgba(114,63,255,.44);
  opacity:0;pointer-events:none;transform:translateY(10px);
  transition:opacity .3s var(--ease),transform .3s var(--ease),background .2s;
  z-index:46;
}
.totop.is-on{opacity:1;pointer-events:auto;transform:none}
.totop:hover{background:var(--violet-hi)}
.totop svg{width:19px;height:19px}

/* ── 全屏放大 ───────────────────────────────────────────── */
.lbox{
  position:fixed;inset:0;z-index:80;
  background:rgba(8,8,10,.965);
  display:flex;flex-direction:column;
}
.lbox[hidden]{display:none}

.lbox__bar{
  flex:0 0 auto;display:flex;align-items:center;gap:14px;
  padding:11px clamp(12px,2vw,20px);
  color:#fff;font-size:13px;
  border-bottom:1px solid rgba(255,255,255,.09);
}
.lbox__label{font-weight:600;white-space:nowrap}
.lbox__tip{color:rgba(255,255,255,.44);font-size:12px;margin-left:auto}
.lbox__close{
  width:34px;height:34px;flex:0 0 auto;border:0;border-radius:9px;
  background:rgba(255,255,255,.1);color:#fff;cursor:pointer;
  font-size:15px;line-height:1;transition:background .2s;
}
.lbox__close:hover{background:rgba(255,255,255,.2)}

.lbox__viewport{
  flex:1 1 auto;position:relative;overflow:hidden;
  cursor:grab;touch-action:none;
}
.lbox__viewport.is-grabbing{cursor:grabbing}
.lbox__img{
  position:absolute;top:0;left:0;
  max-width:none;max-height:none;
  transform-origin:0 0;
  will-change:transform;
  user-select:none;-webkit-user-drag:none;
}

/* ── 移动端提示：点按放大 ───────────────────────────────── */
.zoom-hint{
  display:none;
  position:fixed;left:50%;bottom:20px;transform:translateX(-50%);
  z-index:44;
  padding:8px 16px;border-radius:999px;
  background:rgba(19,19,19,.94);color:#fff;font-size:12.5px;
  border:1px solid rgba(255,255,255,.12);
  transition:opacity .4s var(--ease);
}

/* ============================================================
   响应式
   ============================================================ */

/* 中屏：导航收进菜单 */
@media (max-width:1080px){
  :root{--nav-h:54px}

  .nav__burger{display:flex}
  .nav__cta{display:none}

  .nav__links{
    position:fixed;top:var(--nav-h);left:0;right:0;
    flex-direction:column;gap:2px;margin:0;padding:10px 12px 16px;
    background:rgba(19,19,19,.985);
    border-bottom:1px solid rgba(255,255,255,.08);
    opacity:0;pointer-events:none;transform:translateY(-10px);
    transition:opacity .24s var(--ease),transform .24s var(--ease);
  }
  .nav__links.is-open{opacity:1;pointer-events:auto;transform:none}
  .nav__links a{padding:13px 14px;font-size:15px;border-radius:10px}
  .nav__links-contact{
    display:block;margin-top:6px;
    background:var(--violet);text-align:center;font-weight:600;
  }
  .nav__links-contact:hover{background:var(--violet-hi)}
}

/* 窄屏：手机 */
@media (max-width:700px){
  /* 默认不显示；滚到第一个内容区时由 JS 亮出来，免得用户在封面就错过了 */
  .zoom-hint{display:block;opacity:0}

  /* 16:9 的画面在手机上会很小，提示可以点开放大看细节 */
  .unlock{height:14%;min-height:48px}

  .toc-hit{top:21%;height:57%}

  .contact__row{padding:14px 16px;gap:12px}
  .contact__k{width:38px}

  .totop{bottom:calc(20px + env(safe-area-inset-bottom,0px))}
  .zoom-hint{bottom:calc(20px + env(safe-area-inset-bottom,0px))}
}

/* 尊重「减少动态效果」偏好 */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  /* 脉冲停了，得给个静态的边，否则这个可点区域会完全隐形 */
  .unlock-ring{box-shadow:0 0 0 3px rgba(114,63,255,.45)}
  .unlock-ring::after{opacity:0}
}
