/* ============================================================
   淡蓝底 · 多彩光晕 · clm-website
   ------------------------------------------------------------
   调参速查：
   · 蓝底深浅       → 改 --paper
   · 卡片底色       → 改 .info-section 的 background 渐变色
   · 卡片边框颜色   → 改 .go1 / .go2 / .go3 的 --edge-a / --edge-b
   · 光晕太花       → 改 body::before 四团光的透明度
   · 流星太抢眼     → 改 .meteors span 渐变里的 .95
   · 跟随光晕太亮   → 改 .cursor-glow 里的 .28 / .16
   ============================================================ */

:root {
  --paper: #e9f2fc;
  --card: #ffffff;
  /* 只给三张图片卡片的"白色相框"用 */
  --ink: #1e2b3a;
  --ink-dim: #5f7590;
  --go: #00add8;
  --purple: #8b5cf6;
  --green: #22c55e;
  --amber: #f0a92e;
  --border: rgba(34, 48, 63, .10);
  --dot: rgba(70, 110, 160, .12);
}

html {
  scroll-behavior: smooth;
  /* 底色放 html 上，body 的 ::before/::after 负层级装饰层才能正确压在上面 */
  background-color: var(--paper);
  scrollbar-color: rgba(30, 90, 150, .25) transparent;
}

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

body {
  min-height: 100vh;
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
  overflow-x: hidden;
}

/* ============================================================
   交互反馈：触碰任意可交互元素 → 蓝色闪光一下
   ------------------------------------------------------------
   【难点 1】为什么用 filter: drop-shadow 而不是 box-shadow？
   1. box-shadow 只会画矩形，用在圆形头像、胶囊标签上会露出方角；
      drop-shadow 跟随元素真实形状（含 border-radius），贴合得多。
   2. <img> 是替换元素，挂不了 ::before/::after 伪元素，
      "用伪元素画扩散光环"那套写法对头像、卡片图、gopher 全失效；
      drop-shadow 对 img 直接生效。
   3. 它不占用 box-shadow 属性，元素原有的悬浮阴影可以照常保留。

   animation-iteration-count 默认是 1，
   所以鼠标一移上去只闪一次，不会一直循环闪烁。
   ============================================================ */
@keyframes blueBlink {
  0% {
    filter: drop-shadow(0 0 0 rgba(0, 173, 216, 0));
  }

  35% {
    filter: drop-shadow(0 0 12px rgba(0, 173, 216, .95));
  }

  100% {
    filter: drop-shadow(0 0 0 rgba(0, 173, 216, 0));
  }
}

/* ============================================================
   背景层 1：四团彩色光晕
   ------------------------------------------------------------
   透明度都在 .17~.30 —— 低于 .15 看不出来，高于 .35 会糊成彩虹。
   ============================================================ */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  /* 不加 pointer-events 的话整页点不动 */
  background:
    radial-gradient(ellipse 58% 48% at 8% 0%, rgba(139, 92, 246, .26), transparent 62%),
    radial-gradient(ellipse 55% 50% at 96% 6%, rgba(0, 173, 216, .30), transparent 62%),
    radial-gradient(ellipse 62% 52% at 52% 102%, rgba(34, 197, 94, .22), transparent 62%),
    radial-gradient(ellipse 45% 38% at 78% 52%, rgba(240, 169, 46, .17), transparent 68%);
}

/* ============================================================
   背景层 2：点阵
   ------------------------------------------------------------
   【难点 2】为什么用 radial-gradient 画点，不贴点阵图？
   矢量效果，任何缩放/像素密度下都锐利，而且 0 字节。

   【难点 3】mask 必须写 -webkit- 前缀。
   Safari 至今不认无前缀的 mask-image，只写一行的话点阵会铺满全屏，
   丢掉"中间清晰、四周淡出"的层次。
   ============================================================ */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: radial-gradient(var(--dot) 1.2px, transparent 1.2px);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(ellipse 85% 80% at 50% 30%, #000 30%, transparent 100%);
  mask-image: radial-gradient(ellipse 85% 80% at 50% 30%, #000 30%, transparent 100%);
}

/* ============================================================
   跟随鼠标的柔光
   ------------------------------------------------------------
   【难点 4】宽度写 520px，但 margin 用 -260px（正好一半）。
   这样元素的【中心】才会对准鼠标，
   否则光晕的左上角贴着鼠标，看起来偏一大截。
   也可以用 translate(-50%,-50%)，但那会和 JS 写入的 transform
   打架（后者覆盖前者），所以用负 margin 更稳。
   ============================================================ */
.cursor-glow {
  position: fixed;
  top: 0;
  left: 0;
  width: 520px;
  height: 520px;
  margin: -260px 0 0 -260px;
  border-radius: 50%;
  pointer-events: none;
  z-index: -1;
  opacity: 0;
  transition: opacity 0.6s ease;
  background: radial-gradient(circle,
      rgba(0, 173, 216, .28),
      rgba(139, 92, 246, .16) 42%,
      transparent 70%);
  will-change: transform;
}

/* 触屏设备没有鼠标，光晕只会停在一个奇怪的位置，直接藏掉 */
@media (hover: none) {
  .cursor-glow {
    display: none;
  }
}

/* ============================================================
   顶部标题
   ============================================================ */
.header {
  position: relative;
  width: 100%;
  padding: 34px 0 0;
  text-align: center;
  animation: fadeDown 0.8s ease both;
}

@keyframes fadeDown {
  from {
    opacity: 0;
    transform: translateY(-14px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.header h1 {
  font-size: 50px;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.5px;
  color: var(--ink);
  cursor: pointer;
  /* 只写需要过渡的属性，不要写 all —— 见【难点 5】 */
  transition: transform 0.3s ease;
}

/* 【难点 5】transition: all 会和 animation 抢同一个属性。
   元素上写了 transition: all，hover 时又跑 blueBlink 动画，
   filter 会被两边同时接管，闪光的收尾会发虚。
   所以下面每个元素的 transition 都显式列属性。 */
.header h1:hover {
  transform: scale(1.04);
  background: linear-gradient(90deg, var(--go), var(--purple), var(--green), var(--go));
  background-size: 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* Safari 保险：只写 color 有些版本不生效 */
  -webkit-text-fill-color: transparent;
  /* 两个动画各管各的属性：blueBlink 管 filter，shimmer 管 background-position */
  animation: blueBlink 0.55s ease-out, shimmer 2.5s linear infinite;
}

/* 渐变首尾同色 + 尺寸 300% + 位移 0%→100%，三者凑齐才是无缝循环 */
@keyframes shimmer {
  from {
    background-position: 0% 50%;
  }

  to {
    background-position: 100% 50%;
  }
}

.tagline {
  margin-top: 10px;
  font-size: 16px;
  letter-spacing: 1px;
  color: var(--ink-dim);
}

/* ============================================================
   右上角：问候语 + 头像
   ------------------------------------------------------------
   .avater 原本只装一张图，现在改成 flex 横排，
   问候语排在头像左边，两个一起贴右上角。
   ============================================================ */
.header .avater {
  position: absolute;
  top: 10px;
  right: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.header .avater img {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid #fff;
  box-shadow: 0 2px 10px rgba(30, 60, 100, .18);
  cursor: pointer;
  transition: transform 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}

.header .avater img:hover {
  transform: scale(1.08);
  border-color: var(--go);
  box-shadow: 0 4px 16px rgba(0, 173, 216, .40);
  animation: blueBlink 0.55s ease-out;
}

.greeting {
  font-size: 13px;
  letter-spacing: 0.5px;
  color: var(--ink-dim);
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.25s ease;
}

.greeting:hover {
  color: var(--go);
  animation: blueBlink 0.55s ease-out;
}

/* 【难点 6】用 :empty 兜底。
   问候语是 JS 填进去的，万一 script.js 没加载成功，
   这里会留一个空 span 占着 gap 的 10px 宽度。
   用 :empty 让它在没内容时彻底消失。 */
.greeting:empty {
  display: none;
}

/* 【难点 7】为什么在 1200px 就收掉问候语，而不是等到手机断点？
   粗算一下：问候语最长那句约 220px，加上间隙和头像约 285px，
   而 50px 的英文标题「Welcome to clm-website」约 570px。
   两者要在 1170px 宽度时才会相撞，
   所以从 1200px 往下就提前藏掉，别等它真的压到标题上。
   （这些数字会随字体变化，改了字号要重新估） */
@media (max-width: 1200px) {
  .greeting {
    display: none;
  }
}

/* ============================================================
   左上角斜落的多彩流光
   ------------------------------------------------------------
   【难点 8】transform 的书写顺序决定了方向，最容易搞反。
   CSS 的 transform 从右往左作用：rotate(-30deg) translateY(...)
   表示"先位移、再旋转"，也就是位移发生在【已旋转的坐标系】里，
   所以 translateY 正值 = 沿斜线朝右下走。

   rotate(-30deg) 是逆时针，把竖线拧成 "\" 的朝向（左上 → 右下）。
   想改成从右上角落下，要换成 rotate(30deg) 的 "/"，符号一反就对了。

   【难点 9】基础态 opacity: 0 是有意的。
   这样浏览器不支持动画、或用户开了"减弱动态效果"时，
   线条是隐形的，不会留下一堆僵硬的静态斜线。
   ============================================================ */
.meteors {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  /* 裁掉飞出视口的尾巴 */
  pointer-events: none;
  /* 关键：不加会挡住下面所有点击 */
}

.meteors span {
  position: absolute;
  top: -25vh;
  width: 2.5px;
  border-radius: 999px;
  opacity: 0;
  will-change: transform, opacity;
  /* --c 是"逗号分隔的 RGB 值"，配合 rgba(var(--c), .95) 使用，
     每条流星只要在自己的 nth-child 里换一个 --c 就能换色 */
  background: linear-gradient(180deg,
      transparent 0%,
      rgba(var(--c), .05) 30%,
      rgba(var(--c), .55) 72%,
      rgba(var(--c), .95) 100%);
  box-shadow: 0 0 8px rgba(var(--c), .45);
  animation: meteorFall 6s linear infinite;
}

/* 【难点 10】伪元素做"亮头"。
   光有一条渐变线，看着像划痕；在末尾加一个发光的小圆点，
   才像一颗正在下坠的流星。span 是 absolute 定位，可以当包含块，
   所以这个 ::after 能直接用 bottom/left 定位。 */
.meteors span::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -1px;
  width: 5px;
  height: 5px;
  margin-left: -2.5px;
  border-radius: 50%;
  background: rgba(var(--c), 1);
  box-shadow: 0 0 10px rgba(var(--c), .9), 0 0 20px rgba(var(--c), .5);
}

/* 五条各自的位置、长度、颜色、速度、延迟全部错开，
   全写一样的话会像整齐的雨，很假 */
.meteors span:nth-child(1) {
  left: 5%;
  height: 180px;
  --c: 0, 173, 216;
  animation-duration: 6.0s;
  animation-delay: 0.0s;
}

.meteors span:nth-child(2) {
  left: 18%;
  height: 130px;
  --c: 139, 92, 246;
  animation-duration: 7.5s;
  animation-delay: 1.6s;
}

.meteors span:nth-child(3) {
  left: 2%;
  height: 220px;
  --c: 34, 197, 94;
  animation-duration: 5.5s;
  animation-delay: 3.2s;
}

.meteors span:nth-child(4) {
  left: 30%;
  height: 150px;
  --c: 240, 169, 46;
  animation-duration: 8.0s;
  animation-delay: 4.6s;
}

.meteors span:nth-child(5) {
  left: 12%;
  height: 110px;
  --c: 139, 92, 246;
  animation-duration: 6.8s;
  animation-delay: 6.2s;
}

@keyframes meteorFall {
  0% {
    transform: rotate(-30deg) translateY(0);
    opacity: 0;
  }

  /* 淡入，避免在顶部"凭空出现" */
  12% {
    opacity: 1;
  }

  72% {
    opacity: 1;
  }

  /* 淡出，避免在底部"啪"地消失 */
  100% {
    transform: rotate(-30deg) translateY(150vh);
    opacity: 0;
  }
}

/* ============================================================
   滚动淡入
   ------------------------------------------------------------
   基础态先藏起来（透明 + 下移），JS 观察到进入视口后加 .is-visible。
   注意：如果 JS 挂了，元素会永远藏住 —— 所以 script.js 里
   有一段兜底，2 秒后强制全部显示。这是渐进增强的基本礼貌。
   ============================================================ */
[data-reveal] {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

[data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* ============================================================
   三张图片卡片
   ============================================================ */
.center {
  display: flex;
  justify-content: space-between;
  margin: 50px 140px;
  flex-wrap: wrap;
  gap: 20px;
}

/* ------------------------------------------------------------
   每张卡片一组边框色，跟图片本身的主色调呼应
   （下面 .center>div 会读到这两个变量）
   ------------------------------------------------------------ */
.go1 {
  --edge-a: #00add8;
  --edge-b: #4f8ef7;
  /* 青 → 蓝 */
}

.go2 {
  --edge-a: #22c55e;
  --edge-b: #5eead4;
  /* 绿 → 青绿 */
}

.go3 {
  --edge-a: #8b5cf6;
  --edge-b: #f472b6;
  /* 紫 → 粉 */
}

/* ------------------------------------------------------------
   【难点 11】渐变边框的标准写法
   ------------------------------------------------------------
   普通 border 只能是一个纯色，想要"边框是渐变"必须绕一下：

   1. border: 2px solid transparent —— 边框本身透明，当"窗口"用
   2. 铺两层背景，各用不同的 background-clip：
      · 第一层纯白 → padding-box（只铺在内容+内边距区域）
      · 第二层渐变 → border-box（铺满含边框的整个区域）
   3. 结果是：白色盖住中间，渐变色只有边框那一圈透出来

   ⚠️ 这里不能再用 `background: var(--card)`，
      单层背景会盖住渐变，边框就成了透明的一条。
   ⚠️ var() 都写了兜底值，以后加新卡片忘了配 --edge-* 也不会崩。
   ------------------------------------------------------------ */
.center>div {
  width: 31%;
  padding: 8px;
  /* 留出内边距，让渐变边框有地方显形 */
  border-radius: 18px;
  border: 2px solid transparent;
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    linear-gradient(135deg, var(--edge-a, #00add8), var(--edge-b, #8b5cf6)) border-box;
  box-shadow:
    0 2px 8px rgba(30, 60, 100, .07),
    0 10px 24px rgba(30, 60, 100, .08);
  overflow: hidden;
  cursor: pointer;
  /* 卡片的 hover transform 和 [data-reveal] 的过渡要合到一起写，
     否则前者会覆盖后者，滚动淡入就失效了 */
  transition: transform 0.4s ease, opacity 0.7s ease,
    box-shadow 0.3s ease;
}

/* 【难点 12】阴影用带蓝调的 rgba(30,60,100) 而不是纯黑 rgba(0,0,0)。
   纯黑阴影投在淡蓝底上会发灰发脏，像蹭到的印子；
   换成同色系的蓝灰，阴影会"融进"背景里。 */
.center>div:hover {
  transform: translateY(-8px);
  box-shadow:
    0 4px 12px rgba(30, 60, 100, .09),
    0 16px 36px rgba(30, 60, 100, .15);
  animation: blueBlink 0.55s ease-out;
}

.center>div img {
  width: 100%;
  height: 320px;
  object-fit: cover;
  display: block;
  /* 消掉 inline 元素底部的幽灵间隙 */
  border-radius: 12px;
}

/* ============================================================
   【关于我 + 标签区域】
   ============================================================ */
.info-section {
  margin: 80px 140px;
  padding: 48px 40px;
  border-radius: 20px;
  border: 1px solid var(--border);
  box-shadow:
    0 2px 8px rgba(30, 60, 100, .07),
    0 10px 28px rgba(30, 60, 100, .08);
  /* 卡片底色：淡蓝 → 淡紫的柔和渐变。
     纯白压在淡蓝背景上对比太硬，像贴了张白纸；
     带色相的浅渐变才像"背景的一部分"。 */
  background: linear-gradient(155deg,
      #f4f9ff 0%,
      #eef5ff 48%,
      #f5f2ff 100%);
}

.about-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-bottom: 32px;
}

.about-head h2 {
  font-size: 32px;
  letter-spacing: 1px;
  color: var(--ink);
  cursor: pointer;
}

.about-head h2:hover {
  animation: blueBlink 0.55s ease-out;
}

/* ------------------------------------------------------------
   gopher + 它下面那行小提示
   ------------------------------------------------------------
   用一列 flex 把图和字绑在一起，
   这样 .about-head 里"标题 + 这一坨"整体居中就行，
   不用去算 gopher 的绝对位置。
   ------------------------------------------------------------ */
.mascot-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
}

.mascot {
  width: 72px;
  height: 72px;
  /* 给 SVG 用是无害的，留着以防哪天换回 PNG */
  object-fit: contain;
  cursor: pointer;
  animation: mascotFloat 4s ease-in-out infinite;
}

/* hover 时必须把 mascotFloat 一起写回来，
   否则 animation 属性被覆盖，gopher 会突然停在半空不飘了 */
.mascot:hover {
  animation: blueBlink 0.55s ease-out, mascotFloat 4s ease-in-out infinite;
}

@keyframes mascotFloat {

  0%,
  100% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(-6px);
  }
}

/* 「点我有惊喜」——呼吸式的明暗变化，
   比静态文字更容易让人注意到这里能点 */
.mascot-hint {
  font-size: 11px;
  letter-spacing: 0.5px;
  color: var(--ink-dim);
  white-space: nowrap;
  animation: hintPulse 2.4s ease-in-out infinite;
}

@keyframes hintPulse {

  0%,
  100% {
    opacity: .5;
  }

  50% {
    opacity: 1;
  }
}

/* ------------------------------------------------------------
   gopher 的对话框
   ------------------------------------------------------------
   【难点 13】为什么让它待在正常文档流里，而不是绝对定位挂在图上？
   绝对定位要考虑"挂在图上"就得算 gopher 的水平偏移
   （标题宽度一变，位置就跑），手机窄屏还会溢出卡片。
   放文档流里：不溢出、不用定位、桌面和手机一套代码通吃，
   代价只是没有那个指向 gopher 的小尖角 —— 划算。

   margin-top 用负值，把 .about-head 的 32px 下边距吃掉一半，
   让气泡凑近一点，不然中间空一大截。
   ------------------------------------------------------------ */
.mascot-bubble {
  display: none;
  max-width: 520px;
  margin: -14px auto 28px;
  padding: 12px 22px;
  border-radius: 14px;
  /* 边框用 gopher 的紫色，暗示"这是它说的" */
  background: #fff;
  border: 1px solid rgba(139, 92, 246, .28);
  box-shadow: 0 6px 20px rgba(30, 60, 100, .10);
  font-size: 14px;
  line-height: 1.7;
  color: var(--ink);
  text-align: center;
}

.mascot-bubble.is-open {
  display: block;
  animation: bubblePop 0.3s ease both;
}

@keyframes bubblePop {
  from {
    opacity: 0;
    transform: translateY(-8px) scale(.96);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* ------------------------------------------------------------
   自我介绍：左对齐 + 左侧竖线
   ------------------------------------------------------------
   全居中的大段文字读起来会散，加一条竖线立刻有了"引言"的分量，
   也跟上面居中的标题形成对比，页面才有层次。
   ------------------------------------------------------------ */
.intro {
  max-width: 520px;
  margin: 0 auto 40px;
  padding-left: 22px;
  border-left: 3px solid rgba(0, 173, 216, .35);
}

.intro p {
  font-size: 16px;
  line-height: 1.95;
  color: var(--ink);
}

.intro p+p {
  margin-top: 12px;
}

/* ------------------------------------------------------------
   作者信息：横排 meta 条
   ------------------------------------------------------------ */
.meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px 32px;
  list-style: none;
  margin-bottom: 40px;
}

.meta li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 15px;
  color: var(--ink);
  cursor: pointer;
  transition: color 0.25s ease;
}

.meta li span {
  font-size: 11px;
  letter-spacing: 1.5px;
  color: var(--ink-dim);
  text-transform: uppercase;
}

.meta li a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dashed rgba(0, 173, 216, .45);
}

.meta li:hover {
  color: var(--go);
  animation: blueBlink 0.55s ease-out;
}

/* ------------------------------------------------------------
   标签：按类别分组

   ⚠️ class 名还叫 tech-* —— 那只是 CSS 的样式钩子，
      跟内容是什么没关系。
   ------------------------------------------------------------ */
.tech-groups {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 28px 48px;
}

.tech-group h3 {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 2px;
  color: var(--ink-dim);
  text-align: center;
  margin-bottom: 12px;
}

.tech-stack {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

.tech-tag {
  padding: 8px 18px;
  background: rgba(0, 173, 216, .10);
  color: #0a6c88;
  /* 浅底上必须用深色字，直接用 --go 对比度不够 */
  border: 1px solid rgba(0, 173, 216, .28);
  border-radius: 999px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.25s ease, color 0.25s ease,
    border-color 0.25s ease, transform 0.25s ease, box-shadow 0.25s ease;
}

/* 偶数标签换紫色，跟左上角的紫流星呼应（不想要就删这两段） */
.tech-tag:nth-child(even) {
  background: rgba(139, 92, 246, .10);
  color: #6d3fd4;
  border-color: rgba(139, 92, 246, .28);
}

.tech-tag:hover {
  background: var(--go);
  color: #fff;
  border-color: var(--go);
  transform: translateY(-3px);
  box-shadow: 0 6px 16px rgba(0, 173, 216, .35);
  animation: blueBlink 0.55s ease-out;
}

.tech-tag:nth-child(even):hover {
  background: var(--purple);
  color: #fff;
  border-color: var(--purple);
  box-shadow: 0 6px 16px rgba(139, 92, 246, .40);
}

/* ============================================================
   页脚
   ============================================================ */
.site-footer {
  margin-top: 40px;
  padding: 0 140px 56px;
}

/* 渐变的分隔线，比一条实线柔和，两端自然消失 */
.footer-line {
  height: 1px;
  margin-bottom: 20px;
  background: linear-gradient(90deg,
      transparent,
      rgba(30, 90, 150, .20),
      transparent);
}

.copyright {
  text-align: center;
  font-size: 13px;
  color: var(--ink-dim);
  line-height: 1.9;
  letter-spacing: 0.5px;
}

/* ========== 细节打磨 ========== */
::selection {
  background: rgba(0, 173, 216, .25);
  color: var(--ink);
}

::-webkit-scrollbar {
  width: 10px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: rgba(30, 90, 150, .18);
  border-radius: 999px;
}

::-webkit-scrollbar-thumb:hover {
  background: rgba(30, 90, 150, .32);
}

/* ============================================================
   移动端适配 · 平板 / 手机
   ============================================================ */
@media (max-width: 768px) {

  /* --- 顶部 --- */
  .header {
    /* 顶部留出空间给绝对定位的头像，不然会压在标题上 */
    padding: 46px 20px 0;
  }

  .header h1 {
    font-size: 28px;
    line-height: 1.3;
  }

  .tagline {
    margin-top: 8px;
    font-size: 13px;
  }

  .header .avater {
    top: 8px;
    right: 12px;
  }

  .header .avater img {
    width: 40px;
    height: 40px;
  }

  /* --- 卡片 --- */
  .center {
    margin: 26px 20px;
    gap: 16px;
  }

  .center>div {
    width: 100%;
  }

  .center>div img {
    /* 桌面端 320px 在手机上太高，会把内容顶到屏幕外 */
    height: 230px;
  }

  /* --- 关于我 --- */
  .info-section {
    margin: 44px 20px;
    padding: 30px 20px;
    border-radius: 16px;
  }

  .about-head {
    margin-bottom: 24px;
  }

  .about-head h2 {
    font-size: 24px;
  }

  .mascot {
    width: 54px;
    height: 54px;
  }

  .mascot-bubble {
    max-width: 100%;
    margin: -8px auto 22px;
    padding: 11px 16px;
    font-size: 13px;
  }

  .intro {
    padding-left: 14px;
    margin-bottom: 30px;
  }

  .intro p {
    font-size: 15px;
    line-height: 1.85;
  }

  .meta {
    gap: 10px 20px;
    margin-bottom: 32px;
  }

  .meta li {
    font-size: 14px;
  }

  /* 标签组竖排，横排会挤成一团 */
  .tech-groups {
    flex-direction: column;
    gap: 22px;
  }

  /* --- 页脚 --- */
  .site-footer {
    margin-top: 26px;
    padding: 0 20px 40px;
  }

  .copyright {
    font-size: 12px;
  }

  /* --- 装饰层 --- */
  /* 手机上只留 3 条流星，少两条省电省性能 */
  .meteors span:nth-child(n + 4) {
    display: none;
  }
}

/* ============================================================
   移动端适配 · 小屏手机（iPhone SE 那一档，≤420px）
   ============================================================ */
@media (max-width: 420px) {

  .header h1 {
    font-size: 23px;
  }

  .center>div img {
    height: 200px;
  }

  .info-section {
    padding: 26px 16px;
  }

  .about-head h2 {
    font-size: 21px;
  }

  .mascot {
    width: 46px;
    height: 46px;
  }

  .intro p {
    font-size: 14px;
  }

  /* 邮箱在窄屏上是一长串没有空格的字符，
     浏览器不知道能在哪断行，会直接撑破容器 */
  .meta li a {
    word-break: break-all;
  }
}

/* ============================================================
   无障碍：系统开启「减弱动态效果」时关掉所有动画
   ============================================================ */
@media (prefers-reduced-motion: reduce) {

  .mascot,
  .header h1:hover,
  .mascot-hint {
    animation: none;
  }

  .meteors,
  .cursor-glow {
    display: none;
  }

  /* 闪光关掉，但保留颜色变化作为反馈 */
  .center>div:hover,
  .header .avater img:hover,
  .tech-tag:hover,
  .about-head h2:hover,
  .meta li:hover,
  .greeting:hover {
    animation: none;
  }

  /* 【难点 14】这一条是必须的。
     气泡、提示的入场动画一旦关掉，
     如果它们的基础态是 opacity: 0，就会永远看不见。
     所以减弱动效时直接让它们以最终形态出现。 */
  .mascot-bubble.is-open {
    animation: none;
  }

  .mascot-hint {
    opacity: .8;
  }

  /* 关键：滚动淡入也关掉，否则元素可能永远停在透明状态 */
  [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .header {
    animation: none;
  }
}