/* ============================================================
   styles.css  —  整个网站的外观都在这一个文件里
   零基础也不用怕：上面这一块是「变量」，
   想换配色、换字体、改圆角，改这里的值就行，下面不用动。
   ============================================================ */

:root {
  /* 配色 */
  --bg:          #FBFBF9;   /* 页面底色（暖白） */
  --surface:     #FFFFFF;   /* 卡片底色 */
  --surface-alt: #F4F2EE;   /* 交替区块底色 */
  --ink:         #16161A;   /* 主要文字（近黑） */
  --ink-2:       #4A4A52;   /* 次要文字 */
  --ink-3:       #6A6A73;   /* 说明文字（日期 / 平台 / 图注 / 页脚）
                               ★ 别再调浅了：这个值是算过对比度的。
                               它全部用在 12–14px 的小字上，WCAG AA 要求对比度 ≥ 4.5，
                               而现在三种底色下分别是 5.17（页面底）/ 5.35（卡片白）/
                               4.79（交替区 #F4F2EE）—— 刚好都过。
                               2026-09-15 之前是 #8A8A93，只有 3.06~3.42，不达标。
                               想换风格请换 --accent，不要动这一档灰。 */
  --line:        #E7E4DE;   /* 分割线 / 边框 */
  --accent:      #B4451F;   /* 强调色（砖红）—— 想换风格优先改这个 */
  --accent-soft: #F7EBE5;   /* 强调色的浅底 */

  /* 字体：标题用宋体（有杂志感），正文用系统黑体（清晰） */
  --font-serif: Georgia, "Times New Roman", "Songti SC", "Noto Serif SC",
               "Source Han Serif SC", serif;
  --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
               "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", system-ui, sans-serif;

  /* 尺寸 */
  --wrap: 1080px;
  --radius: 14px;
  --section-y: 92px;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }

a { color: inherit; text-decoration: none; }

ul, ol { margin: 0; padding: 0; list-style: none; }

h1, h2, h3 {
  font-family: var(--font-sans);
  font-weight: 700;
  line-height: 1.3;
  margin: 0;
}

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 24px;
}

/* ---------- 滚动淡入动画（由 script.js 触发） ---------- */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.2, .7, .2, 1);
}
.reveal.is-in { opacity: 1; transform: none; }

/* ⛔ 没有 JS 的时候（脚本被拦、浏览器太老、或者 file:// 下出了岔子）：
   上面那条 .reveal 的 opacity:0 会让**整页看不见**。这里直接显示出来。
   index.html 的 <head> 里有一段同步脚本负责把 html 上的 no-js 摘掉，
   所以正常情况这条永远不生效 —— 它只是保险。 */
html.no-js .reveal { opacity: 1; transform: none; transition: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* ============================================================
   顶部导航 —— 悬在首屏照片上的毛玻璃胶囊菜单
   滚出首屏后自动变成浅色实底（.is-solid 是 script.js 加上去的）
   想改菜单文字，去 index.html 改，这里只负责长相。
   ============================================================ */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 60;
  padding: 20px 0;
  border-bottom: 1px solid transparent;
  transition: background .3s ease, padding .3s ease, border-color .3s ease;
}
.nav.is-solid {
  padding: 10px 0;
  background: rgba(251, 251, 249, .92);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom-color: var(--line);
}

.nav__inner {
  position: relative;
  max-width: 1240px;
  margin: 0 auto;
  padding: 0 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
}

.nav__logo {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: .1em;
  color: #fff;
  text-shadow: 0 2px 14px rgba(0, 0, 0, .5);
  transition: color .3s ease, text-shadow .3s ease;
}
.nav__logo span {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .24em;
  opacity: .72;
}
.nav.is-solid .nav__logo { color: var(--ink); text-shadow: none; }

/* 胶囊本体：外层是「半透明描边的大胶囊」，里面每一项各自再套一个浅色小胶囊。
   这是我们跟参考图对齐的地方 —— 每个菜单项都有一个椭圆的底色，文字更清楚。 */
.nav__links {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .20);
  border: 1px solid rgba(255, 255, 255, .52);
  box-shadow: 0 6px 26px rgba(0, 0, 0, .20);
  backdrop-filter: blur(16px) saturate(170%);
  -webkit-backdrop-filter: blur(16px) saturate(170%);
  transition: background .3s ease, border-color .3s ease, box-shadow .3s ease;
}
.nav.is-solid .nav__links {
  background: rgba(22, 22, 26, .05);
  border-color: rgba(22, 22, 26, .10);
  box-shadow: none;
  /* ⚡ 性能：这层毛玻璃**叠在 .nav.is-solid 的 blur 之上** —— 两层全宽模糊串联，
     浏览器要先把导航底模糊一遍、再把结果模糊一遍，滚动时非常贵。
     滚过首屏后导航底已经是均匀的浅色模糊，再糊一次**肉眼没有区别**，纯浪费。
     （首屏那张深色照片上仍然保留，那里它是有效果的。） */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* 每一项自己的椭圆底色：浅灰白、微微透出后面的照片（跟参考图一致的观感）。
   想让底色更实心就调大最后一个数字（1 是完全不透明）。 */
.nav__links a {
  display: block;
  padding: 8px 20px;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: .02em;
  white-space: nowrap;
  color: #16171B;
  background: rgba(247, 248, 246, .88);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .10);
  transition: background .22s ease, color .22s ease;
}
.nav__links a:hover { background: #fff; }
.nav__links a.is-current {
  background: #16171B;
  color: #fff;
  box-shadow: none;
}
/* 滚出首屏后的浅色实底导航上，小胶囊改成「白底浮起」的观感 */
.nav.is-solid .nav__links a {
  background: #fff;
  box-shadow: 0 1px 3px rgba(22, 22, 26, .09);
}
.nav.is-solid .nav__links a:hover { background: #fff; }
.nav.is-solid .nav__links a.is-current {
  background: #16171B;
  color: #fff;
  box-shadow: none;
}

.nav__toggle {
  display: none;
  width: 42px; height: 42px;
  border: 1px solid rgba(255, 255, 255, .45);
  border-radius: 12px;
  background: rgba(255, 255, 255, .20);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  cursor: pointer;
  padding: 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  transition: border-color .3s ease, background .3s ease;
}
.nav__toggle span {
  display: block;
  width: 16px; height: 1.5px;
  background: #fff;
  transition: transform .25s ease, background .3s ease;
}
.nav__toggle.is-open span:first-child { transform: translateY(3.25px) rotate(45deg); }
.nav__toggle.is-open span:last-child  { transform: translateY(-3.25px) rotate(-45deg); }
.nav.is-solid .nav__toggle {
  border-color: var(--line);
  background: var(--surface);
}
.nav.is-solid .nav__toggle span { background: var(--ink); }

/* ============================================================
   首屏 —— 照片铺满一整屏，名字压在最中间
   换背景图：把你的照片命名为 hero-desktop.jpg（横版 1920×1080）
   和 hero-mobile.jpg（竖版）覆盖 images/ 里的同名文件即可，不用改代码。
   ★ 但换完图一定要把下面 url(...) 里的 ?v=7 数字加一，否则线上会继续用缓存里的旧图。

   关于取景（这张照片的情况）：这是一张半身近照，脸很大，而名字又要求正居中，
   两者必然有重叠。取舍的办法是「把脸在画面里挪低一点」——
   让名字正好落在额头和头发上，眉毛、眼睛、鼻子、嘴全部露出来。
   桌面图的取景（源图 y=285..717）就是按这个选的；竖屏靠 CSS 取景达到同样效果。

   名字的位置由下面 align-items 决定：
     center   → 正中间（当前用的）
     flex-end → 靠下
   注意上下 padding 要**相等**，名字才会落在真正的正中间。
   ============================================================ */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;        /* 名字正居中 */
  justify-content: center;
  padding: 120px 24px;        /* 上下相等 —— 名字才是真正居中 */
  background: #0D0F14 url("images/hero-desktop.jpg?v=7") 68% center / cover no-repeat;
  color: #fff;
  overflow: hidden;
}

/* 压暗层：让白字在任何照片上都读得清。
   这张照片本身很亮，所以只在三处「按需」压暗，中间大片保持明亮：
     ① 顶部一条 —— 给悬在上面的导航（白字）留底，不然白字压在亮天空上看不见
     ② 底部一条 —— 给下滑箭头留底
     ③ 中间一团柔光 —— 只在名字背后压一点点，四周不动
   想更亮：把 ③ 的 .40 / .20 调小；想字更清楚：调大它。
   （最后的 rgba(8,10,14,.07) 是全屏底色，嫌暗可以删掉这一行） */
.hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      rgba(8, 10, 14, .78) 0%,
      rgba(8, 10, 14, .40) 9%,
      rgba(8, 10, 14, .14) 20%,
      rgba(8, 10, 14, 0) 32%),
    linear-gradient(0deg,
      rgba(8, 10, 14, .55) 0%,
      rgba(8, 10, 14, 0) 22%),
    radial-gradient(ellipse 70% 46% at 50% 50%,
      rgba(8, 10, 14, .40) 0%,
      rgba(8, 10, 14, .20) 58%,
      rgba(8, 10, 14, 0) 100%),
    rgba(8, 10, 14, .07);
}

.hero__inner {
  position: relative;
  z-index: 2;
  width: 100%;             /* 必须写死：flex 子项默认按内容撑开，手机上英文那行会顶出屏幕 */
  max-width: 1000px;
  min-width: 0;
  text-align: center;
}

.hero__eyebrow {
  margin: 0 0 26px;
  font-size: clamp(13px, 1.15vw, 17px);
  font-weight: 600;
  letter-spacing: .24em;
  color: rgba(255, 255, 255, .92);
  text-shadow: 0 1px 18px rgba(0, 0, 0, .55);
}

.hero__name {
  margin: 0 0 26px;
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: clamp(58px, 10.5vw, 150px);
  line-height: 1;
  letter-spacing: .06em;
  text-indent: .06em;          /* 抵消字间距在右侧多出的空隙，保证真正居中 */
  color: #fff;
  text-shadow: 0 6px 44px rgba(0, 0, 0, .55);
}

.hero__tagline {
  margin: 0;
  font-size: clamp(15px, 1.5vw, 22px);
  font-weight: 600;
  letter-spacing: .14em;
  color: rgba(255, 255, 255, .95);
  text-shadow: 0 2px 20px rgba(0, 0, 0, .55);
}

/* 底部向下的小箭头 */
.hero__arrow {
  position: absolute;
  left: 50%;
  bottom: 34px;
  z-index: 2;
  width: 46px; height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, .85);
  animation: hero-bob 2.4s ease-in-out infinite;
}
.hero__arrow svg { width: 30px; height: 30px; }
.hero__arrow:hover { color: #fff; }

@keyframes hero-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 8px); }
}
@media (prefers-reduced-motion: reduce) {
  .hero__arrow { animation: none; transform: translateX(-50%); }
}

/* ============================================================
   通用区块
   ============================================================ */
.section { padding: var(--section-y) 0; }
.section--alt {
  background: var(--surface-alt);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.section__head { margin-bottom: 52px; max-width: 720px; }

.section__label {
  margin: 0 0 14px;
  color: var(--accent);
  font-size: 12px;
  letter-spacing: 3px;
  text-transform: uppercase;
}

/* 区块头部统一是「英文小标签 → 中文标题 → 一句引言」三层（跟参考站一致的排法）。
   想换文字去 index.html 改，这里只负责长相。 */
.section__head h2 {
  font-size: clamp(26px, 3.7vw, 40px);
  letter-spacing: .5px;
}

/* 引言：原来是 h2 的那句话，现在挪到标题下面当副标题 */
.section__lead {
  margin: 16px 0 0;
  color: var(--ink-2);
  font-size: clamp(15px, 1.6vw, 17px);
  line-height: 1.85;
}

/* ============================================================
   关于我（about-hero）
   ------------------------------------------------------------
   结构：会晃动的证件吊牌 → ABOUT/关于我 → 关键词轮播 → 自我介绍
        → 邮箱 → 教育经历（两条并列）
   两个动态效果在 lanyard.js（3D 吊牌）和 lightrays.js（背后的光线）里，
   这里只负责长相。
   ★ 吊牌看起来多大：改 .lanyard 的 height —— 它越高，卡片越大。
   ============================================================ */
.about-hero {
  position: relative;
  overflow: hidden;
  padding: 0 0 var(--section-y);
  scroll-margin-top: 76px;
  /* 顶上那块深一点的暖色是「光源」：后面的白色光线压在上面才看得出来。
     想更亮就把第一层的 .26 调小，想光线更明显就调大。 */
  background:
    radial-gradient(ellipse 30% 11% at 50% -2%, rgba(255, 250, 242, .58) 0%, rgba(255, 248, 236, 0) 100%),
    linear-gradient(180deg, rgba(104, 80, 55, .36) 0%, rgba(138, 114, 86, .18) 28%, rgba(180, 160, 135, 0) 56%),
    linear-gradient(180deg, #EFE7DA 0%, #F7F4EF 54%, var(--bg) 100%);
}

/* 背后的光线层：铺满整个区块，不挡点击 */
/* 只铺在顶部一条，并让下缘淡出 —— 铺满整块的话光线会被拉得又宽又淡，等于看不见 */
.light-rays {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: min(82vh, 860px);
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 52%, rgba(0, 0, 0, 0) 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 52%, rgba(0, 0, 0, 0) 100%);
}

.about-hero__inner {
  position: relative;
  z-index: 1;
  text-align: center;
}

/* ---------- 证件照吊牌 ---------- */
/* 这里的默认样式 = 「静态证件照」的样子。
   因为它的存在，即使浏览器的模块脚本被挡住（最常见的：直接双击
   index.html 用 file:// 打开），这一块也一定看得见照片，不会是空白。
   JS 一旦把 3D 吊牌跑起来，就会给容器加上 .is-live，照片收起来、换成 canvas。 */
.lanyard {
  position: relative;
  display: flex;                /* 把照片/画布居中放，箱子的高度从头到尾不变 */
  align-items: center;
  justify-content: center;
  /* 这个高度 = 吊牌那块「画框」的高度。
     它是整块关于我的最顶端，照片就贴在顶部正中。
     想让它更大就调高（卡片会跟着变大），想更紧凑就调低。 */
  height: clamp(330px, 42vh, 440px);
  margin: 0 auto;
}
.lanyard canvas { display: block; }
.lanyard.is-grab { cursor: grab; }
.lanyard.is-grabbing { cursor: grabbing; }

/* 证件照（兜底 / 3D 还没跑起来时先显示它） */
.lanyard__fallback {
  flex: 0 0 auto;
  display: block;
  width: min(230px, 56vw);
  height: auto;
  border: 7px solid #fff;
  border-radius: 14px;
  box-shadow: 0 26px 60px rgba(22, 22, 26, .22);
}

/* 3D 吊牌跑起来了：交给 canvas，照片退场 */
.lanyard.is-live .lanyard__fallback { display: none; }

/* ---------- ABOUT / 关于我 ---------- */
.about-head { margin: 34px 0 0; }
.about-head .section__label { margin-bottom: 12px; }
.about-head__title {
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: clamp(38px, 5.8vw, 60px);
  line-height: 1.12;
  letter-spacing: .12em;
  text-indent: .12em;
  margin: 0;
}

/* ---------- 关键词轮播（那个来回滚动的椭圆） ---------- */
.roller {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 30px 0 0;
  min-height: clamp(46px, 5.4vw, 62px);
}
.roller__pill {
  position: relative;
  display: block;
  height: clamp(46px, 5.4vw, 62px);
  padding: 0 clamp(20px, 2.4vw, 34px);
  border-radius: 999px;
  overflow: hidden;
  background: rgba(255, 255, 255, .72);
  border: 1px solid rgba(180, 69, 31, .22);
  box-shadow: 0 12px 30px rgba(180, 69, 31, .10), inset 0 1px 0 rgba(255, 255, 255, .9);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transition: width .55s cubic-bezier(.2, .8, .2, 1);
}
.roller__word,
.roller__sizer {
  font-family: var(--font-sans);
  font-size: clamp(19px, 2.4vw, 29px);
  font-weight: 700;
  letter-spacing: .04em;
  white-space: nowrap;
}
.roller__word {
  position: absolute;
  left: 0; right: 0; top: 50%;
  transform: translateY(-50%);
  text-align: center;
  color: var(--accent);
  transition: transform .55s cubic-bezier(.2, .8, .2, 1), opacity .42s ease;
}
.roller__word.is-next { transform: translateY(56%); opacity: 0; }
.roller__word.is-leaving { transform: translateY(-156%); opacity: 0; }

/* 量文字宽度的隐形尺子：放在 pill 外面，width:max-content 保证不会被盒子宽度截断 */
.roller__sizer {
  position: absolute;
  left: 0; top: 0;
  width: max-content;
  visibility: hidden;
}

/* 把关键词摊开成小胶囊。两种时候会用到：
   ① 系统开了「减少动态效果」→ JS 给 .roller 加上 .is-static
   ② 模块脚本被挡住（最常见的是直接双击打开这个 html 文件）→
      index.html 里写好的兜底词表（.roller--chips）原样留在页面上 */
.roller.is-static,
.roller--chips {
  flex-wrap: wrap;
  gap: 10px;
  min-height: 0;
  padding: 0 8px;
}
.roller__chip {
  padding: 6px 18px;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  color: var(--accent);
  background: rgba(255, 255, 255, .72);
  border: 1px solid rgba(180, 69, 31, .2);
}

/* ---------- 自我介绍 + 邮箱 ---------- */
.about-hero__lead {
  max-width: 730px;
  margin: 34px auto 0;
  color: var(--ink-2);
  font-size: clamp(15.5px, 1.7vw, 17.5px);
  line-height: 1.95;
}

.about-hero__mail { margin: 26px 0 0; }
.about-hero__mail a {
  display: inline-block;
  padding: 9px 26px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .74);
  color: var(--ink);
  font-size: clamp(14px, 1.55vw, 16px);
  letter-spacing: .02em;
  transition: color .22s ease, border-color .22s ease, background .22s ease;
}
.about-hero__mail a:hover {
  color: var(--accent);
  border-color: rgba(180, 69, 31, .45);
  background: #fff;
}

/* ---------- 教育经历（不单独起小标题，两条直接并列） ---------- */
.edu-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 22px;
  max-width: 1000px;
  margin: 64px auto 0;
  text-align: left;
}
.edu {
  display: flex;
  gap: 20px;
  padding: 26px 26px 28px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .76);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  backdrop-filter: blur(10px) saturate(140%);
  box-shadow: 0 12px 34px rgba(22, 22, 26, .05);
}
.edu__logo {
  flex: 0 0 auto;
  width: 66px;
  height: 66px;
  padding: 5px;
  object-fit: contain;
  border-radius: 50%;
  background: #fff;
  border: 1px solid var(--line);
}
.edu__body { min-width: 0; }
.edu__date {
  margin: 3px 0 7px;
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: .08em;
}
.edu__school {
  font-size: 20px;
  margin: 0 0 6px;
  letter-spacing: .02em;
}
.edu__major {
  margin: 0;
  color: var(--ink-2);
  font-size: 13.5px;
}
.edu__note {
  margin: 12px 0 0;
  color: var(--ink-2);
  font-size: 13.5px;
  line-height: 1.85;
}
.edu__list { margin: 12px 0 0; }
.edu__list li {
  position: relative;
  padding-left: 15px;
  margin-bottom: 6px;
  color: var(--ink-2);
  font-size: 13.5px;
  line-height: 1.7;
}
.edu__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 11px;
  width: 6px; height: 1px;
  background: var(--accent);
}

/* 给读屏软件的隐藏文字（关键词轮播会用到） */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   实习经历 · 时间线（左边日期胶囊 + 中间竖线圆点 + 右边一张卡片）
   —— 桌面：日期在左、卡片在右；手机：竖线挪到最左边，日期压在卡片上方。
   ============================================================ */
.xp__item {
  display: grid;
  grid-template-columns: 178px 1fr;
  gap: 42px;
  position: relative;
  padding-bottom: 26px;
}

/* 竖线：正好落在「日期列」和「卡片列」中间的那条缝里 */
.xp__item::before {
  content: "";
  position: absolute;
  left: 178px;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: var(--line);
}
.xp__item:last-child { padding-bottom: 0; }
.xp__item:last-child::before { bottom: auto; height: 30px; }

/* 圆点：骑在竖线上，外圈用底色描一圈，把线「割断」 */
.xp__item::after {
  content: "";
  position: absolute;
  left: 178px;
  top: 22px;
  width: 11px; height: 11px;
  margin-left: -5.5px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px var(--bg);
}
.section--alt .xp__item::after { box-shadow: 0 0 0 4px var(--surface-alt); }

/* 左边那个日期胶囊 */
.xp__date {
  margin: 0;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 10px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  color: var(--accent);
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: .02em;
  white-space: nowrap;
}

/* 右边的卡片 */
.xp__card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px 26px 22px;
}
.xp__title { font-size: 19px; margin: 0; }
.xp__post {
  color: var(--ink-3);
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 400;
}
.xp__post::before {
  content: "|";
  margin: 0 10px 0 4px;
  color: var(--line);
}

/* 卡片底部的「查看相关作品」按钮 */
.xp__more {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 18px;
  padding: 9px 18px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 13.5px;
  transition: border-color .25s ease, color .25s ease;
}
.xp__more::after {
  content: "\2192";
  transition: transform .25s ease;
}
.xp__more:hover { border-color: var(--accent); color: var(--accent); }
.xp__more:hover::after { transform: translateX(3px); }

/* 窄屏：竖线挪到最左边，日期胶囊压在卡片上方 */
@media (max-width: 760px) {
  .xp__item {
    grid-template-columns: 1fr;
    gap: 12px;
    padding-left: 20px;
    padding-bottom: 26px;
    border-left: 1px solid var(--line);
  }
  .xp__item::before { display: none; }
  .xp__item::after { left: -6px; top: 15px; }
  .xp__item:last-child { border-left-color: transparent; }
  .xp__date {
    flex-direction: row;
    gap: 6px;
    justify-self: start;   /* 不加这句，胶囊会被拉伸成整行宽的一条 */
    padding: 6px 14px;
    font-size: 12.5px;
  }
  .xp__card { padding: 20px 20px 18px; }
  .xp__title { font-size: 17px; }
  /* 窄屏时岗位从「标题同一行」改成「标题下面一行」——
     一定要单独给行高和上边距，否则两行会贴在一起：
     它原来继承标题的 line-height: 1.3（14 × 1.3 = 18.2px，字面上下只余 2px），
     又紧贴标题（实测行盒间距 0px），看着就是「云南广播电视台」被下一行压住。 */
  .xp__post {
    display: block;
    line-height: 1.5;
    margin-top: 5px;
  }
  .xp__post::before { content: none; }
}

.bullets { margin-top: 12px; }
.bullets li {
  position: relative;
  padding-left: 16px;
  margin-bottom: 7px;
  color: var(--ink-2);
  font-size: 14.5px;
}
.bullets li::before {
  content: "";
  position: absolute;
  left: 0; top: 12px;
  width: 6px; height: 1px;
  background: var(--accent);
}

/* ============================================================
   运营项目卡片
   ============================================================ */
.cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* ★ 这里**不要**写 grid-auto-rows: 1fr（2026-09-16 拆掉的坑）：
     原本是「让每一行的卡片都一样高」，但它是**所有行统一等高**，于是
     ① 单列时三张卡全被撑到最高的那张，文字短的卡中间空一大片；
     ② 整行宽的斯里兰卡卡也被撑到 549px，照片框从 3:2 变成近方形，九宫格被裁掉 1/3。
     用默认的 auto 就行：同一行里的卡仍然会被拉伸成等高（grid 的 align 默认就是 stretch），
     而每一行按自己的内容定高，不会有假留白。 */
  gap: 24px;
}
/* 屏幕变窄就退成两列、一列，免得卡片里的字被挤成一团 */
@media (max-width: 980px) { .cards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px) {
  /* 单列：三张卡各按自己的内容高度排（配合上面 .cards 的 grid-auto-rows: auto） */
  .cards { grid-template-columns: 1fr; }
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform .35s cubic-bezier(.2, .7, .2, 1), box-shadow .35s ease;
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 14px 36px rgba(22, 22, 26, .07);
}

.card__body {
  padding: 26px 26px 24px;
  display: flex;
  flex-direction: column;
  flex: 1;                 /* 撑满卡片，好让最下面那行能贴着底边 */
}

.chip {
  display: inline-block;
  margin: 0 0 12px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 12px;
  line-height: 1.6;
}

.card__body h3 { font-size: 19px; margin: 0 0 12px; }

.card__desc {
  margin: 0 0 22px;
  color: var(--ink-2);
  font-size: 14.5px;
}

/* 卡片上那个「大字数据」—— 整张卡片的视觉主角 */
.card__stat {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 46px;
  line-height: 1.05;
  letter-spacing: -.01em;
  color: var(--accent);
}
/* 大字下面那行小注释 */
.card__statlabel {
  margin: 6px 0 22px;
  color: var(--ink-3);
  font-size: 13px;
}
/* 卡片底部那句总结：一条细线隔开，并且自动贴到卡片底边 */
.card__foot {
  margin: auto 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  color: var(--accent);
  font-weight: 700;
  font-size: 15px;
}

/* 「待补充」状态的卡片：虚线边框 + 灰字，一眼能看出还没填 */
.card--pending { border-style: dashed; cursor: default; }
.card--pending:hover { transform: none; box-shadow: none; }
.card--pending .card__stat { color: var(--ink-3); opacity: .45; }
.chip--quiet { background: var(--surface-alt); color: var(--ink-3); }
.card__foot--quiet { color: var(--ink-3); font-weight: 600; }

/* ============================================================
   作品集：筛选 + 图片墙
   ============================================================ */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 34px;
}

.filter {
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  font-family: var(--font-sans);
  font-size: 13.5px;
  padding: 8px 18px;
  border-radius: 999px;
  cursor: pointer;
  transition: all .2s ease;
}
.filter:hover { border-color: var(--ink-3); color: var(--ink); }
.filter.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

.shots {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px 24px;
}
.shot.is-hidden { display: none; }

.shot__frame {
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--surface-alt);
  border: 1px solid var(--line);
}
.shot__frame img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .5s cubic-bezier(.2, .7, .2, 1);
}
.shot:hover .shot__frame img { transform: scale(1.045); }

.shot b {
  display: block;
  margin-top: 14px;
  font-weight: 600;
  font-size: 15px;
}
.shot em {
  display: block;
  margin-top: 3px;
  color: var(--ink-3);
  font-size: 12.5px;
  font-style: normal;
}

/* ============================================================
   联系方式 + 页脚
   ============================================================ */
/* 收尾区：整屏海边照片收尾（2026-09-19 加）—— 和首屏呼应，一头一尾都是全屏照片。
   ⚠️ 原图是**竖版**（960x1282），横屏视口只能看到约四成的高度，
      所以桌面档单独切了一条横带（源图起点 y=300、高 600）：
      让「脸」落在视口上沿 0~25、文字块落在 34~66 —— 两者正好不重叠。
      竖屏手机相反：用原图整张，人物反而完整（见下方 max-aspect-ratio 那条）。 */
.contact {
  position: relative;
  min-height: 100svh;          /* 撑满一屏 —— 和 .hero 同款写法 */
  display: flex;               /* 内容在整屏里居中 */
  align-items: center;
  justify-content: center;
  padding: 120px 24px;         /* 上下相等 → 文字真正居中 */
  text-align: center;
  background: #0D0F14 url("images/contact-bg-desktop.jpg?v=44") 50% 46% / cover no-repeat;
  color: #fff;
  overflow: hidden;
}

/* 压暗层：**只在需要的地方压**，别整屏压暗（这张照片本身已经偏暗）。
   ① 顶部一条给导航的白字留底；② 底部一条收尾渐隐；
   ③ 中间一小团柔光，只在文字背后 —— 四周不动，照片的通透感留着。 */
.contact::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(8, 10, 14, .74) 0%, rgba(8, 10, 14, .30) 11%,
                            rgba(8, 10, 14, .10) 20%, rgba(8, 10, 14, 0) 30%),
    linear-gradient(0deg,   rgba(8, 10, 14, .66) 0%, rgba(8, 10, 14, .18) 18%,
                            rgba(8, 10, 14, 0) 32%),
    radial-gradient(ellipse 64% 38% at 50% 50%,
                    rgba(8, 10, 14, .50) 0%, rgba(8, 10, 14, .22) 62%, rgba(8, 10, 14, 0) 100%);
}

.contact > .wrap {
  position: relative;
  z-index: 1;
  width: 100%;
}

/* 照片上的文字改浅色（原来是深色 --ink，落在照片上根本看不见） */
.contact .section__label { color: rgba(255, 255, 255, .66); }
.contact__title {
  font-size: clamp(22px, 3.6vw, 36px);
  max-width: 620px;
  margin: 0 auto 40px;
  color: #F6F4EF;
  text-shadow: 0 2px 26px rgba(0, 0, 0, .42);
}
.contact__mail a {
  font-family: var(--font-serif);
  font-size: clamp(22px, 4vw, 34px);
  color: #F6F4EF;   /* 照片上砖红对比度不够，改米白 */
  border-bottom: 1px solid rgba(255, 255, 255, .36);
  padding-bottom: 4px;
  text-shadow: 0 2px 20px rgba(0, 0, 0, .40);
  transition: border-color .25s ease;
}
.contact__mail a:hover { border-color: #fff; }
.contact__alt {
  margin-top: 28px;
  color: rgba(255, 255, 255, .52);
  font-size: 13.5px;
}

.footer {
  border-top: 1px solid var(--line);
  padding: 26px 0;
  font-size: 13px;
  color: var(--ink-3);
}
.footer__inner {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.footer p { margin: 0; }
.footer a:hover { color: var(--accent); }

/* ============================================================
   运营项目卡片：整张卡片可以点进详情页
   ============================================================ */
a.card { cursor: pointer; }
a.card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ============================================================
   作品集：点图看大图
   ============================================================ */
.shot[data-lightbox] .shot__frame { cursor: zoom-in; }

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: none;
  place-items: center;
  padding: 40px 24px;
  background: rgba(22, 22, 26, .93);
}
.lightbox.is-open { display: grid; }

.lightbox__img {
  max-width: 100%;
  max-height: 86vh;
  border-radius: 10px;
  object-fit: contain;
}

.lightbox__close {
  position: absolute;
  top: 18px; right: 22px;
  width: 42px; height: 42px;
  border: 1px solid rgba(255, 255, 255, .3);
  border-radius: 50%;
  background: transparent;
  color: #fff;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  transition: background .2s ease;
}
.lightbox__close:hover { background: rgba(255, 255, 255, .14); }

/* ============================================================
   404 错误页
   ============================================================ */
.notfound {
  min-height: 66vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.notfound__code {
  margin: 0 0 18px;
  font-family: var(--font-serif);
  font-size: clamp(64px, 14vw, 130px);
  line-height: 1;
  letter-spacing: 4px;
  color: var(--accent);
}
.notfound p {
  margin: 0 0 36px;
  color: var(--ink-2);
}
.notfound__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
}
.notfound__links a {
  padding: 10px 22px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-2);
  font-size: 14px;
  transition: background .2s ease, border-color .2s ease, color .2s ease;
}
.notfound__links a:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

/* ============================================================
   项目详情页（project.html）专用样式
   ============================================================ */
.backlink {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 34px;
  color: var(--ink-3);
  font-size: 14px;
}
.backlink:hover { color: var(--accent); }

.article {
  max-width: 780px;
  margin-inline: auto;   /* 正文列在页面正中，作品区才能对准整个屏幕居中 */
}

.article__title {
  font-size: clamp(30px, 4.6vw, 46px);
  letter-spacing: 1px;
  margin: 0 0 16px;
}

.article__lead {
  max-width: 660px;
  margin: 0 0 34px;
  color: var(--ink-2);
  font-size: 17px;
}

.article__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 30px;
  margin: 0 0 36px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--line);
}
.article__meta div { color: var(--ink-2); font-size: 14px; }
.article__meta span {
  display: block;
  margin-bottom: 2px;
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: 1px;
}

.article__hero {
  margin: 0 0 44px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface-alt);
}
.article__hero img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.article > p {
  margin: 0 0 20px;
  color: var(--ink-2);
  font-size: 16.5px;
}
.article > p:first-of-type { color: var(--ink); font-size: 18px; }

.article h2 { font-size: 23px; margin: 46px 0 16px; }

.article__quote {
  margin: 34px 0;
  padding: 2px 0 2px 24px;
  border-left: 2px solid var(--accent);
  font-family: var(--font-serif);
  font-size: 19px;
  line-height: 1.7;
  color: var(--ink);
}

.article__stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin: 40px 0;
  padding: 26px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.article__stats b {
  display: block;
  font-family: var(--font-serif);
  font-size: 28px;
  font-weight: 600;
  color: var(--accent);
}
.article__stats span { display: block; color: var(--ink-3); font-size: 13px; }


/* ============================================================
   项目详情页 ·「作品实证」区
   这一块专门用来摆做出来的东西（见报版面、公众号推文截图）。
   ============================================================ */
.gallery {
  /* 详情页正文只有 780px 宽，但三张公众号截图并排塞进 780px 会小到看不清字，
     所以这一块要「撑破」正文宽度，最多到 1160px，并对准整个屏幕居中。 */
  width: min(1160px, calc(100vw - 48px));
  position: relative;
  left: 50%;
  translate: -50% 0;
  margin: 54px 0 10px;
}

.gallery__head { margin-bottom: 26px; }
.gallery__head h2 { font-size: 23px; margin: 6px 0 10px; }
.gallery__note { margin: 0; color: var(--ink-2); font-size: 15px; }

/* 每组前面的那小行说明字，例如「纸媒 ·《重庆晨报》见报版面」 */
.gallery__caption {
  margin: 30px 0 14px;
  color: var(--ink-3);
  font-size: 13px;
  letter-spacing: .04em;
}

/* 三张公众号截图并排 */
.gallery__row {
  display: grid;
  /* auto-fit + minmax：每张至少 300px，能排几张排几张。
     1160px 时是 3 列（每张 374）、820px 时是 2 列、手机上一列。
     写死 repeat(3, 1fr) 的话，820px 时每张只剩 242px，截图里的字就看不清了。

     ★ 下限写成 min(300px, 100%) 而不是直接写 300px —— 这一层很关键：
       超窄屏（320px 那种老设备、或者浏览器窗口被拖得极窄）时，
       这一块的可视宽度只有 272px（= 100vw − 48px 的左右留白），
       而 300px 的下限会逼着列宽撑到 300px → 整页横向溢出 4px、能左右晃。
       min() 让「下限」在容器比它更窄时退让，宽屏下行为和原来完全一样。 */
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 18px;
  align-items: start;
}

.gallery__figure { margin: 0; }
.gallery__figure a { display: block; cursor: zoom-in; }
.gallery__figure img {
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  transition: transform .3s ease, box-shadow .3s ease;
}
.gallery__figure a:hover img {
  transform: translateY(-3px);
  box-shadow: 0 12px 28px rgba(22, 22, 26, .09);
}
.gallery__figure figcaption {
  margin-top: 10px;
  color: var(--ink-3);
  font-size: 12.5px;
  line-height: 1.65;
}

/* 纸媒版面：竖版，能排几列排几列（1160px 宽时 3 列，820px 时 2 列，手机 1 列）
   （下限同样用 min(300px, 100%)，理由见上面 .gallery__row 那段注释） */
.gallery__row--press {
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}

/* 公众号推文：横版，固定两列 —— 列多了字就糊了，HR 反而看不清标题。
   窄屏（≤760px）退成一列，每张占满宽度。 */
.gallery__row--link {
  grid-template-columns: repeat(2, 1fr);
}

/* 点图会跳到外链（公众号原文）的那几张：鼠标变小手，右上角挂一个 ↗，
   提醒「点了是往外走」，跟纸媒那几张「点了原地放大」区分开。 */
.gallery__figure--link a { cursor: pointer; position: relative; }
.gallery__go {
  position: absolute;
  top: 10px; right: 10px;
  width: 28px; height: 28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, .93);
  border: 1px solid var(--line);
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1;
  transition: background .25s ease, color .25s ease, border-color .25s ease;
}
.gallery__figure--link a:hover .gallery__go {
  background: var(--accent);
  border-color: var(--accent);
  color: #FFF;
}

/* 见报版面图注里那行署名 —— 名字印在报纸上，是整页最硬的一条证据，
   所以给它比普通图注更深的颜色，并把本人名字再加重一档。 */
.gallery__credit { color: var(--ink-2); }
.gallery__credit b { color: var(--ink); font-weight: 700; }

/* 图注里的「阅读原文 ↗」 */
.gallery__link {
  color: var(--accent);
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
  white-space: nowrap;
}
.gallery__link:hover { opacity: .72; }

@media (max-width: 760px) {
  .gallery__row { gap: 28px; }
  .gallery__row--link { grid-template-columns: 1fr; }
  .gallery__figure img { border-radius: 8px; }
  .gallery__go { top: 8px; right: 8px; }
}


/* ============================================================
   「做了什么」这类要点列表：一个圆点 + 一个粗体小标题 + 一句说明
   ============================================================ */
.facts { display: grid; gap: 12px; margin: 0 0 8px; }
.facts li {
  display: flex;
  gap: 10px;
  color: var(--ink-2);
}
.facts li::before {
  content: "";
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  margin-top: .68em;
  border-radius: 50%;
  background: var(--accent);
  opacity: .55;
}
.facts b { color: var(--ink); font-weight: 700; }
.facts b::after { content: "："; color: var(--ink-3); font-weight: 400; }

.next-project {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 64px;
  padding-top: 30px;
  border-top: 1px solid var(--line);
  font-size: 15px;
}
.next-project a {
  color: var(--accent);
  border-bottom: 1px solid var(--accent-soft);
}
.next-project a:hover { border-color: var(--accent); }

@media (max-width: 680px) {
  .article__stats { grid-template-columns: 1fr; gap: 16px; }
}

/* ============================================================
   获奖
   ============================================================ */
.awards { border-top: 1px solid var(--line); }
.awards li {
  display: grid;
  grid-template-columns: 84px 1fr auto;
  align-items: center;
  gap: 26px;
  padding: 26px 6px;
  border-bottom: 1px solid var(--line);
  transition: background .25s ease, padding .25s ease;
}
.awards li:hover {
  background: var(--surface-alt);
  padding-left: 18px;
  padding-right: 18px;
}
.awards__year {
  font-family: var(--font-serif);
  font-size: 22px;
  color: var(--accent);
  letter-spacing: .5px;
}
.awards__body h3 { font-size: 19px; margin-bottom: 3px; }
.awards__body p { margin: 0; color: var(--ink-3); font-size: 14px; }
.awards__tag {
  font-size: 13px;
  color: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 14px;
  white-space: nowrap;
}

/* 奖项行里的「查看作品」链接（2026-09-18 加，用在获奖区那条学院奖上）。
   和 .next-project a 同一套语言：砖红字 + 浅色下划线。 */
.awards__link {
  display: inline-block;
  margin-top: 8px;
  color: var(--accent);
  font-size: 13.5px;
  border-bottom: 1px solid var(--accent-soft);
}
.awards__link:hover {
  border-color: var(--accent);
}

/* ============================================================
   响应式：屏幕变窄时自动调整布局
   ============================================================ */
@media (max-width: 900px) {
  :root { --section-y: 68px; }

  /* 注意：项目卡的列数由上面 .cards 那三条规则统一管（3 列 → 2 列 → 1 列），
     这里不要再写 .cards，否则会以「更靠后」的身份把它盖掉。 */
  .shots { grid-template-columns: repeat(2, 1fr); }
  .edu-grid { grid-template-columns: 1fr; gap: 18px; }
}

/* —— 窄窗口（手机横屏、小平板）：字号收一档，取景仍用横版照片 —— */
@media (max-width: 900px) {
  .hero__eyebrow {
    font-size: clamp(11px, 1.5vw, 14px);
    letter-spacing: .12em;
    line-height: 1.9;
    margin-bottom: 18px;
  }
  .hero__name { font-size: clamp(52px, 11vw, 104px); margin-bottom: 20px; }
  .hero__tagline { font-size: clamp(13px, 1.6vw, 17px); letter-spacing: .07em; }
}

/* —— 竖屏（手机、平板竖着用）：横版切图在这个比例下会把人脸挤到文字上，
      所以换成竖版原图。竖图在窄屏上是「高度填满、左右裁掉一截」，
      所以取景要往右偏（68%），保证人脸不被右边缘切掉。
      文字同样正居中（上下 padding 相等）。 —— */
@media (max-aspect-ratio: 4/5) {
  .hero {
    padding: 100px 20px;
    background-image: url("images/hero-mobile.jpg?v=7");
    background-size: cover;
    background-position: 68% center;
  }
}

@media (max-width: 680px) {
  /* —— 导航：胶囊收成右上角的汉堡按钮，点开是一个深色面板 —— */
  .nav { padding: 12px 0; }
  .nav__inner { min-height: 40px; padding: 0 16px; }
  .nav__logo span { display: none; }
  .nav__toggle { display: flex; }

  .nav__links {
    position: absolute;
    top: calc(100% + 12px);
    left: 0; right: 0;
    transform: none;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: 8px;
    border-radius: 18px;
    background: rgba(18, 20, 24, .88);
    border-color: rgba(255, 255, 255, .16);
    display: none;
  }
  .nav__links.is-open { display: flex; }
  /* 滚出首屏后导航会变浅底（.is-solid）——展开的深色面板不能被它染白，
     否则白字会掉在浅底上看不清。这两条是给它的「免疫」。 */
  .nav.is-solid .nav__links {
    background: rgba(18, 20, 24, .88);
    border-color: rgba(255, 255, 255, .16);
  
    backdrop-filter: none;    /* ⚡ 背景已经 .88 不透明，这层模糊看不出效果 */
    -webkit-backdrop-filter: none;
  }
  .nav__links a,
  .nav.is-solid .nav__links a {
    text-align: center;
    padding: 12px;
    color: #fff;
    background: transparent;    /* 展开的深色面板里不要那层浅色椭圆底 */
    box-shadow: none;
    font-size: 15px;
  }
  .nav__links a:hover,
  .nav.is-solid .nav__links a:hover { background: rgba(255, 255, 255, .14); }
  .nav__links a.is-current,
  .nav.is-solid .nav__links a.is-current { background: #fff; color: #16171B; }

  .hero { padding: 100px 20px; }        /* 上下相等 —— 名字仍居正中 */
  .hero__eyebrow { font-size: 11px; letter-spacing: .1em; margin-bottom: 16px; }
  .hero__name { font-size: clamp(52px, 18vw, 82px); margin-bottom: 18px; }
  .hero__tagline { font-size: 13.5px; letter-spacing: .06em; }
  .hero__arrow { bottom: 26px; }

  /* —— 关于我 —— */
  .lanyard { height: clamp(280px, 44vh, 380px); }
  .about-head__title { letter-spacing: .08em; text-indent: .08em; }
  .about-hero__lead { margin-top: 26px; line-height: 1.9; }
  .edu-grid { margin-top: 44px; }
  .edu { flex-direction: column; gap: 14px; padding: 22px; }
  .edu__logo { width: 58px; height: 58px; }
  .edu__school { font-size: 18px; }

  .shots { grid-template-columns: 1fr; }

  /* —— 获奖 —— */
  .awards li {
    grid-template-columns: 1fr;
    gap: 8px;
    padding: 22px 4px;
  }
  .awards__tag { justify-self: start; }
}

/* ============================================================
   2026-09-16 新增：校园项目特色卡 + 作品集文件夹导航 + 作品卡
   ============================================================ */

/* ---------- 一、项目卡的深色卡面（.card--dark）与封面「相框」----------

   ⭐ 深色卡面 .card--dark —— **当前没有任何卡片在用，规则留着备用**。
   2026-09-16 先加给四张卡（用户当时说「更喜欢黑色的」），当天又被他自己否掉：
   「算了还是用原来的那种暗红字白底的搭配吧，感觉黑色的有点不搭」。
   哪天想再要深色卡：给卡片加 class="card--dark" 即可，不用重写。
   配色和布局是分开的 —— 宽窄、整行宽由 .card--feature 等布局规则决定，别混着写。 */
.card--dark {
  background: var(--ink);
  border-color: var(--ink);
}
.card--dark:hover { box-shadow: 0 18px 44px rgba(22, 22, 26, .2); }
.card--dark .chip { background: rgba(255, 255, 255, .15); color: #fff; }
.card--dark .card__stat { color: #fff; }
.card--dark .card__statlabel { color: rgba(255, 255, 255, .6); }
.card--dark .card__body h3 { color: #fff; }
.card--dark .card__desc { color: rgba(255, 255, 255, .76); }
.card--dark .card__foot { color: #fff; border-top-color: rgba(255, 255, 255, .18); }

/* ⭐ 三张窄卡顶部的封面「相框」（16:9）。
   图片是**放大铺满**（object-fit: cover），框里不留任何空白或模糊。
   ⚠️ 2026-09-16 曾用过「contain 居中 + 同图模糊垫底」，被用户否掉：
   「不要上下或者左右边缘给他模糊化，要么放大一点铺满，要么等比例放大，
     有一点遮蔽原图的内容都没事」。
   所以三张素材**预先裁成了 16:9**（每张的裁切窗口见 README 的图片表），
   cover 在这里只是保险 —— 换图时新图也要先裁成 16:9，否则会被 cover 二次裁切。
   （.card--feature 那张整行宽的卡另有一套，用 :not 排掉。） */
.card:not(.card--feature) .card__media {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--surface);              /* 浅色打底：图没加载出来时也不会出现黑块 */
  border-bottom: 1px solid var(--line);
}
.card:not(.card--feature) .card__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---------- 校园项目特色卡：整行宽 + 左图右文（布局，配色见上面的 .card--dark）----------
   ⚠️ 照片框用 aspect-ratio 自己定比例，**不要用 min-height**：
   之前写 min-height: 320px，框高就完全听行的安排，行高一变（比如上面三张卡加了图）
   照片比例就跟着变形 —— 那张九宫格会被裁掉三分之一。
   想换照片：改 .card__media 里的 img 的 src / width / height（比例不是 3:2 就把下面这行一起改）。 */
.card--feature {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 1.06fr) minmax(0, 1fr);
}
.card--feature .card__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 2;
}
.card--feature .card__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* 照片上压一层暗角，让左下角的「校园项目」标签看得清 */
.card--feature .card__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, rgba(22, 22, 26, .52) 0%, rgba(22, 22, 26, .06) 46%, rgba(22, 22, 26, .5) 100%);
}
.card--feature .card__badge {
  position: absolute;
  left: 22px;
  bottom: 20px;
  z-index: 2;
  margin: 0;
  padding: 5px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .92);
  color: var(--ink);
  font-size: 12px;
  letter-spacing: .04em;
}
.card--feature .card__body { padding: 36px 36px 30px; }
.card--feature .card__body h3 { font-size: 21px; }   /* 配色已归 .card--dark */

/* ---------- 二、作品集：文件夹式合集导航 ----------
   复刻 ReactBits 那个 Folder 动效的观感：悬停掀开一角、点击保持打开。
   ★ 比例（2026-09-16 修）：文件夹锁成 4:3、最大 176px 并居中。
     之前是「宽度撑满单元格 + 固定 94px 高」，桌面上一格 250px 宽就被拉成
     2.6:1 的扁条，所以看着别扭。内部所有位置都改成百分比，缩放不走形。
   每个文件夹的颜色由行内 style 的两个变量决定：
     --album    前面那片（主色）
     --album-2  背板 + 左上角小舌头（更深一档）
   加一个合集：复制一个 <button class="album">，改 data-album / 两个颜色 / 文字。 */
.albums {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 30px 20px;
  margin-bottom: 48px;
}

.album {
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  text-align: center;
  font-family: var(--font-sans);
  color: inherit;
}

/* 文件夹本体：4:3、最宽 176px、水平居中 */
.album__shape {
  position: relative;
  display: block;
  width: min(100%, 176px);
  aspect-ratio: 4 / 3;
  margin: 0 auto 15px;
  perspective: 620px;
  transition: transform .4s cubic-bezier(.2, .7, .2, 1);
}

/* 口袋（背板）：深一档的 --album-2，从 13% 处开始，上面留给舌头 */
.album__back {
  position: absolute;
  left: 0;
  right: 0;
  top: 13%;
  bottom: 0;
  z-index: 1;
  border-radius: 9px;
  background: var(--album-2);
  box-shadow: inset 0 3px 6px rgba(22, 22, 26, .2);   /* 内侧上沿暗一点，像个口袋 */
}
/* 左上角的舌头：用和前面同色的 --album，比口袋浅，一眼看出是「翻开的那片」 */
.album__back::before {
  content: '';
  position: absolute;
  left: 0;
  top: -13%;
  width: 46%;
  height: 14%;
  border-radius: 7px 9px 0 0;
  background: var(--album);
}

/* 掀开时从口袋里露出来的「纸」：只露一小截，不越出口袋上沿 */
.album__paper {
  position: absolute;
  left: 8%;
  right: 8%;
  top: 15%;
  height: 20%;
  z-index: 2;
  border-radius: 4px;
  background: #fff;
  opacity: 0;
  transform: translateY(6%);
  transition: opacity .35s ease, transform .45s cubic-bezier(.2, .7, .2, 1);
}
.album__paper:nth-of-type(2) { left: 14%; right: 14%; top: 18%; height: 16%; }

/* 前面那片：掀开靠 rotateX（原点在底边） */
.album__front {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  height: 62%;
  border-radius: 9px;
  background: var(--album);
  transform-origin: bottom center;
  transition: transform .5s cubic-bezier(.2, .7, .2, 1), box-shadow .4s ease;
  box-shadow: 0 5px 12px rgba(22, 22, 26, .16);
}

.album:hover .album__front { transform: rotateX(-20deg); }
.album:hover .album__paper { opacity: 1; transform: translateY(0); }
.album.is-active .album__front { transform: rotateX(-30deg); }
.album.is-active .album__paper { opacity: 1; transform: translateY(-3%); }
.album.is-active .album__shape { transform: translateY(-3px); }

.album__name {
  display: block;
  min-height: 2.9em;   /* 固定两行的高度：名字有长有短时，下面的件数也能对齐 */
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-2);
  transition: color .3s ease;
}
.album.is-active .album__name { color: var(--ink); font-weight: 600; }
.album__count {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  color: var(--ink-3);
}
.album:focus-visible .album__shape {
  outline: 2px solid var(--accent);
  outline-offset: 8px;
  border-radius: 10px;
}

/* ---------- 三、作品卡 ---------- */
.works {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
  gap: 30px 26px;
}
.work { display: block; color: inherit; }
.work.is-hidden { display: none; }

.work__frame {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--surface-alt);
  border: 1px solid var(--line);
}
.work__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s cubic-bezier(.2, .7, .2, 1);
}
.work:hover .work__frame img { transform: scale(1.045); }

/* 视频：右下角一个播放圆钮 + 左下角时长 */
.work__play {
  position: absolute;
  right: 12px;
  bottom: 12px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(22, 22, 26, .66);
  color: #fff;
  font-size: 13px;
  backdrop-filter: blur(6px);
}
.work__dur {
  position: absolute;
  left: 12px;
  bottom: 13px;
  padding: 3px 9px;
  border-radius: 6px;
  background: rgba(22, 22, 26, .6);
  color: #fff;
  font-size: 12px;
  letter-spacing: .02em;
}
.work__tag {
  display: inline-block;
  margin: 15px 0 9px;
  padding: 3px 11px;
  border: 1px solid currentColor;
  border-radius: 999px;
  color: var(--accent);
  font-size: 11.5px;
}
.work__title {
  display: block;
  font-size: 16.5px;
  font-weight: 700;
  line-height: 1.55;
  color: var(--ink);
}
.work__meta {
  display: block;
  margin-top: 8px;
  font-size: 13px;
  color: var(--ink-3);
}

/* 文稿类作品：没有视频封面，就用「纸面」版式 */
.work--text .work__frame {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: 12px;
  padding: 30px;
  background: linear-gradient(155deg, #FCFAF5 0%, #F1EADD 100%);
  border-color: #E6DCC9;
}
.work--text .work__mark {
  font-family: var(--font-serif);
  font-size: 30px;
  line-height: 1;
  color: #C0AE8C;
  letter-spacing: .1em;
}
.work--text .work__frame b {
  font-family: var(--font-serif);
  font-size: 21px;
  line-height: 1.6;
  color: var(--ink);
}

/* 合集里暂时没有作品时的提示 */
.works-empty {
  grid-column: 1 / -1;
  padding: 56px 24px;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  text-align: center;
  color: var(--ink-3);
  font-size: 14.5px;
  background: var(--surface);
}
.works-empty b { display: block; margin-bottom: 8px; color: var(--ink-2); font-size: 16px; }

/* ---------- 四、灯箱支持视频 ---------- */
.lightbox__video {
  display: none;
  max-width: min(1100px, 92vw);
  max-height: 84vh;
  border-radius: var(--radius);
  background: #000;
}
.lightbox.is-video .lightbox__img { display: none; }
.lightbox.is-video .lightbox__video { display: block; }

/* ---------- 五、详情页：照片马赛克 ---------- */
.photomosaic {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin: 26px 0 6px;
}
.photomosaic a {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 10px;
  border: 1px solid var(--line);
  cursor: zoom-in;
}
.photomosaic img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform .5s cubic-bezier(.2, .7, .2, 1);
}
.photomosaic a:hover img { transform: scale(1.05); }
.photomosaic a.is-wide { grid-column: span 2; }
/* 竖版那张：跨两行，正好和左边的横版等高 */
.photomosaic a.is-portrait { grid-row: span 2; aspect-ratio: auto; }
/* 只在「宽屏」占两列的格子（2026-09-17 加）。
   为什么需要它：照片墙的格数在两种宽度下要各自凑满 —— 桌面 3 列、手机 2 列，
   一张跨 2 格的图在两边占的格数不同（桌面 2 格 / 手机 2 格），
   而「只在一个宽度跨格」才能让两边同时不留空洞（桌面 12 格 = 4 行，
   手机 10 格 = 5 行）。加照片前先按这个算一遍格数，别直接往上堆。 */
@media (min-width: 681px) {
  .photomosaic a.is-wide-lg { grid-column: span 2; }
}

/* ---------- 六、详情页：视频作品卡 ---------- */
.vcards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 26px;
  margin: 26px 0 10px;
}
.vcard { margin: 0; }
.vcard__frame {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: #000;
  cursor: pointer;
  font: inherit;
}
.vcard__frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vcard__veil {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(22, 22, 26, .26);
  transition: background .3s ease;
}
.vcard:hover .vcard__veil { background: rgba(22, 22, 26, .42); }
.vcard__veil span {
  width: 58px;
  height: 58px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, .94);
  color: var(--ink);
  font-size: 19px;
  box-shadow: 0 10px 26px rgba(0, 0, 0, .3);
}
.vcard__dur {
  position: absolute;
  right: 11px;
  bottom: 11px;
  padding: 3px 9px;
  border-radius: 6px;
  background: rgba(22, 22, 26, .66);
  color: #fff;
  font-size: 12px;
}
.vcard figcaption { margin-top: 13px; font-size: 13px; color: var(--ink-3); line-height: 1.7; }
.vcard figcaption b { display: block; margin-bottom: 4px; font-size: 15.5px; font-weight: 700; color: var(--ink); }

/* 文稿类作品：没有播放按钮，换成「纸面」版式 */
.vcard__frame--paper {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 14px;
  padding: 30px;
  cursor: default;
  background: linear-gradient(155deg, #FCFAF5 0%, #F1EADD 100%);
  border-color: #E6DCC9;
}
.vcard__frame--paper b {
  font-family: var(--font-serif);
  font-size: 21px;
  line-height: 1.6;
  color: var(--ink);
}

/* ---------- 七、详情页：能力展示网格 ---------- */
.skills {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
  gap: 18px;
  margin: 24px 0 8px;
}
.skill {
  padding: 20px 22px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.skill b { display: block; margin-bottom: 8px; font-size: 15px; color: var(--ink); }
.skill span { font-size: 13.5px; line-height: 1.8; color: var(--ink-2); }

/* ---------- 七之二、作品集里的「子文件夹」卡（2026-09-17 加）----------
   点开是「专题报道合集」这种独立页面。外形复用相册导航那套 CSS 3D 文件夹，
   只是缩小放在作品卡的 16:9 画框里 —— 颜色靠卡上的 --album / --album-2 传进来。 */
.work--folder .work__frame {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(155deg, #FCFAF5 0%, #F1EADD 100%);
  border-color: #E6DCC9;
}
.work--folder .album__shape { width: min(100%, 190px); margin: 0; }
.work--folder:hover .album__front { transform: rotateX(-20deg); }   /* 悬停时掀一下，暗示「能点进去」 */

/* ---------- 七之三、报道汇总页的文档瀑布流（2026-09-17 加）----------
   37 张报道截图的比例差很多（0.2 ~ 2.1），用固定格子会被裁得没法读，
   所以用 CSS 多列做瀑布流：每张按自己的比例排，不裁一像素。
   点开走灯箱看大图。 */
.reports { columns: 3; column-gap: 16px; margin: 24px 0 8px; }
.reports figure { break-inside: avoid; margin: 0 0 16px; }
.reports a {
  display: block;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface);
  cursor: zoom-in;
}
.reports img { display: block; width: 100%; height: auto; }
.reports figcaption {
  margin-top: 6px;
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: .06em;
}
/* 报道汇总页底部的说明行 */
.reports__note { margin: 18px 0 0; color: var(--ink-3); font-size: 13.5px; line-height: 1.8; }
/* 正文里的配图（评论页的「发表页面存档」） */
.article__figure { margin: 34px 0; }
.article__figure a { display: block; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; cursor: zoom-in; }
.article__figure img { display: block; width: 100%; height: auto; }
.article__figure figcaption { margin-top: 8px; color: var(--ink-3); font-size: 13px; }
/* 文章里的实拍配图：比正文列窄一点、居中。
   原因：这几张原图只有 568–738px 宽，铺满 780px 的正文列会被放大约 10–37%，
   在高分屏上发虚；收到 640px 反而比原图略小或持平，看起来是「杂志式配图」。 */
.article__figure--photo { max-width: 640px; margin-inline: auto; }

/* 文案作品的分段呈现（2026-09-18 加，用在 RIO 广告文案那页）。
   四段文案按 2×2 排，每段一张浅底卡片、左侧一道砖红细线做标记 ——
   和站内「引用块」的语言一致，不用新颜色。
   手机（≤680px）降成单列。 */
.copyverse {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 6px;
}
.copyverse__item {
  position: relative;
  margin: 0;
  padding: 24px 26px 24px 30px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.copyverse__item::before {
  content: '';
  position: absolute;
  left: 0; top: 20px; bottom: 20px;
  width: 2px;
  border-radius: 2px;
  background: var(--accent);
}
.copyverse__season {
  margin: 0 0 12px;
  color: var(--accent);
  font-size: 12.5px;
  letter-spacing: .14em;
}
.copyverse__lines {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: 16.5px;
  line-height: 2;
}
@media (max-width: 680px) {
  .copyverse { grid-template-columns: 1fr; gap: 12px; }
  .copyverse__item { padding: 20px 20px 20px 24px; }
}

/* 竖版的证书 / 文件类配图：比照片更窄，避免被放大到超过原尺寸而发虚。 */
.article__figure--portrait { max-width: 430px; margin-inline: auto; }

/* 「去看外部作品」的行动块（2026-09-18 加，用在 H5 作品页）。
   宽度**必须和上面的作品封面一样宽（430px，见 .article__figure--portrait）** ——
   这样封面、按钮、说明文字三者共用同一条左边缘，看着才是一组。
   说明文字在这个宽度下刚好排两行；之前它贴在全宽正文列左边排成一行超长小字，
   又贴着按钮，用户反馈「布局不合理」。 */
.work-cta { max-width: 430px; margin: 24px auto 56px; }
.work-cta .xp__more { margin-top: 0; }   /* .xp__more 自带 margin-top:18px，这里由容器给间距 */
.work-cta__note { margin: 14px 0 0; color: var(--ink-3); font-size: 13px; line-height: 1.85; }
.article__credit { margin: -6px 0 0; color: var(--ink-3); font-size: 13.5px; }

@media (max-width: 980px) { .reports { columns: 2; } }
@media (max-width: 680px) { .reports { columns: 2; column-gap: 10px; } .reports figure { margin-bottom: 10px; } }

/* ---------- 八、窄屏适配 ---------- */
/* 断点为什么是 1100 而不是 900：
   两列布局下照片框的高度是被右侧正文撑出来的（不是自己定的），
   在 1000px 附近正文换行变多、框被撑到 1.25:1 ——
   对那张 3×3 拼图来说等于左右各裁掉 8.5%，外侧两列的人脸可能被切。
   放到 1100px 就单列，照片框用 aspect-ratio 自己定比例，一点不裁。 */
@media (max-width: 1100px) {
  .card--feature { grid-template-columns: 1fr; }
  .card--feature .card__body { padding: 28px 26px 24px; }
}
@media (max-width: 680px) {
  .albums { grid-template-columns: repeat(2, 1fr); gap: 26px 12px; }
  .album__shape { width: min(100%, 146px); margin-bottom: 12px; }
  .album__name { font-size: 12.5px; min-height: 2.9em; }
  .works { grid-template-columns: 1fr; }
  .photomosaic { grid-template-columns: repeat(2, 1fr); }
  .photomosaic a.is-portrait { grid-row: span 1; aspect-ratio: 4 / 3; }
  .photomosaic a.is-wide { grid-column: span 2; }
}
@media (prefers-reduced-motion: reduce) {
  .album__front, .album__paper, .album__shape, .work__frame img, .photomosaic img { transition: none; }
}


/* 收尾区 · 竖屏（手机）：换竖版原图整张。
   竖屏窗口比例（约 0.48）比原图（0.75）更瘦 → cover 按**高度**铺满、裁左右，
   所以用 background-position-x 控制取景：把偏右的人物挪到画面中间。
   ⚠️ 别和「字号收窄」合成一条媒体查询 —— 那样「窄但横屏」的窗口会套错。 */
@media (max-aspect-ratio: 4 / 5) {
  .contact {
    padding: 100px 20px;
    background-image: url("images/contact-bg-mobile.jpg?v=44");
    background-position: 42% center;
    /* 字号收一档：窄屏上一行要放得下「如果你也相信好内容值得被认真制作，」这 17 个字
       （390 容器 / 22px 只放得下 15 个 → 会把「我们」拆成两行）。
       20px 时 342 ÷ 20 ≈ 17，断点正好落在「我们可以聊聊。」之前。 */
  }

  /* ⚠️ 必须写在 .contact__title 上，不能写在 .contact 上 ——
     .contact__title 自己有 font-size 声明，会把继承下来的盖掉（第一次就是这么白改的）。 */
  .contact__title { font-size: clamp(18px, 4.65vw, 22px); }

  /* 竖屏的取景和桌面不同（人物偏左，文字右半会落在偏亮的海面上）——
     实测白字对比度只有 2.90（桌面 3.18）。所以这档单独把中间的柔光加厚、拉宽。
     ⚠️ 只加手机这档，桌面不动 —— 桌面本来就够，再压就暗过头了。 */
  .contact::before {
    background:
      linear-gradient(180deg, rgba(8, 10, 14, .74) 0%, rgba(8, 10, 14, .30) 11%,
                              rgba(8, 10, 14, .10) 20%, rgba(8, 10, 14, 0) 30%),
      linear-gradient(0deg,   rgba(8, 10, 14, .66) 0%, rgba(8, 10, 14, .18) 18%,
                              rgba(8, 10, 14, 0) 32%),
      radial-gradient(ellipse 80% 32% at 50% 48%,
                      rgba(8, 10, 14, .62) 0%, rgba(8, 10, 14, .34) 60%, rgba(8, 10, 14, 0) 100%);
  }
}

/* ---------- 九、首页开场动画：Hello, You!（2026-09-18，09-19 换 ReactBits 风）----------

   首页一进来先播这段，约 2.7 秒后淡出，露出下面原来的照片首屏。

   两个效果都来自 ReactBits（reactbits.dev），**但全是复刻、不是引库**：
     · 文字 → BlurText（text-animations/blur-text）
     · 背景 → Prism（backgrounds/prism）
   这个站是纯静态 HTML + 原生 JS、没有构建工具：BlurText 依赖 React + framer-motion，
   Prism 依赖 React + ogl，**一个都引不进来**。所以照着它们的源码把参数抄过来重写：
   BlurText 用 CSS keyframes，Prism 用**原生 WebGL**（手写约 150 行，见 boot.js）。

   ⛔ 幕布（.boot）**不在 index.html 里**，是 boot.js 运行时插进来的：
      写死在 HTML 里的话，JS 一旦没跑起来，这块深色幕布会永远盖住整站。

   层级（从下到上）：Prism canvas → 兜底光晕 → 颗粒 → 暗角 → 文字
   ⚠️ canvas / 兜底光晕 / 颗粒 三者关系见下面「WebGL 兜底」那段注释。 */


/* 开场期间：底色先变深（免得先闪一下浅色的首屏），并锁住滚动。
   这个 class 由 index.html 的 <head> 里那段内联脚本加上，boot.js 收场时摘掉。 */
html.is-booting { background: #080D0B; }
html.is-booting body { overflow: hidden; }

.boot {
  position: fixed;
  inset: 0;
  z-index: 120;              /* 高于顶部导航（60）与灯箱（100）*/
  display: grid;
  place-items: center;
  overflow: hidden;
  background: #080D0B;
  transition: opacity .64s ease, transform .64s ease;
}
/* 收场：整体淡出 + 往上飘走。时长要和 boot.js 里的 FADE 对上 */
.boot.is-done {
  opacity: 0;
  transform: translateY(-16px);
  pointer-events: none;
}

/* ---------- Prism 背景（WebGL canvas）----------
   Prism 是个跑 raymarching 的 fragment shader：一个缓慢旋转的「光棱锥」，
   靠 100 步步进累加辉光。颜色由 shader 里的 sin() 三通道决定（青蓝/品红/暖黄那套）。
   参数在 boot.js 顶部的 PRISM 常量里，改那儿。 */
.boot canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

/* 连带着的两层装饰（都在 canvas 之上） */
.boot__vignette,
.boot__glow,
.boot__grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* ---------- WebGL 兜底 ----------
   ⛔ 下面两层的 display 是**反的**：默认藏起来，只有 WebGL 起不来时才露出来。
      boot.js 里 createPrism() 失败（浏览器不支持 / 被禁用 / 上下文丢失）会给幕布
      加 .boot--no-gl，那时才显示原来的 CSS 渐变光门 + 颗粒。
      这样「最坏情况」不是黑屏，而是回到 09-18 那版的样子。 */
.boot__glow,
.boot__grain { display: none; }
.boot--no-gl .boot__glow,
.boot--no-gl .boot__grain { display: block; }

/* 兜底光门：拱形光边是主角（根在下方 86%、往上收成拱）。
   过渡带不能太宽（46%→58%→66%→76%），太宽就糊成一团雾。 */
.boot__glow {
  inset: -16%;
  background:
    radial-gradient(34% 26% at 50% 32%, rgba(234, 227, 172, .44), rgba(234, 227, 172, 0) 72%),
    radial-gradient(46% 40% at 50% 30%, rgba(150, 205, 170, .18), rgba(150, 205, 170, 0) 78%),
    radial-gradient(52% 72% at 50% 86%, rgba(0, 0, 0, 0) 44%, rgba(126, 200, 198, .44) 57%, rgba(182, 228, 216, .22) 66%, rgba(0, 0, 0, 0) 77%),
    radial-gradient(28% 52% at 16% 58%, rgba(88, 150, 190, .30), rgba(88, 150, 190, 0) 72%),
    radial-gradient(28% 52% at 84% 58%, rgba(88, 150, 190, .28), rgba(88, 150, 190, 0) 72%),
    radial-gradient(44% 20% at 50% 98%, rgba(96, 150, 170, .18), rgba(96, 150, 170, 0) 78%);
  filter: blur(22px);
  transform-origin: 50% 62%;
  animation: boot-breathe 7s ease-in-out infinite;
}
@keyframes boot-breathe {
  0%, 100% { transform: scale(1);    opacity: .88; }
  50%      { transform: scale(1.07); opacity: 1; }
}

/* 兜底颗粒：内联 SVG 噪点，不发请求。Prism 自带 noise（uNoise=.55），
   所以正常路径下这层是藏着的，只有回退时才需要它 */
.boot__grain {
  opacity: .05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* 暗角：把四周压下去，让中间那束光更亮、文字更跳。
   ⚠️ 压太狠会把棱镜的光边一起吃掉 —— .78 那版就是糊掉的原因。这里用**椭圆**
      （ellipse 78% 52%）而不是 circle：圆形的半径在同一比例下是恒定的，
      换到竖屏时纵向距离被拉长，画面大半会掉进暗区，整个开场变灰。
      ⚠️ 完全不压也不行：Prism 底部那道亮带会过曝成一片死白。 */
.boot__vignette {
  background:
    radial-gradient(ellipse 78% 54% at 50% 48%,
      rgba(8, 13, 11, 0), rgba(8, 13, 11, .22) 58%, rgba(8, 13, 11, .70) 100%),
    linear-gradient(180deg, rgba(8, 13, 11, .22) 0%, rgba(8, 13, 11, 0) 30%, rgba(8, 13, 11, .40) 100%);
}

/* 竖屏（手机）：画面窄而高，同样的暗角会压掉更多面积 —— 单独再放轻一档，
   让手机上的亮度追平桌面。判据用宽高比而不是宽度：横屏手机/小平板也走这条。 */
@media (max-aspect-ratio: 3 / 4) {
  .boot__vignette {
    background:
      radial-gradient(ellipse 92% 62% at 50% 46%,
        rgba(8, 13, 11, 0), rgba(8, 13, 11, .12) 62%, rgba(8, 13, 11, .56) 100%),
      linear-gradient(180deg, rgba(8, 13, 11, .14) 0%, rgba(8, 13, 11, 0) 32%, rgba(8, 13, 11, .30) 100%);
  }
}

/* ---------- 文字：BlurText 复刻 ----------
   ReactBits 的 BlurText 是「逐段做 模糊→半清→全清 + 从上往下落」，三段关键帧、
   线性缓动、每段之间串一点延迟。JS 那边（framer-motion）做的事，这里用 CSS keyframes + --i 实现。

   原文参数（BlurText.jsx 默认值，direction='top'）：
     from: { filter: 'blur(10px)', opacity: 0, y: -50 }
     to:   [ { filter: 'blur(5px)', opacity: .5, y: 5 },
             { filter: 'blur(0px)', opacity: 1,  y: 0 } ]
     stepDuration: .35s → 总时长 = .35 × 2 = .7s，times = [0, .5, 1]
     easing: t => t（线性）        delay: 每段之间（见 boot.js 的 STAGGER）

   ⛔ 这里不用 flex，用普通行内流 —— flex 换行会从任意一个字断开
      （窄屏上可能变成「Hel / lo,」）；行内流才会按词换行。
   ⛔ 也不要 rotateX/perspective 了：BlurText 只有位移 + 模糊，没有翻转。 */
.boot__text {
  position: relative;
  z-index: 2;
  margin: 0;
  padding: 0 26px;
  max-width: 100%;
  text-align: center;
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: clamp(38px, 9.5vw, 118px);
  line-height: 1.22;         /* 比原来松一点：字是从上方 blur 落下来的，行高太紧会碰到 */
  letter-spacing: -.015em;
  color: #F8F7F2;
  text-shadow: 0 14px 46px rgba(0, 0, 0, .45);
}
.boot__char {
  display: inline-block;
  opacity: 0;
  transform: translateY(-50px);
  filter: blur(10px);
  animation: boot-blur-char .7s linear both;
  animation-delay: calc(var(--i) * var(--stagger, 100ms));
}
/* 三段关键帧 = BlurText 的 from → 中间站 → 终点 */
@keyframes boot-blur-char {
  0%   { filter: blur(10px); opacity: 0;   transform: translateY(-50px); }
  50%  { filter: blur(5px);  opacity: .5;  transform: translateY(5px); }
  100% { filter: blur(0px);  opacity: 1;   transform: translateY(0); }
}

@media (max-width: 680px) {
  .boot__text { font-size: clamp(34px, 13vw, 62px); letter-spacing: -.01em; }
}

/* 不想看动画的人：整块不出现（index.html 的 <head> 里其实已经拦掉了，这里是第二道保险）
   ⚠️ 单纯 display:none 会让 canvas 不被创建 —— 正好，省掉一次 WebGL 初始化 */
@media (prefers-reduced-motion: reduce) {
  .boot { display: none; }
}
