:root {
  --bg: #0d0f12;
  --bg-2: #07080a;
  --panel: #12151a;
  --line: #1e232b;
  --cyan: #4CE0D2;
  --magenta: #FF4FCB;
  --amber: #FFB454;
  --text: #E8E8E8;
  --muted: #8A8F98;
  --ease: 0.3s ease;

  --mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Consolas, "Courier New", monospace;
  --sans: "Inter", system-ui, -apple-system, "Segoe UI", "Microsoft YaHei", sans-serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  min-height: 100vh;
  padding: 0 24px 72px;
  background:
    radial-gradient(1200px 600px at 50% -10%, #12161c 0%, transparent 70%),
    linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

/* pixel-grid texture + CRT scanline + noise, all pointer-transparent */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(255,255,255,.028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.028) 1px, transparent 1px);
  background-size: 32px 32px;
}
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background:
    repeating-linear-gradient(180deg, rgba(0,0,0,.16) 0 1px, transparent 1px 3px),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2'/></filter><rect width='120' height='120' filter='url(%23n)' opacity='.5'/></svg>");
  background-size: auto, 120px 120px;
  opacity: .26;
  mix-blend-mode: overlay;
}

header, main, footer { position: relative; z-index: 1; }

/* ---------- hero ---------- */
.hero {
  max-width: 1120px;
  margin: 0 auto;
  padding: 88px 0 56px;
}
.hero .prompt {
  font: 400 13px/1 var(--mono);
  color: var(--muted);
  letter-spacing: .12em;
  margin-bottom: 18px;
}
.hero .prompt b { color: var(--cyan); font-weight: 400; }
/* 提示行终端动画：文字由 app.js 逐字写入/退格（宽度会来回变，所以不用裁切宽度那套），
   这里只管光标 —— 行尾 2px 竖线，跟旧版标题光标共用 keyframes */
.prompt .type { border-right: 2px solid var(--cyan); animation: caret 1s step-end infinite; }
h1 {
  margin: 0;
  font-family: var(--mono);
  font-size: clamp(38px, 8vw, 76px);
  font-weight: 700;
  letter-spacing: -.02em;
  color: var(--text);
  text-shadow: 0 0 26px rgba(76,224,210,.28);
  white-space: nowrap;
}
@keyframes caret { 50% { border-color: transparent } }

.hero p.sub {
  margin: 22px 0 0;
  max-width: 46ch;
  color: var(--muted);
  font-size: 15px;
}
.hero p.sub b { color: var(--amber); font-weight: 500; }

/* ---------- 竹林 + 熊猫 ----------
   东南竹园的那点竹子：和卡片笑脸同一套 8px 格画出来的瓦片，平铺在 hero 底部做剪影
   低透明度 + 极缓慢摇摆，够看出是竹林，又不跟标题抢。
   熊猫单独一层摆在最右（塞进瓦片的话每 460px 就会长一只），站在同一条地平线上。
   竹林右边用 mask 淡出，别糊到熊猫身上 */
.hero::before {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 190px;
  z-index: -1;
  pointer-events: none;
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 70 29' shape-rendering='crispEdges'><path fill='rgba(88,214,150,.7)' d='M29 4h2v25h-2zM46 8h2v21h-2zM12 10h2v19h-2zM61 12h2v17h-2zM11 14h1v1h-1zM14 14h1v1h-1zM28 14h1v1h-1zM31 14h1v1h-1zM38 15h2v14h-2zM23 16h2v1h-2zM45 16h1v1h-1zM48 16h1v1h-1zM60 16h1v1h-1zM63 16h1v1h-1zM25 17h4v1h-4zM2 18h2v11h-2zM27 18h2v1h-2zM11 19h1v1h-1zM14 19h1v1h-1zM28 19h1v1h-1zM31 19h1v1h-1zM54 20h2v9h-2zM33 21h1v1h-1zM56 21h1v1h-1zM0 22h2v2h-2zM21 22h2v7h-2zM34 22h4v1h-4zM48 22h2v1h-2zM57 22h4v1h-4zM36 23h2v1h-2zM50 23h4v1h-4zM59 23h2v1h-2zM1 24h1v1h-1zM4 24h1v1h-1zM11 24h1v1h-1zM14 24h1v1h-1zM28 24h1v1h-1zM31 24h1v1h-1zM37 24h1v1h-1zM40 24h1v1h-1zM45 24h1v1h-1zM48 24h1v1h-1zM52 24h2v1h-2zM60 24h1v1h-1zM63 24h1v1h-1zM53 25h1v1h-1zM56 25h1v1h-1z'/></svg>") repeat-x bottom / 460px 190px;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 250px), transparent calc(100% - 160px));
          mask-image: linear-gradient(90deg, #000 calc(100% - 250px), transparent calc(100% - 160px));
  opacity: .13;
  transform-origin: bottom center;
  animation: sway 13s ease-in-out infinite alternate;
}
.hero::after {
  content: "";
  position: absolute;
  right: 0; bottom: 0;
  width: 190px; height: 151px;
  z-index: -1;
  pointer-events: none;
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 29 23' shape-rendering='crispEdges'><path fill='rgba(56,104,90,.9)' d='M20 6h2v2h-2zM16 7h4v1h-4zM13 8h3v1h-3zM22 8h1v1h-1zM7 9h2v3h-2zM11 9h2v1h-2zM18 9h2v3h-2zM23 9h1v2h-1zM6 10h1v2h-1zM9 10h2v1h-2zM16 10h2v1h-2zM20 10h1v2h-1zM24 11h1v11h-1zM7 12h1v1h-1zM19 12h1v1h-1zM6 13h1v2h-1zM20 13h1v2h-1zM25 13h1v8h-1zM5 15h1v7h-1zM26 15h1v4h-1zM9 16h2v1h-2zM15 16h3v1h-3zM21 16h1v6h-1zM27 16h1v3h-1zM8 17h2v2h-2zM16 17h3v2h-3zM22 17h2v5h-2zM28 17h1v2h-1zM3 18h2v3h-2zM8 19h1v1h-1zM12 19h2v1h-2zM17 19h2v1h-2zM6 20h1v2h-1zM20 20h1v2h-1zM4 21h1v1h-1zM7 21h3v1h-3zM17 21h3v1h-3zM10 22h8v1h-8z'/><path fill='rgba(232,248,240,.95)' d='M 16 8 L 22 8 L 22 9 L 16 9 L 16 8 Z M 13 9 L 18 9 L 18 10 L 13 10 L 13 9 Z M 20 9 L 23 9 L 23 10 L 20 10 L 20 9 Z M 11 10 L 16 10 L 16 16 L 11 16 L 11 10 Z M 21 10 L 23 10 L 23 16 L 21 16 L 21 10 Z M 9 11 L 11 11 L 11 16 L 9 16 L 9 11 Z M 16 11 L 18 11 L 18 16 L 16 16 L 16 11 Z M 23 11 L 24 11 L 24 17 L 23 17 L 23 11 Z M 8 12 L 9 12 L 9 17 L 8 17 L 8 12 Z M 18 12 L 19 12 L 19 17 L 18 17 L 18 12 Z M 20 12 L 21 12 L 21 13 L 20 13 L 20 12 Z M 7 13 L 8 13 L 8 21 L 7 21 L 7 13 Z M 19 13 L 20 13 L 20 21 L 19 21 L 19 13 Z M 6 15 L 7 15 L 7 20 L 6 20 L 6 15 Z M 20 15 L 21 15 L 21 20 L 20 20 L 20 15 Z M 11 16 L 15 16 L 15 19 L 11 19 L 11 16 Z M 22 16 L 23 16 L 23 17 L 22 17 L 22 16 Z M 10 17 L 11 17 L 11 22 L 10 22 L 10 17 Z M 15 17 L 16 17 L 16 22 L 15 22 L 15 17 Z M 9 19 L 10 19 L 10 21 L 9 21 L 9 19 Z M 11 19 L 12 19 L 12 22 L 11 22 L 11 19 Z M 14 19 L 15 19 L 15 22 L 14 22 L 14 19 Z M 16 19 L 17 19 L 17 22 L 16 22 L 16 19 Z M 8 20 L 9 20 L 9 21 L 8 21 L 8 20 Z M 12 20 L 14 20 L 14 22 L 12 22 L 12 20 Z M 17 20 L 19 20 L 19 21 L 17 21 L 17 20 Z M 25 21 L 26 21 L 25 21 Z M 18 22 L 25 22 L 18 22 Z'/></svg>") center / 100% 100% no-repeat;
  opacity: .3;
}
@keyframes sway {
  from { transform: rotate(-.3deg) }
  to   { transform: rotate(.3deg) }
}

/* ---------- grid ---------- */
.grid {
  max-width: 1120px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 24px;
}

/* ---------- card ---------- */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 4px;
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--ease), transform var(--ease), border-color var(--ease), box-shadow var(--ease);
}
.card.in { opacity: 1; transform: none; }
.card.in:hover, .card.in:focus-visible {
  transform: scale(1.03);
  border-color: rgba(76,224,210,.55);
  box-shadow: 0 0 0 1px rgba(76,224,210,.18), 0 12px 40px -12px rgba(76,224,210,.35);
  outline: none;
}
.card.in:hover .idx { color: var(--amber); }

/* corner brackets */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: .38;
  transition: opacity var(--ease), background-image var(--ease);
  --c: var(--cyan);
  background-image:
    linear-gradient(var(--c), var(--c)), linear-gradient(var(--c), var(--c)),
    linear-gradient(var(--c), var(--c)), linear-gradient(var(--c), var(--c)),
    linear-gradient(var(--c), var(--c)), linear-gradient(var(--c), var(--c)),
    linear-gradient(var(--c), var(--c)), linear-gradient(var(--c), var(--c));
  background-size: 11px 1px, 1px 11px, 11px 1px, 1px 11px, 11px 1px, 1px 11px, 11px 1px, 1px 11px;
  background-position: 0 0, 0 0, 100% 0, 100% 0, 0 100%, 0 100%, 100% 100%, 100% 100%;
  background-repeat: no-repeat;
}
.card:hover::after { opacity: 1; }

/* ---------- thumbnail ---------- */
.thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #0a0c0f;
  border-bottom: 1px solid var(--line);
}
.thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: saturate(.9);
  transition: filter var(--ease), transform var(--ease);
}
.card:hover .thumb img { filter: saturate(1.15); transform: scale(1.04); }

/* CSS-only placeholder: gradient block + pixel grid
   网格以盒子中心为基准锚定（而不是默认的左上角），
   这样笑脸的 8px 格子才能和背景格子共用同一套格线 */
.thumb .ph {
  position: absolute;
  inset: 0;
  background-image:
    repeating-linear-gradient(90deg, rgba(0,0,0,.30) 0 1px, transparent 1px 8px),
    repeating-linear-gradient(0deg, rgba(0,0,0,.30) 0 1px, transparent 1px 8px),
    linear-gradient(135deg, rgba(76,224,210,.42), rgba(255,79,203,.30) 55%, rgba(255,180,84,.24));
  background-size: 8px 8px, 8px 8px, auto;
  background-position: center, center, center;
  transition: opacity var(--ease), transform var(--ease);
}

/* 占位图案：像素笑脸。14×14 格，1 格 = 背景网格的 1 格 = 8px，整图 112px
   +4px 是半个格子的修正量 —— 网格用 center 定位时格线落在 center-4px 上，
   笑脸的格子要平移半格才能压在格线上 */
.thumb .ph::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' shape-rendering='crispEdges'><path fill='rgba(13,15,18,.62)' d='M4 0h6v1h-6zM3 1h1v1h-1zM10 1h1v1h-1zM2 2h1v1h-1zM11 2h1v1h-1zM1 3h1v1h-1zM5 3h1v1h-1zM8 3h1v1h-1zM12 3h1v1h-1zM0 4h1v1h-1zM5 4h1v1h-1zM8 4h1v1h-1zM13 4h1v1h-1zM0 5h1v1h-1zM5 5h1v1h-1zM8 5h1v1h-1zM13 5h1v1h-1zM0 6h1v1h-1zM13 6h1v1h-1zM0 7h1v1h-1zM3 7h1v1h-1zM10 7h1v1h-1zM13 7h1v1h-1zM0 8h1v1h-1zM3 8h1v1h-1zM10 8h1v1h-1zM13 8h1v1h-1zM0 9h1v1h-1zM4 9h1v1h-1zM9 9h1v1h-1zM13 9h1v1h-1zM1 10h1v1h-1zM5 10h4v1h-4zM12 10h1v1h-1zM2 11h1v1h-1zM11 11h1v1h-1zM3 12h1v1h-1zM10 12h1v1h-1zM4 13h6v1h-6z'/></svg>");
  background-size: 112px 112px;
  background-position: calc(50% + 4px) calc(50% + 4px);
  background-repeat: no-repeat;
  image-rendering: pixelated;
}
.card:hover .thumb .ph { opacity: .82; transform: scale(1.04); }

.idx {
  position: absolute;
  left: 12px;
  bottom: 10px;
  z-index: 2;
  font: 400 12px/1 var(--mono);
  letter-spacing: .14em;
  color: var(--cyan);
  text-shadow: 0 0 12px rgba(13,15,18,.9), 0 0 3px rgba(13,15,18,1);
  transition: color var(--ease);
}

/* ---------- body ---------- */
.body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px 18px 20px;
  flex: 1;
}
.card h2 {
  margin: 0;
  font-family: var(--mono);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--text);
}
.card .tagline {
  margin: 0;
  flex: 1;
  font-size: 14px;
  color: var(--muted);
}

.meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
}
.badge, .tag {
  font: 400 11px/1 var(--mono);
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 5px 8px;
  border: 1px solid currentColor;
  border-radius: 2px;
}
.status-live      { color: var(--cyan);   background: rgba(76,224,210,.08); }
.status-wip       { color: var(--amber);  background: rgba(255,180,84,.08); }
.status-archived  { color: var(--muted);  background: rgba(138,143,152,.08); }

.tag {
  color: var(--muted);
  border-color: var(--line);
  text-transform: none;
}

/* ---------- footer ---------- */
footer {
  max-width: 1120px;
  margin: 80px auto 0;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  align-items: center;
  font: 400 12px/1.9 var(--mono);
  color: var(--muted);
}
footer a { color: inherit; text-decoration: none; transition: color var(--ease); }
footer a:hover { color: var(--cyan); }
footer .sig { margin-left: auto; color: var(--amber); }
footer .badge-link { display: inline-flex; align-items: center; gap: 5px; }
footer .badge-link img { width: 14px; height: 14px; }

@media (max-width: 560px) {
  body { padding: 0 16px 56px; }
  .hero { padding: 56px 0 36px; }
  .hero::before { height: 130px; background-size: 315px 130px; opacity: .11; }
  .hero::after { display: none; }   /* 窄屏熊猫压到正文，直接不显示 */
  footer .sig { margin-left: 0; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition-duration: .01ms !important; }
  .card { opacity: 1; transform: none; }
}
