/* ==========================================================================
   components.css — 视觉组件
   --------------------------------------------------------------------------
   严格对齐 apanzinc.top 的组件实现：
     Hero（左下大 logo + 右下简介 + chips）
     卡片家族（project / friend / social / achievement）
     主内容进入动画
   ========================================================================== */

/* ==========================================================================
   1. 通用卡片
   --------------------------------------------------------------------------
   全部卡片共用一个基底：bg-secondary 底 + border 描边 + 4px 圆角。
   悬停只改"边框变主色 + 底色变亮"，不加位移、不加阴影 ——
   这是"克制"的体现，位移和阴影会立刻让页面变廉价。
   ========================================================================== */

.card {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color 0.2s var(--ease-out),
    background 0.2s var(--ease-out);
}

.card:hover {
  border-color: var(--accent);
  background: var(--bg-hover);
}

/* ==========================================================================
   2. 首页 Hero
   --------------------------------------------------------------------------
   布局：整体 flex:1 撑满可用高度，内容底对齐（align-items:flex-end）。
        左侧 flex:auto 放超大 logo，右侧固定 360px 放简介与 chips。

   为什么是底对齐而不是居中：底部对齐让大字"贴着地面"，
   配合上方大片留白（被 shader 光晕填充），产生"海报/专辑封面"的构图感。
   居中会显得平淡，像普通的 banner。
   ========================================================================== */

.home-page {
  flex-direction: column;
  flex: 1;
  width: 100%;
  height: 100%;
  min-height: 0;
  display: flex;
  overflow: hidden;
}

.hero {
  flex: 1;
  align-items: flex-end;
  width: 100%;
  height: 100%;
  min-height: 0;
  /* 负 margin + 等量 padding：让 shader 画布延伸到顶栏下方，
     但内容仍从顶栏之下开始。这是全屏背景 + 固定顶栏的标准解法。 */
  margin-top: -56px;
  padding: 56px 0 0;
  display: flex;
  position: relative;
  overflow: hidden;
}

/* ---------- shader 画布层 ---------- */
.hero-shader {
  z-index: 0;
  pointer-events: none;
  position: absolute;
  inset: 0;
}

/* canvas 用绝对定位铺满，而不是 width/height:100%。
   原因：canvas 在 flex/grid 容器里如果只写 100%，浏览器可能
   在首次布局时算出 0 高度（父级高度由 flex 决定，存在循环依赖），
   导致 WebGL 拿到 0×0 的画布、什么都画不出来。
   绝对定位 + inset:0 用的是"已解析的父级盒子"，没有这个问题。 */
.hero-shader canvas {
  display: block;
  position: absolute;
  inset: 0;
  width: 100% !important;
  height: 100% !important;
}

/* ---------- 遮罩层 ----------
   两层渐变：底部往上压暗（保证文字可读），左侧往右压暗（给 logo 让出背景）。
   8% → 42% 的过渡区间很关键：太陡会出现硬边，太缓则文字压在亮色上不可读。 */
.hero-veil {
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to top, var(--bg-primary) 8%, transparent 42%),
    linear-gradient(90deg, #00000059 0%, transparent 42%);
  position: absolute;
  inset: 0;
}

[data-theme="light"] .hero-veil {
  background: linear-gradient(to top, var(--bg-primary) 8%, transparent 42%),
    linear-gradient(90deg, #ffffff59 0%, transparent 42%);
}

/* ---------- 内容层 ---------- */
.hero-content {
  z-index: 2;
  box-sizing: border-box;
  justify-content: space-between;
  align-items: flex-end;
  gap: clamp(20px, 4vw, 64px);
  width: 100%;
  padding: 0 clamp(20px, 5vw, 64px);
  display: flex;
  position: relative;
}

.intro-left {
  flex: auto;
  min-width: 0;
}

/* 首屏字标：RobotoFlex 矢量字，宽度随视口伸缩，
   高度由 SVG viewBox 自动撑开（不做任何裁切）。 */
.hero-logo {
  width: clamp(200px, 50vw, 480px);
  color: var(--text-primary);
}

.hero-logo svg {
  width: 100%;
  height: auto;
  display: block;
  /* fill 用 currentColor 继承父级 color，主题切换时自动跟随 */
  color: var(--text-primary);
}

/* ---------- 右侧简介 ---------- */
.intro-right {
  text-align: right;
  flex: 0 360px;
  width: min(360px, 40%);
  min-width: 0;
  margin-left: auto;
}

/* 简介用 font-weight:300（细体）。
   在大片深色背景上，细体比常规体更"透气"，
   而且与左侧粗壮的 logo 形成对比，构图才不呆板。 */
.intro-bio {
  max-width: 100%;
  font-size: clamp(12px, 1.15vw, 15px);
  font-family: var(--font-sans);
  color: var(--text-primary);
  /* keep-all：禁止在词内断行，中文按标点断，英文按单词断。
     没有它，"AI驱动的" 这种中英混排会断得很难看。 */
  word-break: keep-all;
  opacity: 0;
  transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out);
  margin: 0;
  font-weight: 300;
  line-height: 1.65;
  transform: translateY(10px);
}

.bio-line {
  display: block;
}

/* 入场：由 JS 在挂载后加 .bio-visible */
.bio-visible {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- chips（关键词胶囊）---------- */
.hero-chips {
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  margin-top: clamp(12px, 1.5vw, 20px);
  display: flex;
}

.hero-chip {
  font-family: var(--font-sans);
  color: var(--text-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  opacity: 0;
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out),
    color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 450;
  text-decoration: none;
  transform: translateY(10px);
}

/* 逐个错开入场，由 JS 依次加 chip-visible */
.hero-chip.chip-visible {
  opacity: 1;
  transform: translateY(0);
}

.hero-chip:hover {
  color: var(--accent);
  border-color: var(--border-accent);
  background: var(--accent-glow);
}

[data-theme="light"] .hero-logo {
  color: var(--text-primary);
}

[data-theme="light"] .intro-bio {
  color: var(--text-secondary);
}

/* ==========================================================================
   3. 项目卡片
   --------------------------------------------------------------------------
   注意：用的也是 .corner-frame（四角边框），不是常规矩形描边。
   卡片内部结构：图标 + 名称（等宽字）在一行，描述在下。
   ========================================================================== */

.projects-section {
  padding: var(--spacing-lg) 0;
  margin: 0;
}

.projects-grid {
  gap: var(--spacing-sm);
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  width: 100%;
  display: grid;
}

.project-card {
  padding: var(--spacing-md);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color 0.2s var(--ease-out),
    background 0.2s var(--ease-out), transform 0.2s var(--ease-out);
  flex-direction: column;
  text-decoration: none;
  display: flex;
}

.project-card:hover {
  border-color: var(--accent);
  background: var(--bg-hover);
}

.project-header {
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
  display: flex;
}

.project-icon {
  color: var(--text-tertiary);
  flex-shrink: 0;
}

.project-name {
  font-family: var(--font-mono);
  color: var(--text-primary);
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.project-desc {
  color: var(--text-secondary);
  flex: 1;
  font-size: 14px;
  line-height: 1.6;
}

/* ==========================================================================
   4. 友链卡片
   -------------------------------------------------------------------------- */

.friend-section {
  padding: var(--spacing-lg) 0;
  margin: 0;
}

.friend-grid {
  gap: var(--spacing-sm);
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  width: 100%;
  display: grid;
}

.friend-link {
  align-items: center;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color 0.2s var(--ease-out),
    background 0.2s var(--ease-out), transform 0.2s var(--ease-out);
  height: 100%;
  display: flex;
}

.friend-link:hover {
  border-color: var(--accent);
  background: var(--bg-hover);
}

.friend-avatar {
  border: 1px solid var(--border);
  border-radius: 4px;
  flex-shrink: 0;
  width: 36px;
  height: 36px;
}

.friend-content {
  flex-direction: column;
  min-width: 0;
  display: flex;
}

/* 名字前自动加 @（用 :before 而不是写死在数据里） */
.friend-name {
  color: var(--text-primary);
  font-size: 14px;
  font-weight: 500;
  font-family: var(--font-mono);
}

.friend-name:before {
  content: "@";
  color: var(--accent);
  margin-right: 8px;
}

.friend-desc {
  color: var(--text-secondary);
  white-space: nowrap;
  text-overflow: ellipsis;
  margin-top: 2px;
  font-size: 13px;
  overflow: hidden;
}

/* ---------- 友链加载 / 错误态 ---------- */
.friend-loading,
.friend-error {
  width: 100%;
  padding: var(--spacing-md) var(--spacing-lg);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-top: var(--spacing-md);
  box-sizing: border-box;
  justify-content: space-between;
  align-items: center;
  display: flex;
}

.loading-left,
.error-left {
  align-items: center;
  gap: 10px;
  display: flex;
}

.loading-icon {
  color: var(--text-tertiary);
  flex-shrink: 0;
  animation: 1s linear infinite friend-spin;
  display: block;
}

.error-dot {
  background: #e74c3c;
  border-radius: 50%;
  flex-shrink: 0;
  width: 8px;
  height: 8px;
}

@keyframes friend-spin {
  0% {
    transform: rotate(0);
  }
  to {
    transform: rotate(360deg);
  }
}

.loading-text,
.error-text {
  color: var(--text-primary);
  font-size: 14px;
  line-height: 1;
}

.retry-btn {
  font-size: 13px;
  font-family: var(--font-mono);
  color: var(--text-primary);
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: all var(--transition-fast);
  padding: 8px 20px;
}

.retry-btn:hover {
  color: var(--accent);
  border-color: var(--accent);
}

@media (width <= 768px) {
  .friend-error {
    padding: var(--spacing-sm) var(--spacing-md);
  }

  .error-text {
    font-size: 13px;
  }

  .retry-btn {
    padding: 6px 16px;
    font-size: 12px;
  }
}

@media (width <= 480px) {
  .friend-name {
    word-break: break-word;
    font-size: 13px;
  }

  .friend-desc {
    font-size: 11px;
  }
}

/* ==========================================================================
   5. 社交链接卡片
   ========================================================================== */

.social-section {
  padding: var(--spacing-lg) 0;
  margin: 0;
}

.social-grid {
  gap: var(--spacing-sm);
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  display: grid;
}

.social-link {
  padding: var(--spacing-md);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color 0.2s var(--ease-out),
    background 0.2s var(--ease-out), transform 0.2s var(--ease-out);
  align-items: center;
  gap: 12px;
  display: flex;
}

.social-link:hover {
  border-color: var(--accent);
  background: var(--bg-hover);
}

.social-icon {
  color: var(--text-secondary);
  justify-content: center;
  align-items: center;
  display: flex;
}

.social-name {
  font-size: 14px;
  font-weight: 500;
  font-family: var(--font-mono);
  color: var(--text-primary);
}

.social-handle {
  color: var(--text-secondary);
  font-size: 13px;
  font-family: var(--font-mono);
}

.social-info {
  flex-direction: column;
  flex: 1;
  min-width: 0;
  display: flex;
}

/* 箭头默认隐藏，悬停才出现 —— 减少静态噪音 */
.social-arrow {
  color: var(--text-tertiary);
  opacity: 0;
  font-size: 14px;
}

.social-link:hover .social-arrow {
  opacity: 1;
}

/* ==========================================================================
   6. 成就列表
   --------------------------------------------------------------------------
   技巧：容器背景设成 --border，子项间隔 1px + 子项背景 --bg-secondary，
   这样 1px 的间隙会"漏出"背景色，自动形成分隔线。
   比给每个子项加 border-bottom 更干净（不会有最后一条多余的线）。
   ========================================================================== */

.achievement-section {
  padding: var(--spacing-lg) 0;
  margin: 0;
}

.achievement-list {
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  flex-direction: column;
  gap: 1px;
  display: flex;
  overflow: hidden;
}

.achievement-item {
  gap: var(--spacing-md);
  padding: var(--spacing-md);
  background: var(--bg-secondary);
  display: flex;
}

.achievement-marker {
  flex-shrink: 0;
  align-items: flex-start;
  width: 24px;
  padding-top: 4px;
  display: flex;
}

.marker-arrow {
  color: var(--accent);
  font-size: 14px;
}

.achievement-content {
  flex: 1;
}

.achievement-title {
  font-size: 16px;
  font-weight: 600;
  font-family: var(--font-mono);
  color: var(--text-primary);
  margin-bottom: 6px;
}

.achievement-desc {
  font-size: 14px;
  font-family: var(--font-sans);
  color: var(--text-secondary);
  margin-bottom: 10px;
  line-height: 1.6;
}

.achievement-meta {
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  display: flex;
}

.achievement-date {
  font-size: 12px;
  font-family: var(--font-mono);
  color: var(--text-tertiary);
  /* tabular-nums：数字等宽，多行日期能对齐 */
  font-variant-numeric: tabular-nums;
}

.achievement-tag {
  font-size: 11px;
  font-family: var(--font-mono);
  color: var(--accent);
  background: var(--accent-glow);
  border-radius: var(--radius-xs);
  letter-spacing: 0.05em;
  padding: 2px 8px;
}

/* 列表底部备注：右对齐、等宽小字、低对比度。
   不加 text-align 会默认左对齐，视觉上和上面的列表脱节。 */
.achievement-note {
  margin-top: var(--spacing-sm);
  text-align: right;
  font-size: 12px;
  font-family: var(--font-mono);
  color: var(--text-tertiary);
}

/* ==========================================================================
   6b. 经历 — 横向数轴（Gantt 式）
   --------------------------------------------------------------------------
   为什么是横向数轴而不是竖向时间轴：
     竖向时间轴只能表达"先后顺序"，时间段本身仍是一行文字（2024 — 2025），
     读者看不出哪段更久、哪段和别段重叠。横向数轴把年份映射成 X 坐标，
     每段的"起点 + 长度"就是它的真实时间范围 ——
     横条越长 = 持续越久，左边缘越靠左 = 开始越早。

   布局：两栏共用同一套 X 坐标系
     .axis-head  ┌ 左栏固定标签 ┐ ┌──── 刻度区（整条轴宽）────┐
     .axis-list  li: [ 文字信息 ] [ 横条区（整条轴宽）        ]
   刻度区和每条横条区都用同一个 grid 模板（--info-col + 1fr），
   百分比的零点因此严格对齐 —— 这是"刻度和横条必须对得上"的关键，
   也是上一版把横条放进右侧栅格列后整排横条往右漂的原因。

   ========================================================================== */

.experience-section {
  padding: var(--spacing-lg) 0;
  margin: 0;
}

/* 左栏宽度：放得下标题 + 角色标签即可，不必太宽。
   太宽会把右栏数轴压窄，横条的相对长度就不好比较了。 */
.axis {
  --info-col: 268px;
  --axis-gap: var(--spacing-lg);
  position: relative;
  width: 100%;
  margin-top: var(--spacing-md);
}

/* ==========================================================================
   顶部刻度行
   ========================================================================== */

.axis-head {
  display: grid;
  grid-template-columns: var(--info-col) 1fr;
  column-gap: var(--axis-gap);
  align-items: end;
  padding-bottom: 8px;
}

.axis-head-label {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-tertiary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* 和刻度文字同一基线 */
  line-height: 1;
}

/* 刻度区：相对定位，子项按 --p 百分比绝对落位 */
.axis-ticks {
  position: relative;
  height: 14px;
}

.axis-tick {
  position: absolute;
  left: var(--p);
  /* 居中对准自己的刻度线；首尾改为向内对齐，避免溢出被裁 */
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  line-height: 1;
  white-space: nowrap;
}

.axis-tick.tick-first {
  transform: translateX(0);
}

.axis-tick.tick-last {
  transform: translateX(-100%);
}

/* ==========================================================================
   数轴主体
   ========================================================================== */

.axis-body {
  position: relative;
}

/* 网格线层：铺满整个条目区，每个刻度一条 1px 淡线。
   放在单独的绝对定位层里，而不是给每个 li 加背景，
   这样线能连续贯穿所有行的上下 padding。 */
.axis-grid {
  position: absolute;
  top: 0;
  bottom: 0;
  /* 严格对齐横条区 */
  left: calc(var(--info-col) + var(--axis-gap));
  right: 0;
  pointer-events: none;
  z-index: 0;
}

.axis-gridline {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--p);
  width: 1px;
  background: var(--border);
  /* 网格线要比横条淡，否则抢主体 */
  opacity: 0.6;
}

/* 首尾两条网格线加实一点，作为数轴的"端点" */
.axis-gridline:first-child,
.axis-gridline:last-child {
  opacity: 1;
}

.axis-list {
  position: relative;
  z-index: 1;
  margin: 0;
  padding: 0;
  list-style: none;
  /* 顶部一条横线 = 数轴主线 */
  border-top: 1px solid var(--border);
}

/* ==========================================================================
   单条
   ========================================================================== */

.timeline-item {
  display: grid;
  grid-template-columns: var(--info-col) 1fr;
  column-gap: var(--axis-gap);
  /* 数轴要"对齐到同一条水平中轴"才能互相比较长度，
     所以这里不能用 stretch，必须 center。
     行的实际高度由左栏文字决定，横条在行内垂直居中。 */
  align-items: center;
  padding: var(--spacing-sm) 0;
  border-bottom: 1px solid var(--border);
  min-height: 84px;
}

.timeline-item:last-child {
  border-bottom: none;
  padding-bottom: var(--spacing-sm);
}

/* ---------- 左栏文字 ---------- */
.timeline-info {
  min-width: 0;
}

.timeline-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 6px;
}

.timeline-title {
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.01em;
  line-height: 1.45;
  margin: 0;
  text-wrap: balance;
}

.timeline-role {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  padding: 1px 7px;
  letter-spacing: 0.02em;
  white-space: nowrap;
  transform: translateY(-1px);
}

/* 时间文本跟在标题后面，等宽 + 主色，和横条上的信息重复但更易读 */
.timeline-period {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--accent-dim);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.timeline-desc {
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.55;
  margin: 0;
  /* 描述限 2 行，避免单条把整行撑到 190px 高，
     那样相邻横条的垂直距离太远，长度就没法比较了。
     完整文字保留在 DOM 里（title 属性 + 读屏可读）。 */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.timeline-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

.timeline-tag {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--accent);
  background: var(--accent-glow);
  border-radius: var(--radius-xs);
  padding: 2px 8px;
  letter-spacing: 0.05em;
}

/* ---------- 右栏：一条横条 ----------
   单元本身相对定位，宽度 = 整条轴宽；百分比零点与顶部刻度完全一致。 */
.timeline-axis-cell {
  position: relative;
  height: 30px;
  min-width: 0;
}

.timeline-bar {
  position: absolute;
  left: var(--l);
  width: var(--w);
  top: 0;
  bottom: 0;
  /* 极短区间（半年）也要看得见 */
  min-width: 4px;
  border-radius: var(--radius-sm);
  /* 横条是这一页的主角，必须明显比背景亮一档。
     实测：rgba(255,255,255,.085) 叠在 #000 上只得到 RGB 19-21，
     几乎和纯黑无异 —— 所以这里提到 .22/.13，
     在深色主题下约 RGB 45-55，既看得见又不刺眼。 */
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.22),
    rgba(255, 255, 255, 0.13)
  );
  border: 1px solid #3a3a3a;
  box-sizing: border-box;
  transition: border-color 0.25s var(--ease-out),
    background 0.25s var(--ease-out);
}

/* 浅色主题：白色叠加在 #f8f8f8 上等于没画，改用深色叠加。
   横条要比页面底色"暗"一档，才能在同为浅色的背景下浮出来。 */
[data-theme="light"] .timeline-bar {
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.085),
    rgba(0, 0, 0, 0.045)
  );
  border-color: #cfcfcf;
}

/* 左端一条 2px 主色竖条 = 起点。
   区间最需要被读到的信息是"从什么时候开始"，给起点一个明确的视觉锚。 */
.timeline-bar:before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--accent-dim);
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  transition: background 0.25s var(--ease-out);
}

/* 右端一个向内的细刻线 = 终点（开口条会隐藏它） */
.timeline-bar:after {
  content: "";
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--border);
  transition: background 0.25s var(--ease-out);
}

.timeline-item:hover .timeline-bar:before {
  background: var(--accent);
}

.timeline-item:hover .timeline-bar:after {
  background: var(--border-accent);
}

.timeline-item:hover .timeline-bar {
  border-color: var(--border-accent);
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.28),
    rgba(255, 255, 255, 0.18)
  );
}

[data-theme="light"] .timeline-item:hover .timeline-bar {
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.12),
    rgba(0, 0, 0, 0.07)
  );
}

/* ---------- "至今"的开口横条 ----------
   右端不做圆角 + 渐隐 = 还没结束、仍在延伸。
   这是时间轴上表达 open-ended 的通用画法。 */
.timeline-item-open .timeline-bar {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right-color: transparent;
  background: linear-gradient(
    to right,
    rgba(255, 255, 255, 0.22) 0%,
    rgba(255, 255, 255, 0.16) 55%,
    rgba(255, 255, 255, 0) 100%
  );
}

[data-theme="light"] .timeline-item-open .timeline-bar {
  background: linear-gradient(
    to right,
    rgba(0, 0, 0, 0.085) 0%,
    rgba(0, 0, 0, 0.06) 55%,
    rgba(0, 0, 0, 0) 100%
  );
}

/* 开口端不画右侧终止线（它没有终点） */
.timeline-item-open .timeline-bar:after {
  display: none;
}

/* ---------- 当前进行中 ----------
   只有"至今"这一条上主色，作为整条数轴的视觉落点。
   全部上色会失去重点。
   注意：这条规则要写在 open 之后，否则"至今"的开口渐隐会覆盖主色。 */
.timeline-item-current .timeline-bar {
  border-color: var(--border-accent);
  background: linear-gradient(
    to right,
    color-mix(in srgb, var(--accent) 26%, transparent) 0%,
    color-mix(in srgb, var(--accent) 10%, transparent) 55%,
    transparent 100%
  );
}

.timeline-item-current .timeline-bar:before {
  background: var(--accent);
}

.timeline-item-current .timeline-period {
  color: var(--accent);
}

.timeline-item-current .timeline-title {
  color: var(--text-primary);
}

/* 底部备注：与成就 / 文章页同一层级（右对齐、等宽小字、低对比） */
.timeline-note {
  margin-top: var(--spacing-md);
  text-align: right;
  font-size: 12px;
  font-family: var(--font-mono);
  color: var(--text-tertiary);
}

/* ==========================================================================
   7. 文章列表
   --------------------------------------------------------------------------
   结构：固定宽度日期列 + 标题/摘要。
   与成就列表共用「1px 间隙当分隔线」的做法，视觉上属于同一家族。
   ========================================================================== */

.post-section {
  padding: var(--spacing-lg) 0;
  margin: 0;
}

.post-list {
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  flex-direction: column;
  gap: 1px;
  display: flex;
  overflow: hidden;
}

.post-item {
  align-items: flex-start;
  gap: var(--spacing-md);
  padding: var(--spacing-md);
  background: var(--bg-secondary);
  transition: background 0.2s var(--ease-out);
  display: flex;
}

.post-item:hover {
  background: var(--bg-hover);
}

.post-date {
  font-family: var(--font-mono);
  color: var(--text-tertiary);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
  width: 88px;
  padding-top: 3px;
}

.post-body {
  flex-direction: column;
  min-width: 0;
  flex: 1;
  display: flex;
}

.post-title {
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.5;
  transition: color 0.15s ease;
  display: block;
}

.post-item:hover .post-title {
  color: var(--accent);
}

.post-arrow {
  color: var(--accent);
  opacity: 0;
  font-size: 12px;
  margin-left: 6px;
  transition: opacity 0.15s var(--ease-out);
}

.post-item:hover .post-arrow {
  opacity: 1;
}

.post-summary {
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1.6;
  margin-top: 4px;
}

.post-state {
  padding: var(--spacing-lg) var(--spacing-md);
  text-align: center;
  color: var(--text-tertiary);
  background: var(--bg-secondary);
  font-family: var(--font-mono);
  font-size: 13px;
}

.post-state a {
  color: var(--accent);
}

/* 底部「查看全部」：右对齐、与成就列表备注同一层级 */
.post-more {
  margin-top: var(--spacing-sm);
  text-align: right;
  font-family: var(--font-mono);
  font-size: 12px;
}

.post-more a {
  color: var(--text-tertiary);
}

.post-more a:hover {
  color: var(--accent);
}

@media (width <= 600px) {
  .post-item {
    flex-direction: column;
    gap: 6px;
  }

  .post-date {
    width: auto;
    padding-top: 0;
  }
}

/* ==========================================================================
   8. 页面切换动画
   ========================================================================== */

.page-enter-active,
.page-leave-active {
  transition: opacity 0.2s var(--ease-out), transform 0.2s var(--ease-out);
}

.page-enter-from {
  opacity: 0;
  transform: translateY(12px);
}

.page-leave-to {
  opacity: 0;
  transform: translateY(-8px);
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.25s var(--ease-out);
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .page-enter-active,
  .page-leave-active,
  .fade-enter-active,
  .fade-leave-active {
    transition: none;
  }
}

/* 原站页面切换：0.2s 淡入上移 */
.page {
  animation: page-in 0.2s var(--ease-out) both;
}

@keyframes page-in {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .page {
    animation: none;
  }
}

/* ==========================================================================
   9. 错误页
   ========================================================================== */

.app-error {
  background: var(--bg-primary);
  z-index: 9999;
  padding: var(--spacing-lg);
  justify-content: center;
  align-items: center;
  display: flex;
  position: fixed;
  inset: 0;
}

.error-content {
  text-align: center;
  max-width: 400px;
}

.error-icon {
  margin-bottom: var(--spacing-md);
  font-size: 4rem;
}

.error-title {
  color: var(--text-primary);
  margin-bottom: var(--spacing-sm);
  font-size: 1.5rem;
}

.error-message {
  color: var(--text-secondary);
  margin-bottom: var(--spacing-lg);
  word-break: break-word;
}

.error-retry-btn {
  align-items: center;
  gap: var(--spacing-xs);
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--accent);
  color: var(--bg-primary);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  transition: opacity var(--transition-fast);
  font-size: 0.9rem;
  display: inline-flex;
}

.error-retry-btn:hover {
  opacity: 0.9;
}

/* ==========================================================================
   10. 响应式
   ========================================================================== */

@media (width <= 1024px) {
  .intro-right {
    flex-basis: 300px;
    width: min(300px, 38%);
  }

  .hero-logo {
    width: clamp(180px, 45vw, 400px);
  }

  .intro-bio {
    font-size: 14px;
    line-height: 1.8;
  }
}

@media (width <= 768px) {
  /* 移动端：内容改为纵向堆叠，左对齐 */
  .hero {
    margin-top: -52px;
    padding: 52px 0 0;
  }

  .hero-content {
    flex-direction: column;
    justify-content: flex-end;
    align-items: flex-start;
    gap: 16px;
    padding: 0 20px 36px;
  }

  .intro-left {
    width: 100%;
  }

  .hero-logo {
    width: clamp(180px, 60vw, 320px);
  }

  .intro-right {
    text-align: left;
    flex: none;
    width: 100%;
    max-width: 100%;
    margin-left: 0;
  }

  .intro-bio {
    font-size: 16px;
    line-height: 1.75;
  }

  /* 移动端把分行改成行内。
     原来这里用 :after 补一个中文逗号，但如果原文本身已经带了标点，
     就会出现"，，"这种重复。改为不加标点，交给 content.js 里的原文自己带。 */
  .bio-line {
    display: inline;
  }

  .hero-chips {
    justify-content: flex-start;
  }

  /* 触屏没有 hover，悬停态要禁用否则会"粘住" */
  .hero-chip:hover,
  .hero-chip:active {
    color: inherit !important;
    border-color: var(--border) !important;
    background: 0 0 !important;
    transform: none !important;
  }

  .projects-grid,
  .friend-grid,
  .social-grid {
    gap: var(--spacing-md);
    grid-template-columns: 1fr;
  }

  .project-card {
    padding: var(--spacing-md);
    min-width: 0;
  }

  .project-header {
    gap: 10px;
    margin-bottom: 8px;
  }

  .project-icon {
    width: 18px;
    height: 18px;
  }

  .project-name {
    word-break: break-word;
    font-size: 16px;
  }

  .project-desc {
    word-break: break-word;
    font-size: 14px;
    line-height: 1.7;
  }

  .achievement-item {
    gap: var(--spacing-sm);
    padding: var(--spacing-md);
    min-width: 0;
  }

  .achievement-title {
    word-break: break-word;
    font-size: 15px;
  }

  .achievement-desc {
    word-break: break-word;
    font-size: 14px;
    line-height: 1.6;
  }

  .social-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .social-link {
    padding: var(--spacing-sm);
    min-width: 0;
  }

  .social-icon,
  .social-icon svg {
    width: 16px;
    height: 16px;
  }

  .social-name {
    font-size: 13px;
  }

  .social-handle {
    font-size: 10px;
  }
}

/* ---------- 10.1 经历数轴 ----------
   窄屏的取舍：数轴必须保持"刻度和横条共用同一坐标系"，
   否则百分比就对不上了。所以窄屏不能只把条目改成单列 ——
   顶部刻度行和网格线也要一起归零，三者必须同步改。

   最终形态：文字在上（占满整行），横条在下（占满整行 = 整条轴宽）。
   （放在这里而不是跟 6b 紧挨着，是为了让全站断点集中在一节里，
     顺序仍满足"宽 → 窄"的层叠约定。） */
@media (width <= 760px) {
  .axis {
    /* 单列布局后，左栏这个概念不存在了 */
    --info-col: 0px;
    --axis-gap: 0px;
  }

  .timeline-item {
    grid-template-columns: minmax(0, 1fr);
    /* 文字与横条之间只要很小的缝：横条是这段文字的"图形注解"，
       离太远就读不出它属于谁了。 */
    row-gap: 8px;
    padding: var(--spacing-sm) 0;
    /* 单列时横条在文字下方，垂直居中会让它悬在中间，改为拉伸 */
    align-items: stretch;
    /* 两列时的 min-height 在单列下反而制造空白，取消 */
    min-height: 0;
  }

  /* 顶部刻度行同步变单列：标签占一行，刻度区占满整行 */
  .axis-head {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 6px;
  }

  /* 网格线层也要覆盖整宽（原来是从 --info-col 之后开始） */
  .axis-grid {
    left: 0;
  }

  .timeline-title {
    font-size: 15px;
  }

  .timeline-desc {
    font-size: 13px;
    line-height: 1.6;
  }
}

@media (width <= 600px) {
  /* 横条收窄，避免相邻年份的条首尾相撞时糊成一片 */
  .timeline-bar {
    border-radius: var(--radius-xs);
  }

  /* 刻度数字缩小，否则 5 个年份在 342px 宽的轴上会互相压字 */
  .axis-tick {
    font-size: 10px;
  }

  .axis-head-label {
    font-size: 10px;
  }
}

@media (width <= 480px) {
  .hero-content {
    gap: 14px;
    padding: 0 16px 32px;
  }

  .hero-logo {
    width: clamp(160px, 65vw, 280px);
  }

  .intro-bio {
    font-size: 15px;
    line-height: 1.7;
  }

  .projects-grid,
  .friend-grid {
    gap: var(--spacing-sm);
  }

  .project-card {
    padding: var(--spacing-md);
    min-width: 0;
  }

  .project-header {
    gap: 10px;
    margin-bottom: 8px;
  }

  .project-icon {
    width: 16px;
    height: 16px;
  }

  .project-name {
    font-size: 15px;
  }

  .project-desc {
    word-break: break-word;
    font-size: 14px;
    line-height: 1.65;
  }

  /* 成就项在窄屏改为纵向，避免标记列挤占文字宽度 */
  .achievement-item {
    gap: var(--spacing-xs);
    padding: var(--spacing-sm);
    flex-direction: column;
    min-width: 0;
  }

  .achievement-marker {
    width: auto;
    padding-top: 0;
  }

  .marker-arrow {
    font-size: 12px;
  }

  .achievement-title {
    font-size: 14px;
  }

  .achievement-desc {
    margin-bottom: 8px;
    font-size: 13px;
    line-height: 1.55;
  }

  .achievement-tag {
    padding: 2px 6px;
    font-size: 10px;
  }

  .social-grid {
    gap: var(--spacing-xs);
    grid-template-columns: 1fr;
  }

  .social-link {
    padding: var(--spacing-sm) var(--spacing-md);
  }

  .social-icon,
  .social-icon svg {
    width: 18px;
    height: 18px;
  }

  .social-name {
    font-size: 13px;
  }

  .social-handle {
    font-size: 12px;
  }
}

@media (width <= 390px) {
  .project-card {
    padding: var(--spacing-sm);
  }

  .project-name {
    font-size: 14px;
  }

  .project-desc {
    font-size: 13px;
  }

  .achievement-item {
    padding: var(--spacing-sm);
  }

  .achievement-title {
    font-size: 13px;
  }

  .achievement-desc {
    font-size: 12px;
  }

  .achievement-date {
    font-size: 10px;
  }

  .social-link {
    padding: var(--spacing-sm);
  }

  .social-name {
    font-size: 13px;
  }

  .social-handle {
    font-size: 10px;
  }
}

/* 矮屏：压小 logo 与简介，保证不溢出 */
@media (height <= 640px) {
  .hero-content {
    gap: 12px;
  }

  .hero-logo {
    width: clamp(140px, 35vw, 280px);
  }

  .intro-bio {
    font-size: 14px;
    line-height: 1.65;
  }
}

@media (height <= 500px) {
  .hero-logo {
    width: clamp(120px, 30vw, 220px);
  }

  .intro-bio {
    font-size: 13px;
    line-height: 1.5;
  }
}

/* ==========================================================================
   11. 减少动效降级
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .intro-bio {
    transition: none;
  }

  .hero-chip {
    opacity: 1;
    transition: none;
    transform: none;
  }
}
