/* ════════════════════════════════════════════════════════════
   Seth Li — homepage styles · "deep space HUD" theme
   (indigo × cyan × violet on a cool, high-contrast interface)
   Design tokens live in tokens.css (light + night).

   Sections — this list is the file's own table of contents and used to
   disagree with it (it claimed a §14/§15 that were §15/§16, and skipped §06):
   01 base · 02 background fx · 03 scrollbar · 04 nav ·
   05 hero + HUD readout · 06 sections/cards · 07 timeline ·
   08 stack/projects · 09 browser frames · 10 insights/poem ·
   11 matrix panel (digital rain) · 12 quote banner ·
   13 contact/footer · 14 currency cues · 15 AI direction + Now/Next ·
   16 overlays (palette, back-to-top, copy buttons) · 17 responsive ·
   18 print · 19 reduced motion
   ════════════════════════════════════════════════════════════ */

/* Layout constants shared by the HUD components. The radii and the spacing
   scale live in tokens.css (--r-*/--s*); only the bar height is local. */
:root {
  --hud-radius: var(--r-md);
  --hud-radius-sm: var(--r-sm);
  --hud-bar-h: 62px;
}

/* ── 01 Base ──────────────────────────────────────────────── */
* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  scrollbar-width: thin;
  scrollbar-color: var(--scroll-thumb) var(--bg);
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
  font-size: 16px;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background-color 0.4s ease, color 0.4s ease;
}

h1, h2, h3 {
  font-family: 'Sora', 'Noto Serif SC', sans-serif;
  color: var(--ink);
  line-height: 1.2;
  margin: 0;
  letter-spacing: -0.02em;
}

a { color: var(--sun-deep); text-decoration: none; }
a:hover { color: var(--peach); }

img { max-width: 100%; display: block; }
code { font-family: 'JetBrains Mono', Consolas, monospace; }

/* 选中文本：青蓝底 + 深空字；fill-color 一并覆盖，
   保证渐变色文字（background-clip: text）选中时也可见 */
::selection { background: var(--selection); color: var(--selection-ink); -webkit-text-fill-color: var(--selection-ink); }
::-moz-selection { background: var(--selection); color: var(--selection-ink); -webkit-text-fill-color: var(--selection-ink); }

:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; border-radius: 8px; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: 10px 18px; background: var(--grad-accent); color: var(--on-accent);
  font-weight: 700; font-size: 14px;
  border-radius: 0 0 14px 0;
}
.skip-link:focus { left: 0; color: var(--on-accent); }

/* ── 02 Background fx — aurora haze + tech grid ─────────────
   The haze used to be three 38–46vw layers under filter: blur(95px),
   drifting on a 28s loop — the most expensive thing on the page, and it
   re-rasterised three huge blurred layers every frame. A large radial
   gradient is already soft, so the blur bought nothing: the gradients are
   now static and there is no filter and no animation. */
.bg-mesh { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
.mesh { position: absolute; border-radius: 50%; }
.mesh-a { width: 52vw; height: 52vw; left: -16vw; top: -16vw; background: radial-gradient(circle, var(--mesh-a), transparent 68%); }
.mesh-b { width: 46vw; height: 46vw; right: -16vw; top: 12vh; background: radial-gradient(circle, var(--mesh-b), transparent 68%); }
.mesh-c { width: 44vw; height: 44vw; left: 28vw; bottom: -20vw; background: radial-gradient(circle, var(--mesh-c), transparent 68%); }

/* Film grain over the whole page — static, no animation, no request. */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 39; pointer-events: none;
  background-image: var(--noise);
  opacity: 0.035;
}

.grid-overlay {
  position: absolute; inset: 0;
  background-image: radial-gradient(var(--dot) 1.1px, transparent 1.1px);
  background-size: 30px 30px;
  -webkit-mask-image: radial-gradient(ellipse at 50% 14%, #000 0%, transparent 72%);
  mask-image: radial-gradient(ellipse at 50% 14%, #000 0%, transparent 72%);
}

/* Technical blueprint grid — two scales. The drift is gone: animating
   background-position is a paint, not a composite, so it burned CPU while
   off-screen for a movement nobody could see. */
.grid-overlay-2 {
  background-image: var(--grid-image);
  background-size: 84px 84px;
  -webkit-mask-image: radial-gradient(ellipse 92% 78% at 50% 42%, #000 0%, transparent 88%);
  mask-image: radial-gradient(ellipse 92% 78% at 50% 42%, #000 0%, transparent 88%);
}
.grid-overlay-2::after {
  content: ""; position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--grid-line-strong) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line-strong) 1px, transparent 1px);
  background-size: 21px 21px;
  -webkit-mask-image: radial-gradient(ellipse 60% 46% at 50% 8%, #000 0%, transparent 78%);
  mask-image: radial-gradient(ellipse 60% 46% at 50% 8%, #000 0%, transparent 78%);
}

/* Horizon glow that anchors the grid (soft by way of its stops, not a blur) */
.grid-glow {
  position: absolute; left: 50%; top: -18vh; transform: translateX(-50%);
  width: 120vw; height: 46vh;
  background: radial-gradient(ellipse at 50% 100%, var(--glow-neon), transparent 70%);
  opacity: 0.45;
}

/* CRT scanlines over the whole viewport (very low opacity).
   A full-viewport mix-blend-mode forces the compositor to re-blend the page
   on every scroll frame; a plain low-opacity gradient looks the same. */
.scanlines {
  position: fixed; inset: 0; z-index: 40; pointer-events: none;
  background: repeating-linear-gradient(0deg, var(--scanline) 0 1px, transparent 1px 4px);
  opacity: 0.75;
}
html[data-theme="night"] .scanlines { opacity: 0.6; }

/* Corner-bracket ornament used by nav / hero / cards */
.hud-corners, .nav-frame, .hero-frame {
  position: absolute; inset: 0; pointer-events: none;
}
.hud-corners i, .nav-frame i, .hero-frame i {
  position: absolute; width: 14px; height: 14px;
  border: 1.6px solid var(--line-glow);
}
.hud-corners i:nth-child(1), .nav-frame i:nth-child(1), .hero-frame i:nth-child(1) { top: -1px; left: -1px; border-right: 0; border-bottom: 0; border-radius: 6px 0 0 0; }
.hud-corners i:nth-child(2), .nav-frame i:nth-child(2), .hero-frame i:nth-child(2) { top: -1px; right: -1px; border-left: 0; border-bottom: 0; border-radius: 0 6px 0 0; }
.hud-corners i:nth-child(3), .nav-frame i:nth-child(3), .hero-frame i:nth-child(3) { bottom: -1px; left: -1px; border-right: 0; border-top: 0; border-radius: 0 0 0 6px; }
.hud-corners i:nth-child(4), .nav-frame i:nth-child(4), .hero-frame i:nth-child(4) { bottom: -1px; right: -1px; border-left: 0; border-top: 0; border-radius: 0 0 6px 0; }

#progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 70;
  background: var(--grad-tech);
  box-shadow: 0 0 10px var(--glow-neon);
  transform: scaleX(0); transform-origin: 0 50%;
}

/* ── 03 Scrollbar — cyan → violet ─────────────────────────── */
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--scroll-track); }
::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb-grad);
  border: 3px solid var(--bg);
  border-radius: 9px;
  box-shadow: 0 0 0 1px var(--line-2);
}
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb); border-width: 2px; }
::-webkit-scrollbar-corner { background: transparent; }


/* ── 04 Nav — HUD command bar ─────────────────────────────── */
.nav {
  position: sticky; top: 0; z-index: 50; padding: 10px 0;
  border-bottom: 1px solid transparent;
  transition: background-color 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}
.nav.scrolled {
  background: var(--nav-bg);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  backdrop-filter: blur(16px) saturate(1.3);
  border-bottom-color: var(--line-2);
  box-shadow: var(--shadow-md);
}
/* Luminous hairline along the bottom edge, only once scrolled */
.nav::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: var(--grad-hair);
  opacity: 0; transition: opacity 0.3s ease;
}
.nav.scrolled::after { opacity: 0.9; }
.nav-frame { opacity: 0; transition: opacity 0.3s ease; }
.nav.scrolled .nav-frame { opacity: 1; }
.nav-frame i { width: 10px; height: 10px; border-color: var(--neon); }
.nav-frame i:nth-child(1) { top: 4px; left: 4px; }
.nav-frame i:nth-child(2) { top: 4px; right: 4px; }
.nav-frame i:nth-child(3) { bottom: 4px; left: 4px; }
.nav-frame i:nth-child(4) { bottom: 4px; right: 4px; }
/* Slow sweep of light across the bar */
.nav-scan {
  position: absolute; top: 0; bottom: 0; left: 0; width: 26%;
  background: linear-gradient(90deg, transparent, var(--sky-soft), transparent);
  pointer-events: none; opacity: 0;
  animation: nav-sweep 7s ease-in-out infinite;
}
.nav.scrolled .nav-scan { opacity: 0.9; }
@keyframes nav-sweep {
  0%, 100% { transform: translateX(-30%); opacity: 0; }
  45% { opacity: 0.9; }
  55% { opacity: 0.9; }
  to { transform: translateX(430%); opacity: 0; }
}

.nav-inner {
  max-width: 1240px; margin: 0 auto; padding: 0 24px;
  display: flex; align-items: center; gap: 14px;
  min-height: var(--hud-bar-h);
}

/* Brand / identity block at the far left */
.nav-brand { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.nav-brand__mark {
  width: 34px; height: 34px; border-radius: 11px;
  background: var(--grad-accent); color: var(--on-accent);
  display: grid; place-items: center;
  font-family: 'JetBrains Mono', monospace; font-size: 12.5px; font-weight: 800;
  letter-spacing: 0.04em;
  box-shadow: var(--shadow-sm);
}
.nav-brand__text { display: grid; line-height: 1.15; }
.nav-brand__text b {
  font-family: 'Sora', sans-serif; font-size: 14px; font-weight: 800; color: var(--ink);
  letter-spacing: -0.01em;
}
.nav-brand__text em {
  font-style: normal; font-family: 'JetBrains Mono', monospace;
  font-size: 8.5px; font-weight: 600; letter-spacing: 0.16em;
  color: var(--sky); text-transform: uppercase;
}
.nav-brand:hover .nav-brand__mark { filter: brightness(1.08); }

.burger {
  display: none; margin-left: auto; width: 44px; height: 44px; border-radius: 13px;
  border: 1px solid var(--line-2); background: var(--surface);
  box-shadow: var(--shadow-sm);
  cursor: pointer; padding: 11px; flex: 0 0 auto;
}
.burger span {
  display: block; height: 2.5px; margin: 4px 0; border-radius: 3px;
  background: var(--ink); transition: transform 0.25s ease, opacity 0.25s ease;
}
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* The row itself. `min-width: 0` + `flex-wrap` guard means a too-wide row
   wraps into a second line instead of clipping the last link. */
.menu {
  margin-left: auto; display: flex; align-items: center; gap: 2px;
  min-width: 0; flex-wrap: wrap; justify-content: flex-end;
  row-gap: 4px;
}
.menu > a {
  position: relative;
  padding: 8px 11px; border-radius: var(--hud-radius-sm);
  color: var(--muted); font-weight: 600; font-size: 13.5px;
  transition: color 0.22s, background-color 0.22s;
  white-space: nowrap;
}
.menu > a::after {
  content: ""; position: absolute; left: 11px; right: 11px; bottom: 3px; height: 1.5px;
  background: var(--grad-tech); border-radius: 2px;
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.menu > a:hover { color: var(--ink); background: var(--surface-2); }
/* The indicator runs the full width now: a 60%-scaled underline was a 2019
   signature, and it made the active state and the hover state look alike. */
.menu > a:hover::after { transform: scaleX(1); }
.menu > a.active {
  color: var(--sun-deep); background: var(--sun-soft);
}
.menu > a.active::after { transform: scaleX(1); }

/* Live section readout — 01 … 09 */
.nav-index {
  display: inline-flex; align-items: baseline; gap: 1px; margin-right: 6px;
  font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 700;
  color: var(--sun-deep); letter-spacing: 0.04em;
  padding: 5px 9px; border-radius: 8px;
  border: 1px solid var(--line-2); background: var(--surface-2);
  flex: 0 0 auto;
}
.nav-index u { text-decoration: none; color: var(--faint); font-size: 9.5px; }

.nav-divider { width: 1px; height: 20px; background: var(--line-2); margin: 0 6px; flex: 0 0 auto; }

.lang-sw {
  display: flex; margin-left: 2px; border: 1px solid var(--line-2);
  border-radius: 9px; overflow: hidden; background: var(--surface);
  flex: 0 0 auto;
}
.lang-sw button {
  padding: 6px 10px; border: 0; background: transparent; cursor: pointer;
  color: var(--muted); font-family: 'JetBrains Mono', monospace; font-size: 11px;
  font-weight: 700;
  transition: background-color 0.2s, color 0.2s;
}
.lang-sw button.on { background: var(--grad-accent); color: var(--on-accent); }

/* Search-and-jump trigger. Its own control rather than a menu item, because
   it opens a dialog and works from a keyboard shortcut anywhere on the page. */
.palette-btn {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  margin-left: 2px; padding: 7px 10px; border-radius: 9px;
  border: 1px solid var(--line-2); background: var(--surface);
  color: var(--muted); font-family: 'Manrope', sans-serif;
  font-size: 13px; font-weight: 600; cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background-color 0.2s;
}
.palette-btn:hover { color: var(--sun-deep); border-color: var(--neon); background: var(--surface-2); }
.palette-btn kbd {
  font-family: 'JetBrains Mono', monospace; font-size: 10px; line-height: 1;
  padding: 3px 5px; border-radius: 5px;
  border: 1px solid var(--line-2); background: var(--surface-2); color: var(--faint);
}

.theme-btn {
  width: 34px; height: 34px; border-radius: 9px; margin-left: 2px;
  border: 1px solid var(--line-2); background: var(--surface);
  color: var(--muted); cursor: pointer; display: grid; place-items: center;
  flex: 0 0 auto;
  transition: color 0.2s, border-color 0.2s, transform 0.2s, box-shadow 0.2s;
}
.theme-btn:hover { color: var(--sky); border-color: var(--neon); transform: rotate(12deg); box-shadow: var(--shadow-sm); }
.theme-btn .i-sun { display: none; }
html[data-theme="night"] .theme-btn .i-sun { display: block; }
html[data-theme="night"] .theme-btn .i-moon { display: none; }

.nav-cta {
  margin-left: 6px; padding: 8px 14px; border-radius: 9px;
  background: var(--grad-accent); color: var(--on-accent) !important;
  font-family: 'JetBrains Mono', monospace; font-size: 11.5px !important; font-weight: 700;
  box-shadow: var(--shadow-sun);
  white-space: nowrap; flex: 0 0 auto;
  position: relative; overflow: hidden;
}
.nav-cta:hover { color: var(--on-accent) !important; filter: brightness(1.08); }

/* Overflow tray — hidden until the wide row is too tight to fit */
.nav-more { position: relative; display: none; flex: 0 0 auto; }
.nav-more__btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 12px; border-radius: var(--hud-radius-sm);
  border: 1px solid var(--line-2); background: var(--surface);
  color: var(--muted); font-family: 'Manrope', sans-serif;
  font-size: 13.5px; font-weight: 700; cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background-color 0.2s;
}
.nav-more__btn:hover,
.nav-more__btn[aria-expanded="true"] { color: var(--sun-deep); border-color: var(--neon); background: var(--surface-2); }
.nav-more__caret { font-style: normal; font-size: 10px; transition: transform 0.22s ease; }
.nav-more__btn[aria-expanded="true"] .nav-more__caret { transform: rotate(180deg); }
.nav-more__menu {
  position: absolute; top: calc(100% + 12px); right: 0; min-width: 216px; padding: 8px;
  background: var(--menu-bg); border: 1px solid var(--line-2); border-radius: var(--hud-radius);
  box-shadow: var(--shadow-lg);
  display: none; z-index: 5;
}
.nav-more__menu.open { display: block; animation: tray-in 0.18s ease-out; }
@keyframes tray-in { from { opacity: 0; transform: translateY(-6px); } }
.nav-more__menu a {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 12px; border-radius: 10px;
  font-size: 13.5px; font-weight: 600; color: var(--muted);
  transition: color 0.2s, background-color 0.2s, transform 0.2s;
}
.nav-more__menu a::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--faint); flex: 0 0 auto;
  transition: background-color 0.2s, box-shadow 0.2s;
}
.nav-more__menu a:hover { background: var(--surface-2); color: var(--ink); transform: translateX(2px); }
.nav-more__menu a:hover::before { background: var(--neon); box-shadow: 0 0 8px var(--glow-neon); }
.nav-more__menu a.active { color: var(--sun-deep); background: var(--sun-soft); }
.nav-more__menu a.active::before { background: var(--sun); box-shadow: 0 0 8px var(--glow); }


/* ── 05 Hero — HUD landing ────────────────────────────────── */
.hero {
  position: relative; z-index: 1;
  min-height: 92vh; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 108px 24px 104px; overflow: hidden;
}
.hero::before {
  content: ""; position: absolute; top: -16vw; left: 50%; transform: translateX(-50%);
  width: 58vw; height: 58vw; border-radius: 50%; z-index: -1;
  background: radial-gradient(circle, var(--mesh-a), transparent 62%);
  pointer-events: none;
}
#stars { position: absolute; inset: 0; width: 100%; height: 100%; }

/* Perspective grid floor behind the copy */
.hero-grid {
  position: absolute; left: -10%; right: -10%; bottom: -6%; height: 62%;
  background-image:
    linear-gradient(var(--grid-line-strong) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line-strong) 1px, transparent 1px);
  background-size: 56px 56px, 56px 56px;
  transform: perspective(520px) rotateX(66deg);
  transform-origin: 50% 100%;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 42%, transparent 96%);
  mask-image: linear-gradient(180deg, transparent, #000 42%, transparent 96%);
  opacity: 0.85; pointer-events: none;
  animation: floor-drift 18s linear infinite;
}
@keyframes floor-drift { to { background-position: 0 56px, 56px 0; } }

/* Vertical scan sweep over the hero */
.hero-scan {
  position: absolute; left: 0; right: 0; top: 0; height: 22%;
  background: linear-gradient(180deg, transparent, var(--sky-soft) 55%, transparent);
  pointer-events: none; opacity: 0.5;
  animation: hero-scan 9s ease-in-out infinite;
}
@keyframes hero-scan {
  0% { transform: translateY(-100%); opacity: 0; }
  12% { opacity: 0.55; }
  88% { opacity: 0.55; }
  100% { transform: translateY(460%); opacity: 0; }
}
.hero-frame { inset: 22px 22px 22px 22px; }
.hero-frame i { width: 20px; height: 20px; border-width: 2px; border-color: var(--line-glow); }

.hero-inner { position: relative; max-width: 960px; }

/* Live status readout strip */
.hud {
  display: inline-flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 4px 12px; margin-bottom: 26px;
  padding: 8px 16px; border-radius: 999px;
  border: 1px solid var(--line-2); background: var(--surface);
  box-shadow: var(--shadow-sm);
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; letter-spacing: 0.08em;
  text-transform: uppercase;
}
.hud__item { display: inline-flex; align-items: center; gap: 7px; }
.hud__item em { font-style: normal; color: var(--faint); }
.hud__item b { color: var(--ink); font-weight: 700; }
.hud__sep { width: 1px; height: 12px; background: var(--line-2); }
.hud__dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--neon);
  box-shadow: 0 0 9px var(--neon);
  animation: pulse-dot 2s ease-in-out infinite;
}
@keyframes pulse-dot { 50% { opacity: 0.35; transform: scale(0.82); } }

.eyebrow {
  display: inline-flex; align-items: center; gap: 10px;
  margin: 0; font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--sky);
}
.eyebrow i {
  font-style: normal; display: inline-grid; place-items: center;
  min-width: 30px; height: 22px; padding: 0 6px;
  border-radius: 6px;
  background: var(--sky-soft); border: 1px solid var(--line-2);
  color: var(--sky); font-weight: 800; font-size: 10.5px;
}
.eyebrow::after {
  content: ""; width: 46px; height: 1px;
  background: linear-gradient(90deg, var(--line-glow), transparent);
}
.sec-head.center .eyebrow::after { display: none; }

/* Inline SVG replaces the emoji the UI used to carry (🏢 🪷 ✉️ 📞 …): emoji
   render in the system's own style and break the mono/HUD voice. */
.ico { flex: 0 0 auto; }

.hero-title {
  position: relative;
  margin: 22px 0 4px;
  font-size: clamp(2.9rem, 8vw, 5.4rem); font-weight: 800; letter-spacing: -0.03em;
  color: var(--ink);
}
.hero-title__text {
  background: linear-gradient(180deg, var(--ink) 30%, color-mix(in srgb, var(--ink) 72%, var(--sky)) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
/* A halo behind the headline instead of the old duplicated-and-blurred copy of
   it: that re-rendered a 5.4rem text layer at filter: blur(22px) on every
   paint and read as ghosting rather than glow. */
.hero-inner::before {
  content: ""; position: absolute; z-index: -1; left: 50%; top: 4%;
  transform: translateX(-50%);
  width: min(760px, 94vw); height: 340px; pointer-events: none;
  background: radial-gradient(ellipse at 50% 44%, color-mix(in srgb, var(--neon) 15%, transparent), transparent 70%);
}
.hero-sub {
  display: block; margin-top: 18px;
  font-family: 'Sora', 'Noto Serif SC', sans-serif;
  font-size: clamp(1rem, 2.4vw, 1.3rem); font-weight: 700;
  letter-spacing: 0.04em;
  background: var(--grad-tech);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.hero-type {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 32px; margin: 26px 0 0;
  font-family: 'JetBrains Mono', monospace; font-size: clamp(0.9rem, 2vw, 1rem); color: var(--muted);
}
.hero-type__prompt { color: var(--neon); font-weight: 700; }
.caret { color: var(--sky); animation: blink 1.1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }

.hero-bio { max-width: 780px; margin: 20px auto 0; color: var(--muted); font-size: 16.5px; }
.hero-bio strong { color: var(--ink); font-weight: 700; border-bottom: 2px solid var(--neon); }

.hero-cta { margin-top: 38px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

.btn {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 13px 24px; border-radius: var(--hud-radius-sm);
  font-family: 'Manrope', sans-serif; font-weight: 700; font-size: 14.5px;
  border: 1px solid transparent;
  transition: transform 0.25s ease, box-shadow 0.25s ease, color 0.25s ease, border-color 0.25s ease, filter 0.25s ease, background-color 0.25s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn-sm { padding: 8px 14px; font-size: 12px; }

.btn-primary { background: var(--grad-accent); color: var(--on-accent); box-shadow: var(--shadow-sun); }
.btn-primary:hover { color: var(--on-accent); filter: brightness(1.08); box-shadow: 0 16px 40px -10px var(--glow-soft); }

.btn-ghost {
  background: var(--surface); color: var(--ink);
  border-color: var(--line-2); box-shadow: var(--shadow-sm);
}
.btn-ghost:hover { color: var(--sun-deep); border-color: var(--line-glow); box-shadow: var(--shadow-md); }
/* Copy buttons swap their label rather than opening a toast. */
.copy-btn__done { display: none; }
.copy-btn.is-done { color: var(--leaf); border-color: color-mix(in srgb, var(--leaf) 45%, transparent); }
.copy-btn.is-done .copy-btn__idle { display: none; }
.copy-btn.is-done .copy-btn__done { display: inline; }
/* Printing needs a real button; without JS it could not do anything, so it
   only appears once the boot script has marked the document. */
html:not(.js) .print-btn { display: none; }

.hero-stats { margin-top: 58px; display: flex; justify-content: center; gap: 14px; flex-wrap: wrap; }
.stat {
  position: relative; overflow: hidden;
  min-width: 158px; padding: 20px 22px; border-radius: var(--hud-radius);
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}
.stat::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: var(--grad-hair); opacity: 0; transition: opacity 0.25s ease;
}
.stat:hover, .stat:focus-within { transform: translateY(-4px); border-color: var(--line-glow); box-shadow: var(--shadow-md); }
.stat:hover::before, .stat:focus-within::before { opacity: 1; }
.stat b {
  display: block; font-family: 'Sora', sans-serif; font-size: 1.75rem; font-weight: 800;
  background: var(--grad-tech); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.stat span { font-size: 11px; color: var(--faint); letter-spacing: 0.1em; text-transform: uppercase; font-family: 'JetBrains Mono', monospace; }

.scroll-hint {
  position: absolute; bottom: 22px; left: 50%; transform: translateX(-50%);
  width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 50%; border: 1px solid var(--line-2); background: var(--surface);
  color: var(--faint); font-size: 18px; line-height: 1;
  animation: bob 2.2s ease-in-out infinite;
}
.scroll-hint:hover { color: var(--sky); border-color: var(--neon); }
@keyframes bob { 0%, 100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 8px); } }


/* ── 07 Sections / cards ──────────────────────────────────── */
.sec { position: relative; z-index: 1; padding: 96px 24px; scroll-margin-top: 88px; }
.sec-alt {
  background: var(--bg-2);
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
/* Faint blueprint grid inside alternating sections */
.sec-alt::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: var(--grid-image);
  background-size: 64px 64px;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
}
.wrap { max-width: 1160px; margin: 0 auto; }
.center { text-align: center; }

.sec-head { max-width: 820px; margin-bottom: 48px; }
.sec-head h2 {
  margin: 14px 0 12px; font-size: clamp(1.75rem, 4vw, 2.6rem); font-weight: 800; letter-spacing: -0.028em;
  text-wrap: balance;
}
.sec-head h2 span, .sec-head h2 em { display: inline-block; max-width: 100%; }
.sec-head h2 em {
  font-style: normal;
  background: var(--grad-tech); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.sec-head .sub { margin: 0; max-width: 700px; color: var(--muted); font-size: 16px; }
.sec-head.center .sub { margin-left: auto; margin-right: auto; }

.reveal { transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1); transition-delay: var(--d, 0s); }
html.js .reveal { opacity: 0; transform: translateY(24px); }
html.js .reveal.in { opacity: 1; transform: none; }

.card {
  position: relative; border: 1px solid var(--line); border-radius: var(--hud-radius); overflow: hidden;
  background: var(--surface); box-shadow: var(--shadow-sm);
  transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}
.card::before {
  content: ""; position: absolute; top: 0; left: 8%; right: 8%; height: 2px; z-index: 1;
  background: var(--grad-hair);
  opacity: 0; transition: opacity 0.3s ease;
  pointer-events: none;
}
/* Blueprint texture replaced by a pointer spotlight: --mx/--my are set by one
   delegated pointermove listener in main.js, so the card lights up under the
   cursor instead of fading in a static 32px wash everywhere at once. */
.card::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(
    260px circle at var(--mx, 50%) var(--my, 0%),
    color-mix(in srgb, var(--neon) 13%, transparent),
    transparent 70%);
  opacity: 0; transition: opacity 0.35s ease;
}
.card > * { position: relative; z-index: 1; }
.card > .tl-when, .card > .card-img { position: static; }
.card:hover, .card:focus-within {
  transform: translateY(-5px);
  border-color: var(--line-glow);
  box-shadow: var(--shadow-lg), 0 0 0 1px var(--line-glow);
}
.card:hover::before, .card:focus-within::before,
.card:hover::after, .card:focus-within::after { opacity: 1; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }

/* Bento asymmetry for the AI section only: 4 + 2 / 2 + 4 rather than four
   identical boxes. The other .grid-2 uses (projects, ventures) stay even. */
#ai .grid-2 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
#ai .ai-card:nth-child(1), #ai .ai-card:nth-child(4) { grid-column: span 4; }
#ai .ai-card:nth-child(2), #ai .ai-card:nth-child(3) { grid-column: span 2; }

.card-img { position: relative; aspect-ratio: 16 / 9; overflow: hidden; }
.card-img img { width: 100%; height: 100%; object-fit: cover; transform: scale(1.02); transition: transform 0.6s ease; }
.card:hover .card-img img { transform: scale(1.08); }
.card-img::after { content: ""; position: absolute; inset: 0; background: var(--scrim); }
.img-credit {
  position: absolute; right: 10px; bottom: 8px; z-index: 1;
  font-family: 'JetBrains Mono', monospace; font-size: 10px; color: rgba(255, 255, 255, 0.8);
}
.card-body { padding: 26px 28px 30px; }
.card-icon {
  width: 46px; height: 46px; display: grid; place-items: center; font-size: 22px;
  border-radius: 13px; background: var(--sun-soft); border: 1px solid var(--line-2); margin-bottom: 14px;
}
.card-body h3 { margin: 0 0 10px; font-size: 1.28rem; font-weight: 800; }
.card-body p { margin: 0 0 16px; color: var(--muted); font-size: 14.5px; }
.card-body p strong { color: var(--ink); border-bottom: 2px solid var(--neon); }

.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px;
  padding: 5px 11px; border-radius: 7px;
  border: 1px solid var(--line-2); color: var(--muted); background: var(--surface);
  letter-spacing: 0.06em; text-transform: uppercase;
  transition: border-color 0.2s, color 0.2s;
}
.chip:hover { border-color: var(--neon); color: var(--ink); }
.chip.hot { color: var(--sun-deep); border-color: var(--line-glow); background: var(--sun-soft); }


/* ── 07 Timeline ──────────────────────────────────────────── */
/* The glance strip: three lines a hiring manager can read without expanding
   anything, and the reason the CTO role is no longer buried in the tray. */
.glance {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px;
  margin: 0 0 26px;
}
.glance__item {
  padding: 16px 18px; border-radius: var(--hud-radius-sm);
  border: 1px solid var(--line); background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.glance__k {
  display: block; margin-bottom: 6px;
  font-family: 'JetBrains Mono', monospace; font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--sky);
}
.glance__item b {
  font-family: 'Manrope', sans-serif; font-size: 13.5px; font-weight: 600;
  color: var(--text); line-height: 1.6;
}

.timeline { display: flex; flex-direction: column; gap: 18px; position: relative; }
/* Luminous rail running behind the cards */
.timeline::before {
  content: ""; position: absolute; left: -1px; top: 12px; bottom: 12px; width: 1px;
  background: linear-gradient(180deg, transparent, var(--line-glow) 12%, var(--line-glow) 88%, transparent);
  opacity: 0.6; pointer-events: none;
}
.tl-item {
  display: grid; grid-template-columns: 156px 1fr; gap: 22px; padding: 24px 30px 24px 28px;
}
/* Node marker on the rail */
.tl-item::after {
  content: ""; position: absolute; left: -4px; top: 32px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--neon); box-shadow: 0 0 10px var(--neon);
  opacity: 0.75; transition: opacity 0.25s ease, transform 0.25s ease;
}
.tl-item:hover::after { opacity: 1; transform: scale(1.35); }
.tl-when b {
  display: block; font-family: 'Sora', sans-serif; font-size: 1.1rem; font-weight: 800;
  background: var(--grad-tech); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.tl-when span { display: block; font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--sky); letter-spacing: 0.14em; text-transform: uppercase; margin-top: 4px; }
.tl-body h3 { margin: 0 0 8px; font-size: 1.15rem; font-weight: 800; }
.tl-body p { margin: 0 0 12px; color: var(--muted); font-size: 14px; }
.tl-link { font-family: 'JetBrains Mono', monospace; font-size: 11.5px; }


/* Timeline — collapse / expand (JS collapses the overflow entries;
   without JS everything stays visible and the toggle is hidden) */
.timeline-more { display: flex; flex-direction: column; gap: 18px; }
/* Group divider inside the tray. "Work" and "Education" overlap in time, so
   the two are labelled rather than interleaved into one reverse chronology
   that reads as a sorting mistake. */
.tl-group {
  display: flex; align-items: center; gap: 12px;
  margin: 12px 0 0; font-family: 'JetBrains Mono', monospace;
  font-size: 10px; font-weight: 700; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--faint);
}
.tl-group::after {
  content: ""; flex: 1; height: 1px;
  background: linear-gradient(90deg, var(--line-2), transparent);
}
.career-actions { display: none; }
html.js .career-actions { display: flex; justify-content: center; margin-top: 28px; }
html.js .timeline-more { display: none; }
html.js .timeline-more.open { display: flex; }
.career-count { font-family: 'JetBrains Mono', monospace; color: var(--faint); margin-left: 6px; }
.career-toggle-less { display: none; }
.career-actions.open .career-toggle-more,
.career-actions.open .career-count { display: none; }
.career-actions.open .career-toggle-less { display: inline; }

/* ── 09 Stack / projects ──────────────────────────────────── */.stack-group { padding: 24px 26px; }
.stack-group h3 {
  margin: 0 0 14px; font-family: 'JetBrains Mono', monospace; font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--sky);
}

.proj-grid { gap: 22px; }
.proj-card { padding: 28px; display: flex; flex-direction: column; gap: 10px; }
.proj-top { display: flex; align-items: center; gap: 10px; }
.proj-name { font-family: 'JetBrains Mono', monospace; font-size: 1rem; font-weight: 800; color: var(--ink); }
.proj-lang {
  font-family: 'JetBrains Mono', monospace; font-size: 10px; padding: 3px 9px; border-radius: 6px;
  color: var(--sky); border: 1px solid var(--line-glow); background: var(--sky-soft);
  letter-spacing: 0.06em; text-transform: uppercase;
}
.proj-star { margin-left: auto; font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--sun-deep); }
.proj-card p { margin: 0; color: var(--muted); font-size: 13.8px; flex: 1; }
.proj-meta {
  margin-top: 12px; font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; color: var(--faint); letter-spacing: 0.03em; line-height: 1.7;
}
.proj-subhead {
  display: flex; align-items: center; gap: 12px;
  margin: 46px 0 20px; font-family: 'JetBrains Mono', monospace;
  font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--sky);
}
.proj-subhead::after {
  content: ""; flex: 1; height: 1px;
  background: linear-gradient(90deg, var(--line-glow), transparent);
}
.proj-link { font-family: 'JetBrains Mono', monospace; font-size: 11.5px; }
.proj-more { margin-top: 20px; text-align: center; font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--faint); }
.proj-more a { color: var(--muted); }

.stats-row { margin-top: 30px; display: flex; justify-content: center; gap: 14px; flex-wrap: wrap; }
/* github-readme-stats returns an unpredictable height; reserving the space on
   the link stops the row from shoving the page down when the cards land. */
.stats-row a { display: flex; align-items: center; min-height: 195px; }
.stats-row img { border-radius: 14px; border: 1px solid var(--line-2); box-shadow: var(--shadow-md); }

/* ── 10 Browser frames (venture previews) ─────────────────── */
.venture-block { margin-bottom: 18px; scroll-margin-top: 78px; }
.venture-name {
  margin: 0 0 14px; font-size: 1.3rem; font-weight: 800;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.venture-name span { font-size: 0.9rem; color: var(--muted); font-weight: 600; }

.browser-frame { overflow: hidden; }
.browser-bar {
  display: flex; align-items: center; gap: 12px; padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}
.browser-dots { display: flex; gap: 6px; flex: 0 0 auto; }
.browser-dots i { width: 11px; height: 11px; border-radius: 50%; background: #ff5f57; display: block; }
.browser-dots i:nth-child(2) { background: #febc2e; }
.browser-dots i:nth-child(3) { background: #28c840; }
.browser-url {
  flex: 1; min-width: 160px;
  font-family: 'JetBrains Mono', monospace; font-size: 11.5px; color: var(--faint);
  background: var(--bg); border: 1px solid var(--line-2); border-radius: 999px;
  padding: 6px 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.browser-tools { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.browser-tools button, .browser-tools .btn {
  font-family: 'JetBrains Mono', monospace; font-size: 11px; padding: 6px 12px;
  border-radius: 999px; border: 1px solid var(--line-2); background: var(--surface);
  color: var(--muted); cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background-color 0.2s;
}
.browser-tools button:hover { color: var(--sun-deep); border-color: var(--sun); }
.browser-tools button.on { color: var(--sun-deep); border-color: var(--sun); background: var(--sun-soft); }
.browser-tools .btn { border-color: var(--line-2); box-shadow: none; color: var(--ink); font-weight: 700; }

.browser-stage { position: relative; max-width: 100%; margin: 0 auto; background: var(--bg-2); transition: max-width 0.45s cubic-bezier(0.2, 0.7, 0.2, 1); }
.browser-frame[data-device="tablet"] .browser-stage { max-width: 768px; }
.browser-frame[data-device="mobile"] .browser-stage { max-width: 400px; }

/* Lazy preview: a placeholder until the frame is requested or scrolled to,
   then a wrapper holding the injected <iframe> (both built by main.js §07). */
.frame-load {
  display: grid; place-items: center; gap: 6px; width: 100%; height: 620px;
  padding: 24px; cursor: pointer; border: 0; text-align: center;
  background:
    radial-gradient(ellipse at 50% 40%, var(--sky-soft), transparent 68%),
    var(--bg-2);
  color: var(--muted);
  transition: background-color 0.25s ease, color 0.25s ease;
}
.frame-load:hover { color: var(--ink); }
.frame-load__play {
  width: 52px; height: 52px; border-radius: 999px; display: grid; place-items: center;
  background: var(--grad-accent); color: var(--on-accent); font-size: 15px; padding-left: 3px;
  box-shadow: var(--shadow-sm); margin-bottom: 6px;
  transition: transform 0.25s ease;
}
.frame-load:hover .frame-load__play { transform: scale(1.07); }
.frame-load b { font-family: 'Sora', sans-serif; font-size: 15px; font-weight: 800; color: var(--ink); }
.frame-load em {
  font-style: normal; font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; color: var(--faint); max-width: 40ch;
}
/* Once a frame is loaded the placeholder goes away but a way back stays:
   without it a blocked or slow third party left a permanent empty box, since
   the load button was removed and data-loaded was already "1". */
.browser-stage .frame-reload { display: none; }
.browser-stage.is-loaded .frame-load { display: none; }
.browser-stage.is-loaded .frame-reload {
  display: inline-flex; align-items: center; gap: 7px;
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%); z-index: 2;
  padding: 7px 14px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--muted);
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; letter-spacing: 0.08em;
  text-transform: uppercase; box-shadow: var(--shadow-sm);
}
.browser-stage.is-loaded .frame-reload:hover { color: var(--sun-deep); border-color: var(--line-glow); }
/* Say plainly that the frame is a sandboxed third party. */
.frame-privacy {
  margin: 18px 0 0; text-align: center;
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--faint);
}
/* The wrapper is script-created; the <iframe> inside carries its own pixel
   width/height inline, because a replaced element has no other sizing source
   and would otherwise fall back to the 300×150 default (the 2026-10 live bug:
   the inner site rendered as a sliver in the top-left corner). */
.frame-embed { display: block; width: 100%; height: 620px; border: 0; }

.frame-note {
  margin: 14px 0 0; display: flex; align-items: center; justify-content: center; gap: 12px;
  color: var(--faint); font-size: 12px; font-family: 'JetBrains Mono', monospace;
  text-align: center; flex-wrap: wrap;
}
.frame-note img {
  width: 44px; height: 44px; border-radius: 50%; object-fit: cover;
  border: 1px solid var(--line-2); box-shadow: var(--shadow-sm); flex: 0 0 auto;
}

/* ── 11 Insights / poem / code ────────────────────────────── */
.ins-card { padding: 28px; }
.ins-card .tag {
  display: inline-block; font-family: 'JetBrains Mono', monospace; font-size: 10px;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--leaf); border: 1px solid var(--line-2); background: var(--leaf-soft);
  border-radius: 6px; padding: 4px 10px; margin-bottom: 14px;
}
.ins-card h3 { margin: 0 0 10px; font-size: 1.12rem; font-weight: 800; line-height: 1.5; }
.ins-card p { margin: 0; color: var(--muted); font-size: 13.8px; }
.ins-card p code { font-size: 0.92em; background: var(--surface-2); border: 1px solid var(--line); border-radius: 5px; padding: 1px 5px; }
.ins-card .eng {
  display: block; margin-top: 10px; font-family: 'JetBrains Mono', monospace;
  font-size: 11px; color: var(--faint);
}

.code-row { display: grid; grid-template-columns: 1.2fr 1fr; gap: 22px; margin-top: 22px; }

/* ── 12 Matrix panel — phosphor CRT + digital rain ──────────
   一块“屏幕”：近黑玻璃、绿色磷光、内凹暗角（显像管弧度）。
   雨见下方 .rain-col —— 每列是一条拖着尾迹的彗星：
   流头近白，尾迹渐隐成暗绿，落出屏底后换列重来。          */
.code-card {
  --crt-inset:
    inset 0 0 0 1px rgba(0, 0, 0, 0.90),
    inset 0 0 24px rgba(0, 0, 0, 0.80),
    inset 0 0 90px rgba(0, 0, 0, 0.72),
    inset 0 30px 70px -40px rgba(140, 255, 190, 0.22);
  background:
    radial-gradient(ellipse 62% 52% at 50% 46%, rgba(16, 76, 40, 0.40), rgba(6, 26, 13, 0.22) 55%, transparent 78%),
    radial-gradient(ellipse 130% 110% at 50% 45%, #06140b 0%, #030a05 58%, #010402 100%);
  border-color: rgba(31, 224, 106, 0.30);
  min-height: 480px;
  box-shadow: var(--crt-inset), 0 0 0 1px rgba(0, 0, 0, 0.55), 0 20px 46px -26px rgba(0, 44, 16, 0.90);
}
.code-card::before {
  left: 0; right: 0; height: 1px; opacity: 0.6;
  background: linear-gradient(90deg, transparent, rgba(31, 224, 106, 0.80), transparent);
}
.code-card:hover {
  border-color: rgba(31, 224, 106, 0.50);
  box-shadow: var(--crt-inset), 0 0 0 1px rgba(31, 224, 106, 0.32), 0 24px 54px -26px rgba(0, 60, 22, 0.95);
}

/* 老式显示器：扫描线 + 荫罩彩纹 + 玻璃高光 + 下滚回扫亮带 */
.crt {
  position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background:
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.34) 0 1px, rgba(0, 0, 0, 0) 1px 3px),
    repeating-linear-gradient(90deg, rgba(255, 40, 90, 0.035) 0 1px, rgba(40, 255, 140, 0.030) 1px 2px, rgba(40, 120, 255, 0.035) 2px 3px),
    radial-gradient(ellipse 58% 46% at 50% 38%, rgba(90, 255, 160, 0.10), transparent 68%);
  animation: crt-flicker 3.6s ease-in-out infinite;
}
.crt::before {
  content: ""; position: absolute; left: -5%; right: -5%; top: 0; height: 24%;
  background: linear-gradient(180deg, transparent, rgba(150, 255, 195, 0.050) 45%, rgba(215, 255, 235, 0.085) 50%, transparent);
  animation: crt-roll 7s linear infinite;
}
.crt::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(118deg, rgba(255, 255, 255, 0.080) 0%, rgba(255, 255, 255, 0.022) 20%, transparent 42%);
  mix-blend-mode: screen;
}
@keyframes crt-flicker {
  0%, 100% { opacity: 0.97; }
  38%      { opacity: 1; }
  52%      { opacity: 0.93; }
  68%      { opacity: 1; }
}
@keyframes crt-roll {
  0%   { transform: translateY(-100%); }
  100% { transform: translateY(417%); }
}

.code-tag {
  position: absolute; top: 12px; right: 16px; z-index: 4;
  font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--matrix-body);
  text-shadow: 0 0 10px var(--matrix-glow);
}
.code-tag::before {
  content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 7px;
  border-radius: 50%; background: var(--matrix-body);
  box-shadow: 0 0 8px var(--matrix-body);
  animation: blink 1.2s steps(1) infinite;
}
/* 屏幕左下角的读数：与旁边的诗卡相呼应的一句话 */
.code-osd {
  position: absolute; left: 18px; bottom: 13px; z-index: 4; margin: 0;
  font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: 0.06em;
  color: rgba(31, 224, 106, 0.70);
  text-shadow: 0 0 10px rgba(31, 224, 106, 0.45);
}
.code-osd b { color: var(--matrix-head); font-weight: 700; }
.code-caret {
  display: inline-block; width: 7px; height: 12px; margin-left: 7px; vertical-align: -1px;
  background: var(--matrix-body); box-shadow: 0 0 10px var(--matrix-glow);
  animation: blink 1.1s steps(1) infinite;
}

/* 数字雨：JS 只铺一次网格（列 = 一条拖着尾迹的彗星），
   位移由单个 transform 动画驱动，字符亮度在生成时算好，
   因此没有逐字动画 / 逐帧重绘，开销只有几十个合成层。 */
.code-rain { position: absolute; inset: 0; z-index: 1; overflow: hidden; }

.rain-col {
  position: absolute; top: 0; width: 16px;
  animation: col-fall linear infinite;
}
@keyframes col-fall {
  from { transform: translate3d(0, var(--y0, -100px), 0); }
  to   { transform: translate3d(0, var(--y1, 480px), 0); }
}
/* One glyph is one span; there are several hundred of them, so the tail
   carries no text-shadow (the alpha is pre-computed per glyph in main.js)
   and only the ~38 stream heads glow. */
.char {
  position: absolute; left: 0;
  font-family: 'JetBrains Mono', 'MS Gothic', 'Yu Gothic', Consolas, monospace;
  font-size: 15px; line-height: 1; font-style: normal;
  color: var(--matrix-body);
  text-shadow: none;
}
.char-head { color: var(--matrix-head); text-shadow: 0 0 12px rgba(200, 255, 225, 0.95), 0 0 28px rgba(31, 224, 106, 0.70); }

/* 点中一个字符之后：屏幕冻结（JS 把每列的 playbackRate 缓动到 ~0），
   流头收掉光晕，像整块屏被按住暂停。 */
.code-rain.is-frozen .char-head {
  color: var(--matrix-body);
  text-shadow: 0 0 9px rgba(31, 224, 106, 0.55);
}

/* 停格期间从源码里弹出的一块 Python：近黑的荧光屏上唯一清晰的东西，
   逐行淡入，5–10 秒后逐行崩塌。 */
.code-block {
  position: absolute; left: 50%; top: 50%; z-index: 5;
  width: max-content; max-width: 88%;
  padding: 10px 14px 12px;
  transform: translate(-50%, -50%);
  font-family: 'JetBrains Mono', monospace; font-size: 12.5px; line-height: 1.75;
  white-space: pre; overflow: hidden; text-align: left;
  color: var(--matrix-head);
  background: rgba(3, 12, 7, 0.82);
  border: 1px solid rgba(31, 224, 106, 0.34);
  border-radius: 3px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.70), 0 0 30px rgba(31, 224, 106, 0.20);
  text-shadow: 0 0 9px rgba(31, 224, 106, 0.45);
}
.cb-head {
  display: block; margin-bottom: 6px; padding-bottom: 5px;
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--matrix-body); border-bottom: 1px solid rgba(31, 224, 106, 0.22);
}
.cb-line { display: block; }

/* 提示：屏幕可以点；键盘与触摸走同一轮的按钮在右上角 */
.code-hint {
  margin: 14px 2px 0;
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--faint);
}
.code-hint::before {
  content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 8px;
  border-radius: 50%; background: var(--matrix-body);
  box-shadow: 0 0 8px var(--matrix-glow); opacity: 0.75;
}
/* The rain itself is aria-hidden, so the interaction needs a real control:
   this is the keyboard/touch equivalent of tapping a stream head. */
.code-tap {
  position: absolute; top: 12px; left: 16px; z-index: 4;
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid rgba(31, 224, 106, 0.38);
  background: rgba(3, 12, 7, 0.72); color: var(--matrix-body);
  font-family: 'JetBrains Mono', monospace; font-size: 10px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  transition: border-color 0.25s ease, color 0.25s ease;
}
.code-tap:hover { color: var(--matrix-head); border-color: rgba(31, 224, 106, 0.75); }

/* 静态代码（无 JS / 关闭动画时的兜底）：同一块屏幕上的终端 */
pre.code {
  position: relative; z-index: 2;
  margin: 0; padding: 30px 30px 48px; overflow-x: auto;
  font-family: 'JetBrains Mono', monospace; font-size: 13px; line-height: 1.8;
  color: var(--code-ink); background: transparent;
  text-shadow: 0 0 10px var(--matrix-glow);
}
pre.code::-webkit-scrollbar { height: 8px; }
pre.code::-webkit-scrollbar-thumb { background: var(--matrix-body); }
pre.code .c-k { color: var(--tok-k); }
pre.code .c-t { color: var(--tok-t); }
pre.code .c-f { color: var(--tok-f); }
pre.code .c-s { color: var(--tok-s); }
pre.code .c-m { color: var(--tok-m); }
pre.code .c-p { color: var(--tok-p); }

/* 定场诗 —— 双燕归画堂：诗仍是主角，UI 只做「屏上的诗笺」，
   所以沿用全站的 blueprint 网格 / HUD 角标，另加一抹燕羽的春色。 */
.poem-card {
  --swallow-a: var(--sky);
  --swallow-b: var(--leaf);
  position: relative;
  padding: 30px 32px 28px;
  display: flex; flex-direction: column;
  border-color: color-mix(in srgb, var(--swallow-b) 26%, var(--line-2));
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.35);
  background-color: var(--surface);
  background-image:
    radial-gradient(120% 84% at 50% -6%, color-mix(in srgb, var(--swallow-b) 11%, transparent), transparent 62%),
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 100% 100%, 40px 40px, 40px 40px;
  background-position: center, center, center;
}
.poem-card:hover { border-color: color-mix(in srgb, var(--swallow-b) 55%, var(--line-glow)); }
/* 夜底：白描高光换成一层幽微的羽色反光 */
html[data-theme="night"] .poem-card {
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(234, 242, 255, 0.06);
}

/* 诗题：终端提示符 + 汉字，兼作 lang="zh" 的锚点（中文时点亮） */
.poem-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; margin: 0 0 20px;
}
.poem-label {
  margin: 0; font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--faint);
}
:lang(zh) .poem-label { color: var(--sun-deep); letter-spacing: 0.2em; }

/* 双燕：同一首诗的插图，中文时收起，让汉字自己站住 */
.poem-art { flex: 0 0 auto; width: 104px; height: auto; overflow: visible; }
html[lang^="zh"] .poem-art { display: none; }
.poem-art .pa-body, .poem-art .pa-tail { fill: var(--swallow-a); }
.poem-art .pa-wing { fill: var(--swallow-b); }
.poem-art .pa-flock { animation: swallow-glide 11s ease-in-out infinite; }
.poem-art .pa-bird-b { animation: swallow-lag 2.6s ease-in-out infinite; }
.poem-art .pa-trail {
  fill: none; stroke: var(--swallow-b); stroke-width: 1.3; stroke-linecap: round;
  stroke-dasharray: 2 5.5; opacity: 0.45;
  animation: swallow-trail 5.2s linear infinite;
}
@keyframes swallow-glide {
  0%, 100% { transform: translate(0, 0) rotate(0.8deg); }
  50%      { transform: translate(2.5px, -3px) rotate(-0.9deg); }
}
@keyframes swallow-lag {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(-1.2px, -1.6px); }
}
@keyframes swallow-trail { to { stroke-dashoffset: -14; } }

/* 五言八句：一句一行；联内两行挨紧、联间留一口气。
   两种语言互斥显示 —— 中文写在标记里、英文由 JS 注入，永远只出现一种。 */
.poem { margin: 0 auto; max-width: 420px; text-align: center; }
.poem-cn {
  margin: 0; padding: 0;
  font-family: 'Noto Serif SC', 'Songti SC', SimSun, serif;
  font-size: clamp(1.06rem, 2.1vw, 1.22rem);
  line-height: 1.72; color: var(--ink); letter-spacing: 0.02em;
}
/* 每联两行靠紧，联与联之间留一口气。中文：3/5/7 行另起一联。
   英文：整段由 JS 注入，以 <br> 切行，靠行高区分即可。 */
.pc-line { display: block; width: fit-content; margin: 0 auto; }
.pc-line:nth-child(odd):not(:first-child) { margin-top: 0.6em; }

.poem-en {
  margin: 0 auto; max-width: 44ch;
  font-family: 'Iowan Old Style', 'Palatino Linotype', 'Noto Serif SC', Georgia, serif;
  font-size: 13.4px; line-height: 1.95; color: var(--muted);
  font-style: italic; letter-spacing: 0.01em;
}

/* 语言互斥：根元素 lang 由 main.js 切换。中文写在标记里（无 JS 也读得见），
   英文在 ZH 字典里；同一时刻只有一种语言的八行在页面上。 */
:lang(zh) .poem-en { display: none; }
html:not([lang^="zh"]) .poem-cn { display: none; }

/* 落款：朱印一句压角，与诗行留出气口 */
.poem-sign {
  display: flex; flex-direction: column; align-items: center;
  margin-top: auto; padding-top: 22px;
}
.seal {
  display: inline-grid; place-items: center; width: 44px; height: 44px;
  border-radius: 11px;
  background: linear-gradient(150deg, #e9684f, #c8442e); color: #fff;
  font-family: 'Noto Serif SC', serif; font-size: 22px; font-weight: 900;
  box-shadow: 0 8px 20px -8px rgba(200, 68, 46, 0.7);
  transform: rotate(-4deg);
  transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.poem-card:hover .seal { transform: rotate(3deg) scale(1.05); }
:lang(zh) .seal { font-size: 24px; }

/* ── 13 Quote banner — aurora poster ──────────────────────── */
.quote-banner {
  position: relative; z-index: 1; min-height: 56vh;
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: 96px 24px; overflow: hidden;
}
.quote-bg {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  filter: saturate(0.55) contrast(0.96) brightness(1.02);
}
.quote-overlay {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, var(--ov) 0%, var(--ov-mid) 45%, var(--ov) 100%);
}
.quote-grid {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 48px 48px, 48px 48px;
  -webkit-mask-image: radial-gradient(ellipse 70% 80% at 50% 50%, #000, transparent 82%);
  mask-image: radial-gradient(ellipse 70% 80% at 50% 50%, #000, transparent 82%);
}
.quote-inner { position: relative; max-width: 820px; }
.quote-mark { font-family: 'Noto Serif SC', serif; font-size: 3.4rem; color: var(--sky); line-height: 1; margin-bottom: 6px; }
#quote {
  margin: 0; font-family: 'Sora', 'Noto Serif SC', sans-serif;
  font-size: clamp(1.3rem, 3.4vw, 1.85rem); font-weight: 700; letter-spacing: 0.02em;
  color: var(--ink); line-height: 1.85; transition: opacity 0.45s ease;
}
#quote-author {
  display: block; margin-top: 18px; font-style: normal; font-family: 'JetBrains Mono', monospace;
  font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--sun-deep);
  transition: opacity 0.45s ease;
}

/* ── 14 Contact / footer ──────────────────────────────────── */
/* Channel cards — six direct lines of contact */
.contact-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
  margin-top: 8px;
}
.contact-card {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: 6px;
  padding: 24px 24px 22px; border-radius: var(--hud-radius);
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  transition: transform 0.28s ease, box-shadow 0.28s ease, border-color 0.28s ease;
}
.contact-card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--grad-tech);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 0.4s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.contact-card:hover, .contact-card:focus-within {
  transform: translateY(-5px);
  border-color: var(--line-glow);
  box-shadow: var(--shadow-lg), 0 0 0 1px var(--line-glow);
}
.contact-card:hover::before, .contact-card:focus-within::before { transform: scaleX(1); }
.contact-card__icon {
  width: 42px; height: 42px; display: grid; place-items: center; color: var(--sky);
  border-radius: 12px; background: var(--surface-2); border: 1px solid var(--line-2);
  margin-bottom: 8px;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.contact-card:hover .contact-card__icon { color: var(--sun-deep); border-color: var(--line-glow); }
.contact-card__label {
  font-family: 'JetBrains Mono', monospace; font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--sky);
}
.contact-card b {
  font-family: 'Sora', 'Noto Serif SC', sans-serif;
  font-size: 1.02rem; font-weight: 800; color: var(--ink); line-height: 1.4;
  word-break: break-word;
}
.contact-card em {
  font-style: normal; font-size: 12.5px; color: var(--faint); line-height: 1.6;
}
.contact-card__go {
  position: absolute; top: 18px; right: 20px;
  font-family: 'JetBrains Mono', monospace; font-size: 13px; color: var(--faint);
  transition: color 0.25s ease, transform 0.25s ease;
}
.contact-card:hover .contact-card__go { color: var(--neon); transform: translate(2px, -2px); }

/* Contact telemetry console */
.contact-panel {
  margin-top: 22px; border-radius: var(--hud-radius); overflow: hidden;
  border: 1px solid var(--line-2); background: var(--surface);
  box-shadow: var(--shadow-md);
}
.contact-panel__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 18px; border-bottom: 1px solid var(--line);
  background: var(--surface-2);
  font-family: 'JetBrains Mono', monospace; font-size: 11.5px;
  flex-wrap: wrap;
}
.contact-panel__title { display: inline-flex; align-items: center; gap: 8px; color: var(--muted); font-weight: 700; }
.contact-panel__title i { font-style: normal; color: var(--neon); }
.contact-panel__sig {
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--leaf); font-size: 10px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
}
/* Which of the two availability lines shows is decided by the real Sydney
   hour (main.js §07d). With no JS neither shows, rather than claiming
   something about the time that may be untrue. */
.contact-panel__sig .avail-on,
.contact-panel__sig .avail-off { display: none; }
html.js #avail.is-on .avail-on { display: inline; }
html.js #avail.is-off .avail-off { display: inline; }
.contact-panel__body { padding: 6px 18px 16px; }
.contact-panel__row {
  display: grid; grid-template-columns: 86px 1fr; gap: 14px; align-items: baseline;
  margin: 0; padding: 11px 0;
  border-bottom: 1px dashed var(--line);
  font-family: 'JetBrains Mono', monospace; font-size: 12px;
}
.contact-panel__row:last-child { border-bottom: 0; }
.contact-panel__row span {
  color: var(--sky); font-size: 10px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
}
.contact-panel__row b { color: var(--text); font-weight: 500; line-height: 1.7; }

.footer {
  position: relative; z-index: 1; margin-top: 40px;
  background: var(--footer-bg); color: var(--footer-dim);
  padding: 48px 24px 36px;
  border-top: 1px solid var(--line-2);
}
/* Luminous hairline + faint blueprint grid over the dark plate */
.footer::before {
  content: ""; position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: var(--grad-hair);
}
.footer::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(var(--footer-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--footer-grid) 1px, transparent 1px);
  background-size: 56px 56px;
  -webkit-mask-image: linear-gradient(180deg, #000, transparent 70%);
  mask-image: linear-gradient(180deg, #000, transparent 70%);
}
.footer > * { position: relative; z-index: 1; }
.foot-grid { display: flex; justify-content: space-between; gap: 26px; flex-wrap: wrap; }
.foot-brand { font-family: 'Sora', sans-serif; font-size: 1.05rem; font-weight: 800; letter-spacing: 0.02em; color: var(--footer-brand); }
.foot-brand small {
  display: block; font-family: 'Manrope', sans-serif; font-size: 11.5px; font-weight: 500;
  color: var(--footer-dim); letter-spacing: 0.02em; margin-top: 6px;
}
.foot-credits { max-width: 620px; font-size: 11.5px; line-height: 1.9; }
.foot-credits a { color: var(--footer-link); }
.foot-credits a:hover { color: var(--footer-link-hover); }
.foot-copy {
  width: 100%; margin-top: 16px; padding-top: 16px; border-top: 1px dashed var(--footer-rule);
  font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--footer-dim);
  display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
}

/* ── 17 Currency cues — "what I am doing now" ─────────────
   A small mono line at the foot of a card. It is what keeps a
   30-year CV from reading as a museum label.                     */
.card-now {
  margin: 16px 0 0; padding-top: 12px; border-top: 1px dashed var(--line);
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; line-height: 1.7;
  color: var(--muted); display: flex; gap: 8px; align-items: baseline;
}
.card-now b {
  flex: 0 0 auto; color: var(--leaf);
  font-size: 9px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
}
.card-now span { min-width: 0; }

.stats-note {
  margin: 12px 0 0; text-align: center;
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--faint);
}

/* ── 18 AI direction + Now/Next ───────────────────────────── */
.ai-card { padding: 26px 26px 24px; }
.ai-top { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.ai-num {
  flex: 0 0 auto; font-family: 'JetBrains Mono', monospace;
  font-size: 10px; font-weight: 700; letter-spacing: 0.14em;
  color: var(--sun-deep); padding: 3px 7px; border-radius: 7px;
  border: 1px solid var(--line-2); background: var(--surface-2);
}
.ai-top h3 { flex: 1 1 auto; min-width: 0; font-size: 1.12rem; font-weight: 800; letter-spacing: -0.015em; }
.ai-tag {
  flex: 0 0 auto; font-family: 'JetBrains Mono', monospace;
  font-size: 9px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--leaf); padding: 3px 8px; border-radius: 999px;
  background: var(--leaf-soft); border: 1px solid transparent;
}
.ai-card p { margin: 0; font-size: 14.5px; line-height: 1.78; color: var(--text); }
.ai-list { margin: 14px 0 0; padding: 0; list-style: none; display: grid; gap: 7px; }
.ai-list li {
  position: relative; padding-left: 17px;
  font-family: 'JetBrains Mono', monospace; font-size: 11.5px; line-height: 1.65; color: var(--muted);
}
.ai-list li::before {
  content: "▸"; position: absolute; left: 0; top: 0; color: var(--neon);
}

.now-card { margin-top: 22px; padding: 0; overflow: hidden; }
.now-head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  flex-wrap: wrap; padding: 16px 24px; border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}
.now-head h3 { font-size: 1.05rem; font-weight: 800; letter-spacing: -0.01em; }
.now-stamp {
  display: inline-flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--muted);
}
.now-stamp > span { color: var(--faint); font-size: 9px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; }
.now-stamp b { color: var(--sun-deep); font-weight: 700; }
.now-body { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.now-col { padding: 20px 24px; border-right: 1px dashed var(--line); min-width: 0; }
.now-col:last-child { border-right: 0; }
.now-label {
  margin: 0 0 10px; font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--sky);
}
.now-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.now-list li {
  position: relative; padding-left: 16px;
  font-size: 13px; line-height: 1.68; color: var(--text);
}
.now-list li::before {
  content: "·"; position: absolute; left: 3px; top: -1px;
  color: var(--neon); font-size: 17px; line-height: 1.3;
}
.now-foot {
  margin: 0; padding: 14px 24px 18px; border-top: 1px dashed var(--line);
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; line-height: 1.85; color: var(--faint);
}

/* ── 16 Overlays — search palette + back to top ─────────────
   The palette contains two things: commands and section links, which are
   static markup so they translate with the rest of the page, and hits built
   from the page's own text by main.js. Search never leaves the browser, and
   the footer of the box says so. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.palette {
  position: fixed; inset: 0; z-index: 90; display: none;
  align-items: flex-start; justify-content: center;
  padding: 11vh 16px 24px;
}
.palette.open { display: flex; }
.palette__scrim {
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--ink) 45%, transparent);
}
.palette__box {
  position: relative; width: min(620px, 100%); max-height: 74vh;
  display: flex; flex-direction: column;
  border-radius: var(--r-md); overflow: hidden;
  border: 1px solid var(--line-2); background: var(--menu-bg);
  box-shadow: var(--shadow-lg);
  animation: tray-in 0.16s ease-out;
}
.palette__bar {
  display: flex; align-items: center; gap: 10px; padding: 12px 14px;
  border-bottom: 1px solid var(--line); color: var(--faint);
}
.palette__bar input {
  flex: 1; min-width: 0; border: 0; background: transparent; color: var(--ink);
  font-family: 'Manrope', sans-serif; font-size: 15px;
}
.palette__bar input:focus { outline: none; }
.palette__esc {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer; flex: 0 0 auto;
  padding: 5px 10px; border-radius: var(--r-pill); border: 1px solid var(--line-2);
  background: var(--surface-2); color: var(--muted);
  font-family: 'JetBrains Mono', monospace; font-size: 10px;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.palette__esc kbd { font-family: inherit; font-size: 10px; }
.palette__list { margin: 0; padding: 8px; list-style: none; overflow-y: auto; }
.palette__sec {
  padding: 10px 10px 6px; font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--faint);
}
.palette__sec[hidden] { display: none; }
.palette__item {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  padding: 10px 12px; border-radius: 10px;
  color: var(--text); font-size: 14px;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.palette__item[hidden] { display: none; }
.palette__item .ico { color: var(--sky); }
.palette__item[aria-selected="true"] { background: var(--surface-2); color: var(--ink); }
.palette__item[aria-selected="true"] .ico { color: var(--sun-deep); }
.palette__hit { flex-direction: column; align-items: flex-start; gap: 3px; }
.palette__hit b { font-family: 'JetBrains Mono', monospace; font-size: 11.5px; color: var(--sun-deep); }
.palette__hit em { font-style: normal; font-size: 12.5px; color: var(--muted); line-height: 1.65; }
.palette__foot {
  margin: 0; padding: 10px 14px; border-top: 1px solid var(--line);
  background: var(--surface-2); color: var(--faint);
  font-family: 'JetBrains Mono', monospace; font-size: 10px;
  display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap;
}
.palette__foot em { font-style: normal; }

.to-top {
  position: fixed; right: 18px; bottom: 18px; z-index: 80;
  width: 42px; height: 42px; display: grid; place-items: center; cursor: pointer;
  border-radius: 50%; border: 1px solid var(--line-2); background: var(--surface);
  color: var(--muted); box-shadow: var(--shadow-md);
  opacity: 0; pointer-events: none; transform: translateY(8px);
  transition: opacity 0.25s ease, transform 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
.to-top.on { opacity: 1; pointer-events: auto; transform: none; }
.to-top:hover { color: var(--sun-deep); border-color: var(--line-glow); }

/* ── 17 Responsive ────────────────────────────────────────── */
/* Progressive retreat of the wide row. Each step hands more of the
   nav to the overflow tray, so the row never clips its last item. */

/* Tight desktop — trim the index readout and inner padding */
@media (max-width: 1240px) {
  .nav-inner { gap: 10px; padding: 0 18px; }
  .menu > a { padding: 8px 9px; font-size: 13px; }
  .menu > a::after { left: 9px; right: 9px; }
  .nav-brand__text em { display: none; }
}

/* Laptop — retired to the tray: ai, insights, ventures, stack */
@media (max-width: 1120px) {
  .nav-more { display: block; }
  .menu > a[data-scroll="#ai"],
  .menu > a[data-scroll="#insights"],
  .menu > a[data-scroll="#ventures"],
  .menu > a[data-scroll="#stack"] { display: none; }
}

/* Small laptop / large tablet — the tray covers everything but the
   primary four, which always stay visible. */
@media (max-width: 940px) {
  .menu > a[data-scroll="#career"],
  .menu > a[data-scroll="#projects"] { display: none; }
  .nav-index { display: none; }
}

@media (max-width: 900px) {
  .grid-2, .grid-3, .code-row, .contact-grid { grid-template-columns: 1fr; }
  /* The bento layout is an id-scoped rule, so it has to be undone explicitly
     here — a plain .grid-2 override would lose to #ai .grid-2. */
  #ai .grid-2 { grid-template-columns: 1fr; }
  #ai .ai-card { grid-column: auto; }
  .glance { grid-template-columns: 1fr; }
  .palette { padding-top: 6vh; }
  .sec { padding: 72px 20px; }
  .frame-load, .frame-embed { height: 480px; }
  .now-body { grid-template-columns: 1fr; }
  .now-col { border-right: 0; border-bottom: 1px dashed var(--line); }
  .now-col:last-child { border-bottom: 0; }
  .hero { padding-top: 92px; min-height: auto; }
  .hero-frame { display: none; }
  .tl-item { grid-template-columns: 1fr; gap: 8px; }
  .code-card { min-height: 400px; }
  /* 诗卡独占一行后不再需要撑高，插图也收回数据卡的比例 */
  .poem-card { min-height: 0; padding: 26px 22px 24px; }
  .poem-art { width: 88px; }
  .contact-panel__row { grid-template-columns: 1fr; gap: 2px; }
}

/* Tablet / phone — burger takes over the whole row */
@media (max-width: 800px) {
  .burger { display: block; }
  .menu {
    display: none; position: absolute; top: 72px; left: 14px; right: 14px;
    flex-direction: column; align-items: stretch; gap: 4px; padding: 14px;
    border-radius: var(--hud-radius); background: var(--menu-bg);
    -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
    border: 1px solid var(--line-2); box-shadow: var(--shadow-lg);
    max-height: calc(100vh - 96px); overflow-y: auto;
  }
  .menu.open { display: flex; animation: tray-in 0.2s ease-out; }
  /* Every hidden link comes back inside the tray */
  .menu > a,
  .menu > a[data-scroll="#insights"],
  .menu > a[data-scroll="#ventures"],
  .menu > a[data-scroll="#stack"],
  .menu > a[data-scroll="#ai"],
  .menu > a[data-scroll="#career"],
  .menu > a[data-scroll="#projects"] { display: block; }
  .menu > a { padding: 12px 14px; text-align: center; }
  .menu > a::after { display: none; }
  .nav-index { display: none; }
  .nav-divider { width: 100%; height: 1px; margin: 6px 0; }
  .nav-more { display: none; }        /* redundant once the tray is open */
  .nav-cta { margin-left: 0; text-align: center; }
  .lang-sw { margin: 4px auto 0; }
  .theme-btn { margin: 8px auto 0; }
  .nav-brand__text em { display: block; }
}

@media (max-width: 580px) {
  .stat { min-width: 44%; }
  .browser-tools { width: 100%; justify-content: space-between; }
  .frame-load, .frame-embed { height: 62vh; min-height: 420px; }
  .card-now { flex-direction: column; gap: 3px; }
  .now-head, .now-col, .now-foot { padding-left: 16px; padding-right: 16px; }
  .foot-copy { flex-direction: column; }
  .hud { font-size: 9.5px; gap: 4px 9px; padding: 7px 12px; }
  .hud__sep { display: none; }
  .hero-frame { display: none; }
  .code-card { min-height: 320px; }
  .nav-brand__text { display: none; }
}

/* ── 18 Print — a CV a recruiter can actually keep ──────────
   ⌘P / Ctrl+P used to produce a dark, animated, half-truncated poster. Print
   forces the light palette, drops every decorative layer and every
   interaction-only control, opens the collapsed career list, and writes each
   external URL after its link text. */
@media print {
  :root {
    --bg: #ffffff; --bg-2: #ffffff; --surface: #ffffff; --surface-2: #ffffff;
    --surface-3: #ffffff; --ink: #000000; --text: #1c1c1c; --muted: #333333;
    --faint: #4a4a4a; --line: #cccccc; --line-2: #bbbbbb; --footer-bg: #ffffff;
    --footer-dim: #333333; --footer-brand: #1c1c1c; --footer-link: #1c1c1c;
  }
  html, body { background: #ffffff !important; color: #000000; }
  .bg-mesh, .scanlines, #progress, .nav, .palette, .to-top, .scroll-hint,
  .hero-frame, .hero-grid, .hero-scan, #stars, .quote-banner, .browser-frame,
  .stats-row, .code-row, .hero-cta, .frame-privacy, .career-actions,
  .footer::after, .card::after, .card::before, .contact-card::before { display: none !important; }
  .hero { min-height: 0; padding: 0 0 18px; text-align: left; }
  .hero-inner::before { display: none; }
  .hero-title, .sec-head h2, .hero-sub { -webkit-text-fill-color: #000000; color: #000000; background: none; }
  .sec, .sec-alt { padding: 20px 0; border: 0; background: #ffffff; }
  .sec-alt::before { display: none; }
  .card, .glance__item, .contact-panel, .stat { box-shadow: none; border-color: #cccccc; break-inside: avoid; }
  .grid-2, .grid-3, .contact-grid, .code-row { grid-template-columns: 1fr 1fr; gap: 10px; }
  #ai .grid-2 { grid-template-columns: 1fr 1fr; }
  #ai .ai-card { grid-column: auto; }
  /* Print the whole career, not the collapsed five. */
  html.js .timeline-more { display: flex !important; }
  .career-toggle-more, .career-toggle-less, .career-count { display: none !important; }
  /* A printed page cannot be clicked, so the link's URL has to be visible. */
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9px; color: #555555; word-break: break-all; }
  .footer { background: #ffffff; color: #333333; border-top: 1px solid #cccccc; }
  .foot-brand, .foot-credits a { color: #1c1c1c; }
}

/* ── 19 Reduced motion ────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.js .reveal { opacity: 1; transform: none; transition: none; }
  .mesh, .caret, .scroll-hint, .code-tag::before,
  .grid-overlay-2, .hero-grid, .hero-scan, .nav-scan, .hud__dot,
  .palette__box { animation: none !important; }
  /* 矩阵屏：屏幕的闪烁 / 回扫亮带 / 光标停住，但雨照下 ——
     JS 只把下落与换字放慢（calm / tick）。这块屏是本节的主角，
     把它换成一张不动的静态代码，比缓慢下落的字符更让人意外。
     点击后弹出/崩塌的函数块同理：留在原位，只是不再逐行动。 */
  .crt, .crt::before, .code-caret { animation-play-state: paused !important; }
  .char-head { transition: none !important; }
  /* 双燕：停在半空，不循环飞行 */
  .pa-flock, .pa-bird-b, .pa-trail { animation-play-state: paused !important; }
  /* Transitions on the decorative pseudo-elements were uncovered before, so
     the grid wash and the hairline rules still animated. */
  .card, .card::before, .card::after, .btn, .stat, .stat::before,
  .quote-overlay, #quote, #quote-author, .contact-card, .contact-card::before,
  .contact-card__icon, .contact-card__go, .menu > a, .menu > a::after,
  .nav, .nav-brand, .nav-brand__mark, .nav::after, .nav-frame, .nav-scan,
  .browser-frame, .browser-stage, .frame-load, .frame-load__play,
  .palette__item, .to-top, .glance__item, .code-tap, .seal { transition: none !important; }
  .card:hover, .stat:hover, .btn:hover, .contact-card:hover { transform: none; }
  .frame-load:hover .frame-load__play { transform: none; }
  .poem-card:hover .seal { transform: rotate(-4deg); }
}

