/* ============================================================
   橘子海 ORANGE SEA —— 品牌层
   在 site.css（复刻站模板样式）之上覆盖：字体、排印、导航文字、
   首屏问候、联系区星标动画。site.css 保持模板原样，便于日后复用。
   ============================================================ */

/* ---------- 排版：标题走衬线，正文走品牌无衬线 ---------- */
body { font-family: var(--font-primary); }

.portfolio-hero-heading h1,
.story-logo-module h2,
.story-market-copy,
.story-vision-copy h2,
.story-community-copy h2,
.contact-heading,
.story-gallery-topline strong,
.story-gallery-tab {
  font-family: var(--font-serif);
  font-weight: 600;
}

/* 中文正文的呼吸感：字距略开、行高放宽 */
.portfolio-hero-description span,
.contact-intro,
.story-vision-copy p,
.story-community-copy p,
.contact-help {
  letter-spacing: .02em;
  line-height: 1.7;
}

/* 首屏主标题：中文衬线要更重一点才有分量 */
.portfolio-hero-heading h1 {
  font-weight: 700;
  letter-spacing: .01em;
  line-height: 1.14;
}
.portfolio-hero-title-text {
  background: linear-gradient(180deg, rgba(244, 240, 231, .42), #f4f0e7 78%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ---------- 导航：由 SVG 遮罩图改为文本 ---------- */
.wordmark { width: auto; height: 44px; padding: 0 4px; }
.wordmark-text {
  display: inline-flex; align-items: baseline; gap: 7px;
  font-family: var(--font-serif);
  font-size: 19px; font-weight: 600; letter-spacing: .06em; line-height: 1;
  white-space: nowrap;
}
.brand-mark {
  font-style: normal; font-size: 15px; line-height: 1;
  color: var(--warm); transform: translateY(-1px);
}
.pill-nav { gap: 22px; }
.pill-nav a { padding: 0 12px; }
.nav-text {
  font-family: var(--font-primary);
  font-size: 14px; font-weight: 500; letter-spacing: .08em; line-height: 1;
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .wordmark-text, .nav-text { transition: transform .26s cubic-bezier(.16,1,.3,1), opacity .2s; }
  .wordmark:hover .wordmark-text,
  .pill-nav a:hover .nav-text { transform: translateY(-2px); }
}
@media (max-width: 720px) {
  .wordmark { width: auto; }
  .wordmark-text { font-size: 17px; }
  .nav-text { font-size: 13px; letter-spacing: .04em; }
  .pill-nav { gap: 6px; }
  .pill-nav a { padding: 0 7px; }
}

/* ---------- 首屏问候：改为品牌文本 ---------- */
.portfolio-hero-greeting {
  align-items: baseline; gap: 8px;
  margin: 0 0 clamp(30px, 3.4vw, 46px);
}
.portfolio-hero-greeting-text {
  font-family: var(--font-serif);
  font-size: clamp(20px, 1.9vw, 27px);
  font-weight: 500; letter-spacing: .08em; line-height: 1.2;
  color: var(--ink);
}
.portfolio-hero-greeting-moon {
  color: var(--warm); font-size: 22px; font-style: normal;
  animation: mark-breathe 4.6s ease-in-out infinite;
}
@keyframes mark-breathe {
  0%, 100% { transform: translateY(1px) scale(1); opacity: .82; }
  50%      { transform: translateY(0) scale(1.14); opacity: 1; }
}

/* 首屏角色标签：中文无衬线，渐隐到右侧 */
.portfolio-hero-description strong {
  background: linear-gradient(90deg, var(--ink), rgba(244, 240, 231, .42));
  -webkit-background-clip: text; background-clip: text;
  min-width: 116px; font-size: 18px; font-weight: 600; line-height: 1.28;
  letter-spacing: .04em;
}
.portfolio-hero-description span { color: rgba(244, 240, 231, .5); max-width: 520px; }

/* ---------- 品牌墙 ---------- */
.story-logo-module h2 { letter-spacing: .1em; }
.story-logo-set li { font-family: var(--font-primary); font-size: 14px; letter-spacing: .04em; }
.story-logo-set img { height: 30px; }

/* ---------- 滚动叙事 ---------- */
.story-market-copy { font-size: clamp(30px, 3.4vw, 54px); letter-spacing: .04em; }
.story-market-copy span:nth-child(3) { font-size: .58em; letter-spacing: .06em; }
.story-vision-copy h2 { letter-spacing: .05em; line-height: 1.24; }
.story-community-copy h2 { letter-spacing: .05em; line-height: 1.24; }
.story-community-title-secondary { margin-top: 6px; }
.story-speech { font-size: 14px; letter-spacing: .06em; }
.story-icon-cluster span { font-family: var(--font-primary); font-size: 13px; letter-spacing: .06em; }

/* ---------- 联系区 ---------- */
.contact-heading-lead { font-size: clamp(30px, 3vw, 50px); letter-spacing: .06em; }
.contact-heading strong { font-size: clamp(46px, 5vw, 82px); letter-spacing: .06em; }
.contact-heading-highlight { background: var(--warm); color: #0a1714; }
.contact-label { background: var(--ink); color: #0a1714; font-family: var(--font-primary); letter-spacing: .08em; }
.email-link strong {
  font-family: var(--font-mono);
  font-size: clamp(18px, 2vw, 26px); font-weight: 600; letter-spacing: -.01em;
}
.email-link:hover strong:after, .email-link:focus-visible strong:after { background: var(--warm); }

/* GitHub 文本链接，对齐 jzhm.fun 的写法 */
.social-row { margin-top: 20px; }
.social-row > .social-link {
  display: inline-flex; align-items: center; gap: 10px;
  color: var(--ink); font-size: 15px; letter-spacing: .04em;
  border-bottom: 1px solid var(--line); padding-bottom: 6px;
  transition: color .22s, border-color .22s, transform .28s cubic-bezier(.22,1,.36,1);
}
.social-row > .social-link i { font-style: normal; color: var(--brand); transition: transform .28s cubic-bezier(.22,1,.36,1), color .22s; }
.social-row > .social-link:hover, .social-row > .social-link:focus-visible { color: var(--warm); border-color: var(--warm); transform: translateY(-2px); }
.social-row > .social-link:hover i, .social-row > .social-link:focus-visible i { transform: translate(3px, -3px); color: var(--warm); }

/* ---------- 音乐面板：播放进度线 ---------- */
.music-track { position: relative; }
.music-track-bar {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px;
  background: rgba(244, 240, 231, .1);
  overflow: hidden;
}
.music-track-bar > i {
  display: block; height: 100%;
  background: linear-gradient(90deg, #8de6b2 0%, #f6a26f 100%);
  transform-origin: 0;
  transform: scaleX(var(--music-progress, 0));
  transition: transform .25s linear;
}
:root[data-theme=light] .music-track-bar { background: rgba(13, 26, 23, .12); }

/* ---------- 邮箱：复制按钮 + 信封开盖 ---------- */
/* 复制没做成「点地址就复制」——点地址是写邮件，两件事抢一个动作会都做不好 */
.email-row {
  position: relative;                  /* 提示与纸船以此为基准 */
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
  margin-top: 28px;
}
.email-row .email-link { margin-top: 0; }

.email-copy {
  flex: none;
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  color: var(--muted);
  background: var(--soft-surface);
  border: 1px solid var(--line);
  cursor: pointer;
  transition: color .22s, background .22s, border-color .22s, transform .28s cubic-bezier(.22,1,.36,1);
}
.email-copy svg { width: 16px; height: 16px; }
.email-copy:hover, .email-copy:focus-visible {
  color: var(--warm); background: var(--soft-surface-hover);
  border-color: var(--warm); transform: translateY(-2px);
}
.email-copy.is-done { color: var(--brand); border-color: var(--brand); }

/* 信封盖：hover 时整个 V 翻到信封上方。transform-origin 由 site.css
   的 .mail-open 提供（fill-box 的 50% 0，即 V 的顶边中点）。 */
.email-link .mail-open { transition: transform .42s cubic-bezier(.16,1,.3,1), opacity .42s; }
.email-link:hover .mail-open,
.email-link:focus-visible .mail-open { transform: scaleY(-1); opacity: .62; }

.email-toast {
  position: absolute; left: 0; bottom: calc(100% + 10px);
  display: flex; align-items: center; gap: 8px;
  padding: 7px 13px;
  border-radius: 999px;
  background: var(--modal-bg);
  border: 1px solid var(--line);
  color: var(--ink);
  font-size: 12px; letter-spacing: .06em; white-space: nowrap;
  opacity: 0; transform: translateY(6px);
  pointer-events: none;
  transition: opacity .28s, transform .34s cubic-bezier(.16,1,.3,1);
}
.email-toast.is-on { opacity: 1; transform: translateY(0); }
.email-toast svg { width: 15px; height: 15px; color: var(--warm); }
.email-toast.is-on svg { animation: boat-sail 1.6s cubic-bezier(.3,.9,.4,1) both; }
@keyframes boat-sail {
  from { transform: translate(-5px, 4px) rotate(-9deg); opacity: .25; }
  55%  { transform: translate(6px, -4px) rotate(4deg); opacity: 1; }
  to   { transform: translate(0, 0) rotate(0); opacity: 1; }
}

/* ---------- 联系区品牌动效：落日海面 ----------
   .contact-video-frame 的方框尺寸与四边羽化遮罩沿用模板，
   画布内容由 js/contact-scene.js 绘制。 */
.contact-scene-frame {
  position: relative;
  background: #07100f;
  overflow: hidden;
}
.contact-scene-canvas {
  display: block;
  width: 100%;
  height: 100%;
  /* 与模板 .contact-video 相同的四边羽化，让画面融进页面而不是一块硬边方块 */
  -webkit-mask-image:
    linear-gradient(90deg, #0000 0%, #000 18% 82%, #0000 100%),
    linear-gradient(#0000 0%, #000 18% 82%, #0000 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(90deg, #0000 0%, #000 18% 82%, #0000 100%),
    linear-gradient(#0000 0%, #000 18% 82%, #0000 100%);
  mask-composite: intersect;
}
@media (prefers-reduced-motion: reduce) {
  .contact-scene-canvas { /* 静态帧由 JS 绘制，这里只保证边缘仍柔和 */
    transition: none;
  }
}

/* ---------- 杂项 ---------- */
.portfolio-hero-aero .aero-shards { width: 100%; height: 100%; }
.portfolio-hero-aero[data-aero="off"] {
  background: radial-gradient(circle at 62% 48%, #0d2a24 0%, #07100f 64%);
}
.site-loader-value { font-variant-numeric: tabular-nums; }
.site-loader-value b { font-weight: 600; }
.site-loader-brand { font-family: var(--font-serif); letter-spacing: .1em; font-size: 16px; }
.music-popover[hidden] { display: none; }
.story-logo-module h2:empty { display: none; }
.simple-footer { font-family: var(--font-primary); letter-spacing: .08em; font-size: 9px; }
/* 页脚原来用 --dim（38% 透明度）在黑底上只有约 3.0:1，低于 4.5 的可读门槛 */
.simple-footer span { color: rgba(244, 240, 231, .60); }

/* 高亮块要留出字距的空间：原 padding 会让「坐坐」被裁掉约 4px */
.contact-heading-highlight { padding: .08em .12em .13em; }


/* ---------- 中文排印：字号与断行微调（实测后调整） ---------- */

/* 市场幕：中文句子要够长才能在卡片合拢时从两侧露出 */
.story-market-copy { font-size: clamp(22px, 2.5vw, 38px); letter-spacing: .03em; line-height: 1.5; }
.story-market-copy span:nth-child(3) { font-size: .68em; letter-spacing: .05em; margin-top: 10px; }

/* 愿景幕标题：9 个中文字在窄栏里会孤字成行 */
.story-vision-copy h2 { font-size: clamp(30px, 3.1vw, 46px); letter-spacing: .06em; line-height: 1.28; }
.story-vision-copy p { font-size: 15px; }

/* 社区幕标题 */
.story-community-copy h2 { font-size: clamp(34px, 4.4vw, 64px); }

/* 联系区：邮箱较长，缩一号并收紧间距 */
.email-link { gap: 6px; }
.email-link strong { font-size: clamp(16px, 1.65vw, 22px); }
.email-icon { flex-basis: 28px; width: 28px; height: 28px; }
.email-arrow { width: 22px; height: 22px; }
.contact-intro { font-size: clamp(14px, 1.2vw, 17px); }


/* 首屏标题与说明的断行 */
.portfolio-hero-heading h1 { font-size: clamp(34px, 3.5vw, 52px); }
.portfolio-hero-description span { max-width: 460px; font-size: 15px; }


/* ---------- 首屏恒为深色：品牌文字不能跟随主题变量 ----------
   复刻站里 .portfolio-hero 的背景是写死的 #000，浅色主题下
   var(--ink) 会变成深色，导致深底上出现深字。这里改用固定色值。 */
.portfolio-hero-greeting-text { color: #f4f0e7; }
.portfolio-hero-greeting-moon { color: #f6a26f; }
.portfolio-hero-description strong {
  background: linear-gradient(90deg, #f4f0e7, rgba(244, 240, 231, .42));
  -webkit-background-clip: text; background-clip: text;
}
.portfolio-hero-description span { color: rgba(244, 240, 231, .5); }
.portfolio-hero-heading h1 { color: #f4f0e7; }

/* 导航星标：深色区用亮橙，滚到浅色区自动转深橙 */
.brand-mark { color: #f6a26f; }
.site-header.is-on-light .brand-mark { color: #c2601f; }


/* ============================================================
   首屏卡面皮肤
   两套卡面（苍月 / 赤月）各自一套素材与配色：card-accent-rgb 驱动
   光环、流星、材质边与眩光的颜色；sheen-mask 决定高光镂空的形状。
   注意：--card-accent-rgb 必须在 :root 有默认值，否则
   rgb(var(--card-accent-rgb)) 会整条属性失效。
   ============================================================ */
:root { --card-accent-rgb: 22 119 255; }          /* 兜底：模板原色 */

.hero-card-stage[data-skin="neon"] {
  --card-accent-rgb: 79 227 255;                  /* 苍月 · 霓虹青 */
  --card-sheen-mask: url(../assets/flash-card/neon/sheen.webp);
}
.hero-card-stage[data-skin="crimson"] {
  --card-accent-rgb: 255 96 111;                  /* 赤月 · 暗红 */
  --card-sheen-mask: url(../assets/flash-card/crimson/sheen.webp);
}

/* 换卡面时淡入淡出，避免图层 src 切换的突兀 */
.hero-card-layer { transition: opacity .42s cubic-bezier(.22,1,.36,1); }
.hero-card-stage.is-switching .hero-layer-background,
.hero-card-stage.is-switching .hero-layer-subject,
.hero-card-stage.is-switching .hero-layer-surface { opacity: .35; }

/* ---------- 切换器 ---------- */
.hero-card-skins {
  position: absolute;
  left: 50%;
  bottom: 1.5%;
  transform: translateX(-50%);
  z-index: 24;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px;
  border-radius: 999px;
  background: rgba(7, 16, 15, .58);
  border: 1px solid var(--line);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
.hero-card-skin {
  appearance: none;
  border: 0;
  cursor: pointer;
  padding: 7px 15px;
  border-radius: 999px;
  background: transparent;
  color: rgba(244, 240, 231, .58);
  font-family: var(--font-primary);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .1em;
  line-height: 1;
  transition: color .26s, background .26s, transform .26s cubic-bezier(.16,1,.3,1);
}
.hero-card-skin:hover { color: var(--ink); transform: translateY(-1px); }
.hero-card-skin[aria-selected="true"] {
  background: rgb(var(--card-accent-rgb) / .18);
  color: var(--ink);
}
.hero-card-skin:focus-visible { outline: 2px solid rgb(var(--card-accent-rgb)); outline-offset: 2px; }
@media (max-width: 720px) {
  .hero-card-skins { bottom: 0; padding: 4px; gap: 4px; }
  .hero-card-skin { padding: 6px 11px; font-size: 11px; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-card-layer, .hero-card-skin { transition: none; }
}

/* ============================================================
   首屏文字动效：小忍者吉祥物 / 打印机解码 / 扫光
   ============================================================ */

/* ---------- 1. 小忍者吉祥物（替掉原来的两只眼睛） ---------- */
.portfolio-mascot {
  position: absolute; top: 17%; left: 4%;
  width: 118px; height: 104px;
}
/* 大屏下标题与说明都靠左对齐（模板的 min-width:1280 规则），吉祥物跟着对齐 */
@media (min-width: 1280px) { .portfolio-mascot { left: 0; } }
.mascot-body {
  position: relative; width: 100%; height: 100%;
  /* 浮动用 transform 动画，转头用独立的 rotate/translate 属性——
     两者是分开合成的，所以 JS 写朝向不会把 CSS 浮动覆盖掉 */
  rotate: var(--mascot-look, 0deg);
  translate: 0 var(--mascot-nod, 0px);
  animation: mascot-bob 5.2s ease-in-out infinite;
  will-change: transform, rotate, translate;
}
/* 空闲时轻轻上下浮动 + 微微左右摇 */
@keyframes mascot-bob {
  0%, 100% { transform: translateY(0) rotate(-1.4deg); }
  50%      { transform: translateY(-7px) rotate(1.4deg); }
}
.mascot-head {
  position: absolute; inset: 0;
  border-radius: 46px 46px 44px 44px / 40px 40px 48px 48px;
  background: radial-gradient(circle at 34% 26%, #ffffff 0%, #f4f0e7 42%, #d9d3c6 100%);
  box-shadow:
    inset 0 -7px 14px rgba(120, 112, 96, .22),
    inset 0 3px 6px rgba(255, 255, 255, .9),
    0 12px 26px rgba(0, 0, 0, .38);
}
/* 护额绑带 */
.mascot-band {
  position: absolute; left: -3px; right: -3px; top: 26px; height: 19px;
  border-radius: 5px;
  background: linear-gradient(180deg, #2f5a4d, #1b3a32);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .16), 0 3px 8px rgba(0, 0, 0, .3);
}
.mascot-plate {
  position: absolute; left: 50%; top: 2px; transform: translateX(-50%);
  width: 40px; height: 15px; border-radius: 4px;
  background: linear-gradient(165deg, #e8e9e4 0%, #a9aea7 46%, #d6d8d2 62%, #8d938c 100%);
  box-shadow: inset 0 0 0 1px rgba(60, 64, 60, .5);
  display: grid; place-items: center;
}
/* 金属牌上那道刻痕 */
.mascot-plate > i {
  display: block; width: 13px; height: 8px;
  border-bottom: 1.6px solid rgba(58, 62, 58, .68);
  border-radius: 0 0 40% 40%;
  transform: translateY(-1.5px) rotate(-8deg);
}
/* 绑带垂下来的那截尾巴 */
.mascot-knot {
  position: absolute; right: -13px; top: 3px; width: 20px; height: 7px;
  border-radius: 3px;
  background: linear-gradient(180deg, #2f5a4d, #1b3a32);
  transform-origin: 0 50%;
  animation: mascot-knot 3.4s ease-in-out infinite;
}
.mascot-knot::after {
  content: ""; position: absolute; left: 16px; top: 3px; width: 17px; height: 6px;
  border-radius: 3px;
  background: linear-gradient(180deg, #2a5146, #17332c);
  transform-origin: 0 50%; transform: rotate(9deg);
}
@keyframes mascot-knot {
  0%, 100% { transform: rotate(2deg); }
  50%      { transform: rotate(-7deg); }
}
/* 耳朵 */
.mascot-ear {
  position: absolute; top: -11px; width: 27px; height: 29px;
  background: linear-gradient(160deg, #ffffff, #e2dccd);
  border-radius: 50% 50% 44% 44%;
  box-shadow: inset 0 -4px 8px rgba(120, 112, 96, .2);
}
.mascot-ear-left { left: 20px; transform: rotate(-15deg); }
.mascot-ear-right { right: 20px; transform: rotate(15deg); }
/* 眼睛 */
.mascot-eye {
  position: absolute; top: 54px; width: 27px; height: 29px;
  background: #fff; border-radius: 50%;
  box-shadow: inset 0 -3px 6px rgba(90, 90, 100, .22);
  overflow: hidden;
  animation: mascot-blink 4.8s ease-in-out infinite;
}
.mascot-eye:nth-of-type(1) { left: 21px; }
.mascot-eye:nth-of-type(2) { left: 68px; }
@keyframes mascot-blink {
  0%, 90%, 100% { transform: scaleY(1); }
  94%, 96%      { transform: scaleY(.06); }
}
.mascot-pupil {
  position: absolute; top: 50%; left: 50%;
  width: 13px; height: 13px; margin: -6.5px 0 0 -6.5px;
  background: radial-gradient(circle at 34% 30%, #3b4250, #0a0b10 68%);
  border-radius: 50%;
  transition: transform .16s cubic-bezier(.2, .8, .2, 1);
  will-change: transform;
}
.mascot-pupil::after {
  content: ""; position: absolute; top: 2px; right: 2px;
  width: 4px; height: 4px; border-radius: 50%; background: #fff; opacity: .95;
}
/* 腮红 + 嘴 */
.mascot-blush {
  position: absolute; top: 80px; width: 16px; height: 8px; border-radius: 50%;
  background: radial-gradient(circle, rgba(246, 162, 111, .72), rgba(246, 162, 111, 0) 72%);
}
.mascot-blush-left { left: 12px; }
.mascot-blush-right { right: 12px; }
.mascot-mouth {
  position: absolute; left: 50%; top: 81px; transform: translateX(-50%);
  width: 16px; height: 8px;
  border-bottom: 2px solid rgba(20, 24, 30, .8);
  border-radius: 0 0 46% 46%;
}
@media (max-width: 1000px) {
  .portfolio-mascot { width: 100px; height: 88px; }
  .mascot-band { top: 22px; height: 17px; }
  .mascot-eye { top: 46px; }
  .mascot-blush { top: 68px; }
  .mascot-mouth { top: 69px; }
}
@media (max-width: 720px) {
  .portfolio-mascot { top: 34px; left: 2px; width: 84px; height: 74px; }
  .mascot-band { top: 19px; height: 15px; }
  .mascot-plate { width: 31px; height: 12px; }
  .mascot-ear { top: -8px; width: 20px; height: 22px; }
  .mascot-ear-left { left: 14px; }
  .mascot-ear-right { right: 14px; }
  .mascot-eye { top: 38px; width: 20px; height: 21px; }
  .mascot-eye:nth-of-type(1) { left: 15px; }
  .mascot-eye:nth-of-type(2) { left: 49px; }
  .mascot-pupil { width: 10px; height: 10px; margin: -5px 0 0 -5px; }
  .mascot-blush { top: 57px; width: 12px; height: 6px; }
  .mascot-mouth { top: 58px; width: 12px; height: 6px; }
}

/* ---------- 2. 问候语：打印机解码 ---------- */
.portfolio-hero-greeting-text {
  /* 等宽打底——解码时滚动的乱码因此像机器在打字；
     定下来的中文回落到衬线，比无衬线更耐看 */
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Consolas,
               "Noto Serif SC", "Songti SC", "SimSun", serif;
  font-size: clamp(19px, 1.7vw, 25px);
  font-weight: 500;
  letter-spacing: .14em;
  line-height: 1.3;
  min-height: 1.3em;
  white-space: pre;
  background: linear-gradient(180deg, #ffffff 8%, #efe9dc 52%, #c9c0ad 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
/* 解码中：偏冷的字色，像还没渲染完 */
.portfolio-hero-greeting.is-decoding .portfolio-hero-greeting-text {
  background: none;
  -webkit-text-fill-color: #7f8f88;
  color: #7f8f88;
}
/* 打印机光标 */
.portfolio-hero-greeting-caret {
  display: inline-block;
  width: .52em; height: 1.02em;
  margin-left: 5px;
  vertical-align: -.14em;
  background: #8de6b2;
  box-shadow: 0 0 10px rgba(141, 230, 178, .8);
  animation: caret-blink 1.05s steps(1, end) infinite;
}
@keyframes caret-blink { 0%, 48% { opacity: 1; } 49%, 100% { opacity: .12; } }
/* 原来的 ✱ 让位给光标 */
.portfolio-hero-greeting-moon { display: none; }

/* ---------- 3. 扫光：标题与说明 ---------- */
/* 标题：常驻的竖向金属渐变打底，上面再铺一条斜向高光带周期扫过 */
.portfolio-hero-title-text {
  background-image:
    linear-gradient(102deg, transparent 40%, rgba(255, 255, 255, .96) 50%, rgba(180, 235, 255, .5) 54%, transparent 64%),
    linear-gradient(180deg, rgba(244, 240, 231, .40), #f4f0e7 78%);
  background-size: 240% 100%, 100% 100%;
  background-position: -130% 0, 0 0;
  background-repeat: no-repeat, no-repeat;
  -webkit-background-clip: text; background-clip: text;
  animation: hero-sweep 6.4s cubic-bezier(.55, 0, .35, 1) infinite;
}
@keyframes hero-sweep {
  0%, 46%   { background-position: -130% 0, 0 0; }
  78%, 100% { background-position: 235% 0, 0 0; }
}
/* 说明文字：同一条光带，延后一拍横扫，形成层次 */
.portfolio-hero-description span {
  background-image: linear-gradient(102deg, transparent 40%, rgba(255, 255, 255, .62) 50%, rgba(141, 230, 178, .34) 55%, transparent 65%);
  background-size: 240% 100%;
  background-position: -130% 0;
  background-repeat: no-repeat;
  -webkit-background-clip: text; background-clip: text;
  animation: hero-sweep-soft 6.4s cubic-bezier(.55, 0, .35, 1) infinite;
  animation-delay: .55s;
}
@keyframes hero-sweep-soft {
  0%, 46%   { background-position: -130% 0; }
  78%, 100% { background-position: 235% 0; }
}
/* 角色标签：走一条更慢的暖色高光，不跟着循环扫，避免整块都在闪 */
.portfolio-hero-description strong {
  background-image: linear-gradient(112deg, #ffffff 0%, #efe9dc 34%, #f6a26f 62%, #ffffff 100%);
  background-size: 220% 100%;
  background-position: 0 0;
  -webkit-background-clip: text; background-clip: text;
  animation: role-shine 7.2s ease-in-out infinite;
}
@keyframes role-shine {
  0%, 60%   { background-position: 0 0; }
  100%      { background-position: -120% 0; }
}
/* 标题下那道渐变横条：一道亮斑来回游走 */
.portfolio-hero-rule { overflow: hidden; }
.portfolio-hero-rule::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, .95) 50%, transparent 100%);
  mix-blend-mode: screen;
  animation: rule-glint 4.2s cubic-bezier(.5, 0, .5, 1) infinite;
}
@keyframes rule-glint {
  0%, 18%   { transform: translateX(-120%); }
  72%, 100% { transform: translateX(120%); }
}

/* ---------- 减少动效：全部静态化 ---------- */
@media (prefers-reduced-motion: reduce) {
  .mascot-body, .mascot-knot, .mascot-eye, .portfolio-hero-greeting-caret,
  .portfolio-hero-title-text, .portfolio-hero-description span,
  .portfolio-hero-description strong, .portfolio-hero-rule::after { animation: none; }
  .mascot-eye { transform: none; }
  .portfolio-hero-greeting-caret { opacity: 1; }
  .portfolio-hero-rule::after { transform: translateX(0); opacity: .5; }
}

/* ============================================================
   进场加载层：潮水退去
   加载时是一屏深海，落日辉光随进度从底部透上来；结束时整块
   带着波浪边缘向上退去，把首屏露出来。
   ============================================================ */
.site-loader {
  color: #f4f0e7;
  background: #07100f;
  --boot: 0;
  /* 覆盖模板的淡出：这里改成整块上移离场 */
  transition:
    transform .95s cubic-bezier(.76, 0, .24, 1) .1s,
    visibility 0s linear 1.2s;
}
.site-loader[data-phase="ready"] {
  transform: translateY(-102%);
  visibility: hidden;
  pointer-events: none;
  opacity: 1;                     /* 不走透明度，靠位移离场 */
}

/* 底部落日辉光：随进度从底部升起来 */
.site-loader-dusk {
  position: absolute; left: 50%; bottom: -14%;
  width: 120vw; aspect-ratio: 2.1 / 1;
  transform: translateX(-50%) scaleY(calc(.35 + var(--boot) * .65));
  transform-origin: 50% 100%;
  background: radial-gradient(ellipse at 50% 100%,
    rgba(246, 162, 111, .40) 0%,
    rgba(194, 96, 31, .20) 26%,
    rgba(141, 230, 178, .05) 52%,
    rgba(7, 16, 15, 0) 74%);
  opacity: calc(.35 + var(--boot) * .65);
  transition: opacity .5s linear, transform .5s linear;
  pointer-events: none;
}

/* 星点：用重复径向渐变铺一层，比放 60 个 span 便宜 */
.site-loader-stars {
  position: absolute; inset: 0;
  background-image:
    radial-gradient(1.4px 1.4px at 12% 22%, rgba(244,240,231,.55), transparent),
    radial-gradient(1.2px 1.2px at 78% 14%, rgba(244,240,231,.42), transparent),
    radial-gradient(1px 1px at 34% 46%, rgba(141,230,178,.5), transparent),
    radial-gradient(1.6px 1.6px at 62% 33%, rgba(244,240,231,.36), transparent),
    radial-gradient(1px 1px at 88% 58%, rgba(244,240,231,.3), transparent),
    radial-gradient(1.2px 1.2px at 22% 68%, rgba(244,240,231,.26), transparent),
    radial-gradient(1px 1px at 52% 76%, rgba(141,230,178,.3), transparent);
  opacity: .8;
  animation: boot-twinkle 6s ease-in-out infinite;
  pointer-events: none;
}
@keyframes boot-twinkle { 0%, 100% { opacity: .55; } 50% { opacity: .95; } }

/* ---------- 中央内容 ---------- */
.site-loader-inner { transform: translateY(0); }
.site-loader[data-phase="ready"] .site-loader-inner {
  opacity: 0;
  transform: translateY(-16px);
  transition: opacity .3s cubic-bezier(.4, 0, 1, 1), transform .34s cubic-bezier(.4, 0, 1, 1);
}

.site-loader-brand {
  display: flex; align-items: baseline; gap: 9px;
  font-family: var(--font-serif);
  font-size: clamp(22px, 2.1vw, 30px);
  font-weight: 600; letter-spacing: .16em; line-height: 1;
  margin-bottom: 34px;
  color: #f4f0e7;
  /* 入场：轻微上浮 + 字距收紧 */
  animation: boot-brand-in .9s cubic-bezier(.16,1,.3,1) both .15s;
}
.site-loader-brand i {
  font-style: normal; font-size: .58em; color: #f6a26f;
  transform: translateY(-.12em);
}
.site-loader-brand em {
  font-family: var(--font-mono);
  font-style: normal; font-size: .42em; font-weight: 500;
  letter-spacing: .28em; color: rgba(244, 240, 231, .42);
}
@keyframes boot-brand-in {
  from { opacity: 0; transform: translateY(14px); letter-spacing: .3em; }
  to   { opacity: 1; transform: translateY(0); }
}

/* 状态行 + 等宽百分比 */
.site-loader-meta {
  color: rgba(244, 240, 231, .52);
  font: 500 11px/1.2 var(--font-primary);
  letter-spacing: .12em;
  margin-bottom: 11px;
  animation: boot-fade-in .7s cubic-bezier(.16,1,.3,1) both .5s;
}
.site-loader-value { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: .04em; }
.site-loader-value b { font-weight: 500; color: rgba(244, 240, 231, .82); }
@keyframes boot-fade-in { from { opacity: 0; } to { opacity: 1; } }

/* ---------- 进度：十个小鸣人头，随进度依次点亮 ----------
   没有进度条了，进度本身就是这排头：亮的多少 = 加载到几成。
   --boot（0→1，由 initLoader() 写）同时喂给每个头算 --lit：
     头 i 点亮的时机 = i / (count + 1)
   分母刻意比头数多 1，最后一个头在 --boot ≈ .82 就全亮，
   这样「等素材」停在 92% 那段不会留一个半亮不亮的头。 */
.site-loader-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.site-loader-inner { width: min(430px, 100vw - 40px); }   /* 放得下 10 个头 */

.site-loader-track {
  --count: 10;          /* 头数，与 .site-loader-head 的行数保持一致 */
  --head: 34px;         /* 单头尺寸 */
  --gap: 8px;
  display: flex;
  align-items: flex-end;   /* 配合下面的 transform-origin，点亮时是往上「长」 */
  gap: var(--gap);
  background: none;        /* 去掉模板留下的底条 */
  height: auto;
  overflow: visible;
  animation: boot-fade-in .7s cubic-bezier(.16,1,.3,1) both .5s;
}

.site-loader-head {
  /* 乘 2.2 让每个头的出现窗口只占它自己时间槽的 45%：
     头是「啪」一下蹦出来的，而不是跟着进度被慢慢擦亮。 */
  --lit: clamp(0, calc((var(--boot, 0) * (var(--count) + 1) - var(--i)) * 2.2), 1);
  position: relative;
  display: block;
  width: var(--head);
  height: var(--head);
  transform-origin: 50% 100%;
  /* 没轮到的头完全不出场——整排是「一个一个出现」，不是给灰剪影上色。
     不加 filter：十个元素同时动 filter 是白花的合成开销。 */
  opacity: var(--lit);
  transform: scale(calc(.45 + var(--lit) * .55));
}
.site-loader-head > svg { display: block; width: 100%; height: 100%; }

/* 点亮时透出一圈落日色的暖光 */
.site-loader-head::after {
  content: '';
  position: absolute; inset: -20%;
  z-index: -1;                       /* 垫在头的后面 */
  border-radius: 50%;
  background: radial-gradient(circle, rgba(246, 162, 111, .42) 0%, rgba(246, 162, 111, 0) 64%);
  opacity: var(--lit);
}

/* 头像配色：鸣人的招牌三件套——金发、护额、腮须 */
.nar-hair  { fill: #f5c33b; }
.nar-face  { fill: #fbd9b4; }
.nar-band  { fill: #2b4a86; }
.nar-plate { fill: #ccd8e6; }
.nar-leaf  { fill: none; stroke: #35465e; stroke-width: 1.7; stroke-linecap: round; }
.nar-eye   { fill: #1f3f75; }
.nar-spark { fill: #ffffff; }
.nar-whisker path { fill: none; stroke: #cb8b5b; stroke-width: 2; stroke-linecap: round; }
.nar-mouth { fill: none; stroke: #b06a44; stroke-width: 1.8; stroke-linecap: round; }

/* ---------- 波浪边缘 ---------- */
.site-loader-wake {
  position: absolute; left: 0; right: 0; top: 100%;
  height: 56px; overflow: hidden; pointer-events: none;
}
.site-loader-wake svg {
  position: absolute; top: 0; left: 0;
  width: 200%; height: 100%;
  animation: boot-wake-drift 9s linear infinite;
}
.site-loader-wake path { fill: #07100f; }
@keyframes boot-wake-drift { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ---------- 减少动效：不做位移与波浪，直接消失 ---------- */
@media (prefers-reduced-motion: reduce) {
  .site-loader { transition: opacity .2s, visibility 0s linear .2s; }
  .site-loader[data-phase="ready"] { transform: none; opacity: 0; }
  .site-loader-brand, .site-loader-meta, .site-loader-track, .site-loader-stars { animation: none; }
  .site-loader-wake { display: none; }
  .site-loader-inner { transform: none; }
  /* 头像点亮可以留（那是进度指示本身），但「点亮时放大」是装饰，去掉 */
  .site-loader-head { transform: none; }
  .site-loader-head::after { display: none; }
}

@media (max-width: 720px) {
  .site-loader-brand { font-size: 20px; letter-spacing: .1em; }
  .site-loader-brand em { font-size: .46em; letter-spacing: .2em; }
  .site-loader-track { --head: 26px; --gap: 6px; }
}

/* 更窄的屏（320px 一类）十个头会被挤到 21px，几乎看不出是什么。
   只留前 8 个，尺寸就保得住。--count 必须跟着改成 8，
   否则第 9、10 个头的权重没人用，最后两个会一直不亮。 */
@media (max-width: 480px) {
  .site-loader-track { --count: 8; --head: 28px; --gap: 6px; }
  .site-loader-head:nth-child(n + 9) { display: none; }
}

/* ---------- 加载层退去后，首屏轻微落定 ----------
   延迟要跟滑走的进度对齐：加载层大约在 .45s 才让出画面中段，
   起跑太早的话动画会在幕布后面演完，白做。 */
html.boot-done .portfolio-hero-copy {
  animation: hero-rise 1s cubic-bezier(.16, 1, .3, 1) both .42s;
}
html.boot-done .hero-card-wrap {
  animation: hero-rise 1.15s cubic-bezier(.16, 1, .3, 1) both .54s;
}
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  html.boot-done .portfolio-hero-copy,
  html.boot-done .hero-card-wrap { animation: none; }
}

/* ============================================================
   作品轮播的「显影」说明层
   原先 6 件作品只有画面，名字只存在于 alt 里。现在标题与一句话
   说明是可见文字，切到该作品时从模糊里收清、一道暖光扫过——
   沿用首屏那套光语言，不另起一套。
   ============================================================ */
.featured-reel-caption {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(14px, 1.6vw, 22px);
  row-gap: 6px;
  align-items: start;
  padding: clamp(18px, 2.2vw, 30px) clamp(20px, 2.6vw, 36px) clamp(20px, 2.4vw, 32px);
  background: linear-gradient(to top,
    rgba(4, 11, 10, .92) 0%, rgba(4, 11, 10, .66) 40%,
    rgba(4, 11, 10, .28) 70%, rgba(4, 11, 10, 0) 100%);
}
.featured-reel-index {
  grid-row: 1 / span 3;
  font: 500 clamp(22px, 2.6vw, 34px)/1 var(--font-mono);
  color: rgba(244, 240, 231, .34);
  font-variant-numeric: tabular-nums;
}
.featured-reel-title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(19px, 2.3vw, 30px);
  font-weight: 600; letter-spacing: .02em; line-height: 1.15;
  color: #f4f0e7;
}
.featured-reel-title-link { display: inline-flex; align-items: baseline; gap: 8px; color: inherit; }
.featured-reel-title-link i {
  font-style: normal; font-size: .56em; color: #f6a26f;
  transform: translateY(-.1em);
  transition: transform .3s cubic-bezier(.16, 1, .3, 1);
}
.featured-reel-title-link:hover i,
.featured-reel-title-link:focus-visible i { transform: translate(.16em, -.28em); }
.featured-reel-title-link:focus-visible { outline: 2px solid #8de6b2; outline-offset: 4px; border-radius: 3px; }
.featured-reel-desc {
  margin: 0; max-width: 46ch;
  font-size: clamp(12px, 1.1vw, 14px); line-height: 1.55;
  color: rgba(244, 240, 231, .72);
}
.featured-reel-tags { display: flex; flex-wrap: wrap; gap: 7px; margin: 0; padding: 0; list-style: none; }
.featured-reel-tags li {
  padding: 4px 10px; border-radius: 999px;
  font-size: 11px; letter-spacing: .06em;
  color: rgba(244, 240, 231, .68);
  background: rgba(244, 240, 231, .05);
  border: 1px solid rgba(244, 240, 231, .16);
}

/* 显影：用 animation 而不是 transition——动画在元素「带类出生」时也会播，
   而第一张作品从创建起就带 is-active，用 transition 会直接跳到终态。 */
.featured-reel-caption > * { opacity: 0; filter: blur(9px); transform: translateY(12px); }
.featured-reel-panel.is-active .featured-reel-caption > * {
  animation: reel-develop .78s cubic-bezier(.2, .7, .2, 1) both;
}
.featured-reel-panel.is-active .featured-reel-index { animation-delay: .08s; }
.featured-reel-panel.is-active .featured-reel-title { animation-delay: .16s; }
.featured-reel-panel.is-active .featured-reel-desc { animation-delay: .24s; }
.featured-reel-panel.is-active .featured-reel-tags { animation-delay: .32s; }
@keyframes reel-develop {
  from { opacity: 0; filter: blur(9px); transform: translateY(12px); }
  to   { opacity: 1; filter: blur(0); transform: translateY(0); }
}

/* 一次暖光扫过，和首屏标题是同一种光 */
.featured-reel-caption:after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(102deg, transparent 40%, rgba(246, 162, 111, .34) 50%, rgba(255, 255, 255, .20) 55%, transparent 66%);
  background-size: 280% 100%; background-position: -160% 0;
  opacity: 0;
}
.featured-reel-panel.is-active .featured-reel-caption:after {
  animation: reel-develop-sweep 1.15s cubic-bezier(.32, .72, .28, 1) .18s both;
}
@keyframes reel-develop-sweep {
  0%   { background-position: -160% 0; opacity: 0; }
  25%  { opacity: 1; }
  100% { background-position: 260% 0; opacity: 0; }
}

@media (max-width: 720px) {
  .featured-reel-caption { row-gap: 5px; }
  .featured-reel-desc { font-size: 12px; }
}
@media (max-width: 560px) {
  /* 窄屏放下序号会挤掉标题，直接把序号去掉 */
  .featured-reel-caption { grid-template-columns: minmax(0, 1fr); }
  .featured-reel-index { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .featured-reel-caption > * { opacity: 1; filter: none; transform: none; }
  .featured-reel-panel.is-active .featured-reel-caption > * { animation: none; }
  .featured-reel-caption:after { display: none; }
}

/* ============================================================
   彩蛋：影分身
   连点吉祥物三下，四个分身扇形散开再淡走。
   分身的定位与尺寸直接沿用 .portfolio-mascot（它是 absolute，
   父容器 .portfolio-hero-copy 是定位上下文），所以不用算坐标。
   ============================================================ */
.mascot-clone {
  pointer-events: none;
  will-change: transform, opacity;
  animation: mascot-clone-out 1.15s cubic-bezier(.2, .7, .2, 1) var(--clone-delay, 0ms) both;
}
@keyframes mascot-clone-out {
  0%   { opacity: 0;   transform: translate(0, 0) rotate(0deg) scale(.86); }
  22%  { opacity: .95; transform: translate(calc(var(--clone-x) * .45), calc(var(--clone-y) * .5)) rotate(calc(var(--clone-rot) * .4)) scale(1.02); }
  62%  { opacity: .92; transform: translate(var(--clone-x), var(--clone-y)) rotate(var(--clone-rot)) scale(1); }
  100% { opacity: 0;   transform: translate(calc(var(--clone-x) * 1.25), calc(var(--clone-y) * 1.5)) rotate(var(--clone-rot)) scale(.94); }
}
/* 每个分身带一团烟 */
.mascot-puff {
  position: absolute; left: 50%; top: 56%;
  width: 30px; height: 30px; margin: -15px 0 0 -15px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(244, 240, 231, .5) 0%, rgba(244, 240, 231, 0) 70%);
  animation: mascot-puff-out .9s ease-out var(--clone-delay, 0ms) both;
}
@keyframes mascot-puff-out {
  0%   { opacity: 0;   transform: scale(.4); }
  35%  { opacity: .85; transform: scale(1.25); }
  100% { opacity: 0;   transform: scale(2.1); }
}
/* 那句台词 */
.mascot-clone-label {
  position: absolute; left: 100%; top: 30%;
  margin-left: 10px;
  font-family: var(--font-serif);
  font-size: 13px; letter-spacing: .22em; white-space: nowrap;
  color: #f6a26f;
  text-shadow: 0 0 12px rgba(246, 162, 111, .6);
  pointer-events: none;
  animation: mascot-label 1.5s cubic-bezier(.2, .7, .2, 1) .08s both;
}
@keyframes mascot-label {
  0%   { opacity: 0; transform: translateY(6px); }
  20%  { opacity: 1; transform: translateY(0); }
  72%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-9px); }
}

/* ============================================================
   音乐面板：真频谱
   原来那几根条是纯 CSS 假动效，跟音频无关。接了 Web Audio 之后
   .is-live 一挂上就把 CSS 动画让位给 --bar-h（由 JS 按频段实时写）。
   同理，条数也从 4 根加到 8 根。
   ============================================================ */
.music-track-status { flex-basis: 64px; width: 64px; gap: 2px; padding-right: 6px; }
.music-track-status i { width: 3px; height: 5px; }
.music-track-status.is-live i {
  animation: none;
  height: var(--bar-h, 5px);
  transition: height .07s linear;
}
/* 拿不到 AudioContext 时不会挂 is-live，CSS 假波形继续跑，功能不受影响 */
@media (prefers-reduced-motion: reduce) {
  .music-track-status.is-live i { transition: none; }
}

/* ============================================================
   海况胶囊
   站点跟着访客的真实时间走，这枚小胶囊告诉你「现在是什么海」。
   点一下钉住一个时辰（白天来访也能看到招牌橘子海），再点回到自动。
   ============================================================ */
.sky-chip {
  display: inline-flex; align-items: center; gap: 9px;
  margin-top: 20px;
  padding: 7px 14px 7px 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--soft-surface);
  color: var(--muted);
  font-size: 11px; letter-spacing: .1em;
  cursor: pointer;
  transition: color .24s, border-color .24s, background .24s, transform .28s cubic-bezier(.22,1,.36,1);
}
.sky-chip:hover, .sky-chip:focus-visible {
  color: var(--ink); border-color: var(--warm);
  background: var(--soft-surface-hover); transform: translateY(-2px);
}
.sky-chip-dot {
  flex: none;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--sky-chip-dot, #f6a26f);
  box-shadow: 0 0 10px 1px var(--sky-chip-dot, #f6a26f);
  transition: background .6s, box-shadow .6s;
}
/* 钉住时给个明确的「这不是自动」的暗示 */
.sky-chip.is-pinned { border-color: var(--warm); color: var(--ink); }
.sky-chip.is-pinned .sky-chip-dot { box-shadow: 0 0 0 3px var(--sky-chip-dot, #f6a26f); }
