/* KeyMoment 首页专用：固定舞台、首屏与态势曲线。站点外壳见 site.css */

:root {
  --apple-display-font: "SF Pro Display", "SF Pro Text", "PingFang SC", "Helvetica Neue", Arial, sans-serif;
  --apple-title-white: #f5f5f7;
  --apple-title-muted: #86868b;
  --apple-headline-gradient: linear-gradient(90deg, #e4f6f0 0%, #9dcfca 31%, #6b95ac 68%, #45657d 100%);
  --hero-curve-entry-delay: 360ms;
  --hero-curve-entry-duration: 3400ms;
  --hero-curve-entry-ease: cubic-bezier(.65, 0, .35, 1);
  --hero-photo-drift-delay: calc(var(--hero-curve-entry-delay) + var(--hero-curve-entry-duration));
}

body { font-family: var(--apple-display-font); }

/* 舞台与两段画面的显隐全部由滚动进度写入的自定义属性驱动，过渡跟手而不是到阈值再定时淡入 */
.stage {
  position: sticky; top: 0; z-index: 0; width: 100%; height: 100svh;
  overflow: hidden; background: #000;
  pointer-events: none; opacity: var(--stage-reveal, 0);
  transition: opacity 120ms linear;
}
.video-macbook, .three-shell, #rendered-3d-video, #keyshot-link, .cinema-shade {
  position: absolute; inset: 0; width: 100%; height: 100%;
}
.video-macbook {
  z-index: 1; left: 68%; right: auto; top: 27svh; bottom: auto;
  /* 比例即模板图幅：机身照 product-shots/web/macbook-frame.webp 画，不再用 CSS 拼 */
  width: min(60vw, 920px, 104svh); height: auto; aspect-ratio: 4260 / 2840;
  opacity: 1;
  transform: translate(-50%, var(--video-laptop-rise, 24px)) scale(var(--video-product-scale, .9));
  transform-origin: 50% 0;
}
.video-scan-curtain {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: #050506;
  transform: translateY(var(--video-scan-shift-y, 0));
  will-change: transform, opacity;
}
.video-scanline {
  position: absolute; left: 0; right: 0; top: 0;
  height: 3px;
  background: linear-gradient(90deg, transparent, rgba(124,226,255,.68) 18%, #f5f5f7 50%, rgba(124,226,255,.68) 82%, transparent);
  box-shadow: 0 0 14px rgba(110,220,255,.28);
  opacity: var(--video-scan-opacity, 0);
  transform: scaleX(var(--video-scan-scale-x, 0));
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}
/* 这一层现在正好等于模板的屏幕开口：机身边框、刘海、摄像头、底座都在模板图里。
   keymoment_app.js 用这一层的 getBoundingClientRect() 算「传送门」的起始画框，
   所以它必须与开口逐像素重合——开口的百分比是从原图量出来的，见 product.css 顶部。 */
.video-macbook-display {
  position: absolute; overflow: hidden;
  left: 9.4366%; top: 10.6690%; width: 81.1268%; height: 78.6620%;
  background: #050506;
  /* 圆角要圆不要椭圆：百分比横向按盒宽、纵向按盒高解析，两个方向分开写（都等于开口的 37px） */
  border-radius: 1.071% / 1.656%;
  clip-path: inset(var(--video-screen-clip-y, 50%) var(--video-screen-clip-x, 50%) var(--video-screen-clip-y, 50%) var(--video-screen-clip-x, 50%) round 1.071% / 1.656%);
  opacity: calc(var(--video-screen-reveal, 0) * (1 - var(--reality-fade, 0)));
  transform:
    translate(var(--portal-shift-x, 0), var(--portal-shift-y, 0))
    scale(var(--portal-scale, 1));
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}
/* 模板分两层贴，为的是保住原来的两拍节奏：先屏幕、后补齐机身前沿。
   上盖（含刘海、摄像头、边框与下巴）跟着 --video-screen-reveal 出现，并与屏幕同走传送门变换；
   底座（第 93.7% 行以下那块楔形）跟着 --video-base-reveal 上移补齐。
   开口在模板里正好居中（横 9.4366+81.1268/2 = 50%，纵 10.669+78.662/2 = 50%），
   所以两层与屏幕层共用 transform-origin: 50% 50%，变换时锚在同一点上。 */
.video-macbook::before,
.video-macbook::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: url("/product-shots/web/macbook-frame.webp?v=1") center / 100% 100% no-repeat;
  transform-origin: 50% 50%;
}
.video-macbook::before {
  z-index: 2;
  clip-path: inset(0 0 6.3% 0);
  opacity: calc(var(--video-screen-reveal, 0) * (1 - var(--device-recede, 0)));
  transform:
    translate(var(--portal-shift-x, 0), var(--portal-shift-y, 0))
    scale(var(--portal-scale, 1));
  will-change: transform, opacity;
}
.video-macbook::after {
  z-index: 4;
  clip-path: inset(93.7% 0 0 0);
  opacity: calc(var(--video-base-reveal, 0) * (1 - var(--device-recede, 0)));
  transform: translateY(calc(var(--video-base-offset, 12px) + var(--device-recede, 0) * 28px));
}
/* 摄像头、底座、开合凹口与底脚都画在模板里了 */
.video-macbook-camera, .video-macbook-base { display: none; }
/* 比赛画面保持原始亮度与颜色，不加任何静态滤镜；文字可读性由底部幕布单独负责。
   只有过渡时随 --reality-crush 整体压暗，现实画面退成暗底，三维证据从暗底里浮现。 */
#match-video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 1; object-fit: cover;
  transform: scale(calc(1 + .05 * var(--evidence-mix, 0)));
  filter: brightness(calc(1 - .78 * var(--reality-crush, 0)));
  transition: filter 120ms linear, transform 120ms linear;
}
.video-macbook-camera {
  position: absolute; left: 50%; top: clamp(3px, .42vw, 6px); z-index: 3;
  width: clamp(4px, .42vw, 6px); height: clamp(4px, .42vw, 6px);
  border-radius: 50%; background: #09090a;
  box-shadow: inset 0 0 0 1px rgba(78,100,116,.42), 0 0 4px rgba(46,80,104,.35);
  opacity: calc(var(--video-screen-reveal, 0) * (1 - var(--device-recede, 0)));
  transform: translateX(-50%);
}
.video-macbook-base {
  position: absolute; left: -4%; right: -4%; top: 71.8%; z-index: 4; height: 4.8%;
  border-radius: 2px 2px clamp(8px, .8vw, 12px) clamp(8px, .8vw, 12px);
  background:
    linear-gradient(90deg, rgba(255,255,255,.04), transparent 7% 93%, rgba(255,255,255,.04)),
    linear-gradient(180deg, #4b4c51 0%, #25262a 30%, #0d0e10 72%, #232428 100%);
  box-shadow:
    0 9px 14px rgba(0,0,0,.68),
    inset 0 1px rgba(255,255,255,.2),
    inset 0 -1px rgba(255,255,255,.08);
  opacity: calc(var(--video-base-reveal, 0) * (1 - var(--device-recede, 0)));
  transform: translateY(calc(var(--video-base-offset, 12px) + var(--device-recede, 0) * 28px));
}
.video-macbook-notch {
  position: absolute; left: 50%; top: 0; width: 18%; height: 46%;
  border-radius: 0 0 999px 999px;
  background: linear-gradient(180deg, #17181b, #46474c 55%, #2a2b2f);
  box-shadow: inset 0 -1px rgba(255,255,255,.13), 0 1px 3px rgba(0,0,0,.7);
  transform: translateX(-50%);
}
.video-macbook-feet::before,
.video-macbook-feet::after {
  content: ""; position: absolute; bottom: -8%; width: 10%; height: 10%;
  border-radius: 0 0 999px 999px; background: #08090a;
  box-shadow: 0 2px 4px rgba(0,0,0,.8);
}
.video-macbook-feet::before { left: 6%; }
.video-macbook-feet::after { right: 6%; }
.three-shell {
  z-index: 3; opacity: var(--evidence-mix, 0);
  transform:
    perspective(1200px)
    translate(var(--court-stage-shift-x, 0), var(--court-stage-shift-y, 0))
    translateY(calc((1 - var(--court-depth, 0)) * 7vh))
    rotateX(calc((1 - var(--court-depth, 0)) * 7deg))
    scale(var(--court-stage-scale, 1.08));
  transform-origin: 50% 62%;
  -webkit-mask-image:
    linear-gradient(90deg, transparent 0%, rgba(0,0,0,.35) 4%, #000 13%),
    radial-gradient(ellipse at 58% 50%, #000 0 72%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(90deg, transparent 0%, rgba(0,0,0,.35) 4%, #000 13%),
    radial-gradient(ellipse at 58% 50%, #000 0 72%, transparent 100%);
  mask-composite: intersect;
  transition: opacity 120ms linear;
  will-change: transform, opacity;
}
#rendered-3d-video {
  display: block; object-fit: contain; background: #041019;
  filter: brightness(calc(1 - .28 * var(--analysis-layout, 0)));
}

.curve-shell {
  position: absolute; left: 6vw; right: auto; bottom: 12vh; top: auto; z-index: 9;
  width: 50vw; height: 34vh; margin: 0; padding: 0;
  opacity: var(--curve-stage-reveal, 0);
  transform: translateX(calc((1 - var(--curve-stage-reveal, 0)) * -42px));
  background: transparent;
  will-change: transform, opacity;
}
.analysis-grid {
  position: absolute; inset: 0; z-index: 2;
  --grid-minor: 36px; --grid-major: 180px;
  opacity: var(--analysis-grid-reveal, 0);
  background-position: 6vw 18vh;
  -webkit-mask-image: radial-gradient(ellipse 66% 58% at 42% 66%, #000 0%, rgba(0,0,0,.58) 48%, transparent 100%);
  mask-image: radial-gradient(ellipse 66% 58% at 42% 66%, #000 0%, rgba(0,0,0,.58) 48%, transparent 100%);
  will-change: opacity;
}
#situation-curve { position: absolute; inset: 0; z-index: 1; display: block; width: 100%; height: 100%; }
#keyshot-link { z-index: 10; opacity: var(--curve-stage-reveal, 0); }
.cinema-shade {
  z-index: 7; background: radial-gradient(circle at 58% 42%, transparent 20%, rgba(0,3,6,.66) 100%);
  transition: background 900ms var(--ease-out);
}

.status, .sound-toggle { position: fixed; z-index: 22; text-transform: uppercase; }
/* 状态行不再报告正常阶段：叙事屏上不留小字，但它仍是 aria-live 区域并在出错时显形 */
.status {
  left: var(--edge); bottom: 2.4vh; color: var(--muted);
  opacity: 0; transition: opacity 400ms var(--ease-out);
}
body.phase-degraded .status { opacity: 1; }
/* 声音开关目前在所有阶段都不显示：叙事屏保持无小字，需要时再决定放回哪一屏 */
.sound-toggle {
  right: var(--edge); top: 76px; padding: 8px; border: 0; color: var(--white);
  background: transparent; cursor: pointer; opacity: 0; pointer-events: none;
}

.chapters { position: relative; z-index: 12; margin-top: -100svh; }
.chapter {
  min-height: 112vh; display: flex; flex-direction: column; justify-content: center;
  padding: 12vh var(--edge); opacity: 0; pointer-events: none;
  transition: opacity 420ms var(--ease-out);
}
.chapter > * { max-width: 980px; }
.chapter.is-active { opacity: 1; pointer-events: auto; }
.chapter.chapter-hero { opacity: 1; }
.chapter-hero {
  --hero-balance-line-y: 79.26%; --hero-player-line-gap: 3.74%;
  --grid-minor: 34px; --grid-major: 170px;
  position: relative; min-height: 100svh; padding: 0; overflow: visible;
  pointer-events: auto; background: #000;
}
.hero-sticky-scene {
  position: fixed; inset: 0; height: 100svh; overflow: hidden;
  max-width: none; width: 100%;
  transform: translateY(var(--hero-scene-offset, 0));
  will-change: transform;
  background:
    radial-gradient(128% 72% at 50% 112%, rgba(44,58,132,.4), transparent 64%),
    linear-gradient(180deg, #060b1c 0%, #040815 48%, #02060f 100%);
}
.hero-sticky-scene > * { max-width: none; }
.hero-backdrop { position: absolute; inset: 0; pointer-events: none; }
.hero-horizon, .hero-grain, .hero-vignette { position: absolute; inset: 0; }
/* 两级暗格：主格交点带节点圆点。首屏与态势曲线共用同一套绘制，各自给格距 */
.hero-grid, .analysis-grid {
  position: absolute; left: 0; right: 0;
  background-image:
    radial-gradient(circle at 0 0, rgba(170,202,255,.34) 0 1.2px, transparent 1.7px),
    linear-gradient(90deg, rgba(124,166,255,.105) 1px, transparent 1px),
    linear-gradient(180deg, rgba(124,166,255,.105) 1px, transparent 1px),
    linear-gradient(90deg, rgba(124,166,255,.052) 1px, transparent 1px),
    linear-gradient(180deg, rgba(124,166,255,.052) 1px, transparent 1px);
  background-size:
    var(--grid-major) var(--grid-major),
    var(--grid-major) var(--grid-major),
    var(--grid-major) var(--grid-major),
    var(--grid-minor) var(--grid-minor),
    var(--grid-minor) var(--grid-minor);
}
/* 上下两块共用同一椭圆遮罩：纵向半径取首屏高度的 64%，按各自高度换算为 81% 与 309% */
.hero-grid-upper {
  top: 0; bottom: calc(100% - var(--hero-balance-line-y)); background-position: left bottom;
  -webkit-mask-image: radial-gradient(94% 81% at 52% 100%, #000 14%, rgba(0,0,0,.66) 56%, transparent 93%);
  mask-image: radial-gradient(94% 81% at 52% 100%, #000 14%, rgba(0,0,0,.66) 56%, transparent 93%);
}
.hero-grid-lower {
  top: var(--hero-balance-line-y); bottom: 0; background-position: left top;
  -webkit-mask-image: radial-gradient(94% 309% at 52% 0, #000 14%, rgba(0,0,0,.66) 56%, transparent 93%);
  mask-image: radial-gradient(94% 309% at 52% 0, #000 14%, rgba(0,0,0,.66) 56%, transparent 93%);
}
.hero-horizon {
  background:
    radial-gradient(40% 30% at 55.5% 66%, rgba(224,120,240,.16), transparent 70%),
    radial-gradient(58% 40% at 30% 80%, rgba(78,124,236,.15), transparent 72%),
    radial-gradient(46% 34% at 22% 26%, rgba(58,90,190,.18), transparent 72%);
}
.hero-grain {
  opacity: .05; mix-blend-mode: soft-light; background-size: 140px 140px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/></filter><rect width='140' height='140' filter='url(%23g)'/></svg>");
}
.hero-vignette {
  background:
    radial-gradient(112% 86% at 50% 54%, transparent 42%, rgba(1,4,10,.7) 100%),
    linear-gradient(180deg, rgba(0,0,0,.96) 0%, rgba(0,0,0,.78) 36%, rgba(0,1,5,.36) 56%, transparent 68%, transparent 78%, rgba(2,6,15,.9));
}
/* 原片完整保留顶灯、羽毛球与球网纵深，作为右侧斜向空间层；径向遮罩让左侧标题与
   下方曲线继续落在干净底色上。两层使用不同周期的横纵漂移，形成连续缓慢的曲线路径。 */
.hero-badminton-backdrop {
  position: absolute; inset: 3vh -1vw 26vh 41vw; overflow: hidden;
  opacity: calc(1 - var(--hero-copy-exit, 0));
  -webkit-mask-image: radial-gradient(92% 92% at 76% 24%, #000 0%, rgba(0,0,0,.92) 48%, rgba(0,0,0,.45) 69%, transparent 94%);
  mask-image: radial-gradient(92% 92% at 76% 24%, #000 0%, rgba(0,0,0,.92) 48%, rgba(0,0,0,.45) 69%, transparent 94%);
}
.hero-badminton-backdrop i, .hero-badminton-backdrop b {
  position: absolute; inset: 0;
}
.hero-badminton-backdrop b {
  left: auto; bottom: auto; width: auto; height: 100%; aspect-ratio: 2048 / 1639;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.1) 12%, rgba(0,0,0,.72) 26%, #000 42%);
  mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.1) 12%, rgba(0,0,0,.72) 26%, #000 42%);
  animation: hero-shuttle-drift-y 19s var(--ease-in-out) var(--hero-photo-drift-delay) infinite alternate both;
  will-change: transform;
}
.hero-badminton-backdrop i {
  animation: hero-shuttle-drift-x 31s var(--ease-in-out) var(--hero-photo-drift-delay) infinite alternate both;
  will-change: transform;
}
.hero-badminton-backdrop b::before {
  content: ""; position: absolute; inset: 0;
  background: url("/illustrations/home-shuttle-net.jpg") center / 100% 100% no-repeat;
  filter: saturate(.82) brightness(1.12) contrast(1.08);
  opacity: 0;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 58%, rgba(0,0,0,.78) 72%, rgba(0,0,0,.28) 86%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 58%, rgba(0,0,0,.78) 72%, rgba(0,0,0,.28) 86%, transparent 100%);
  animation: hero-shuttle-reveal var(--hero-curve-entry-duration) var(--hero-curve-entry-ease) var(--hero-curve-entry-delay) forwards;
  will-change: opacity;
}
@keyframes hero-shuttle-reveal {
  from { opacity: 0; }
  to { opacity: .62; }
}
@keyframes hero-shuttle-drift-x {
  from { transform: translate3d(4.5%, 0, 0) rotate(.8deg); }
  to { transform: translate3d(-4.5%, 0, 0) rotate(-.8deg); }
}
@keyframes hero-shuttle-drift-y {
  from { transform: translate3d(0, 3%, 0); }
  to { transform: translate3d(0, -3%, 0); }
}
.hero-title {
  position: absolute; left: var(--edge); right: var(--edge); top: 15vh; z-index: 3;
  opacity: calc(1 - var(--hero-copy-exit, 0));
  transform: translateY(var(--hero-copy-offset, 0));
  will-change: opacity, transform;
}
.hero-title p { display: flex; align-items: baseline; gap: 24px; margin: 0; }
.hero-title strong {
  color: var(--apple-title-white); font-size: clamp(40px, 3.2vw, 54px); font-weight: 650;
  line-height: 1; letter-spacing: -.035em;
}
.hero-wordmark { display: inline-flex; align-items: baseline; column-gap: 0.08em; }
.hero-wordmark i {
  color: var(--apple-title-white); font-style: oblique 10deg; font-weight: 550;
  padding-inline-end: 0.08em;
}
.hero-wordmark > span { color: var(--cyan); font-style: normal; font-weight: 750; }
.hero-title em {
  color: var(--apple-title-muted); font-size: clamp(37px, 2.95vw, 50px);
  font-style: normal; letter-spacing: 0;
}
.hero-title h1 {
  display: flex; flex-wrap: wrap; align-items: center; gap: .2em;
  margin-top: 24px; color: var(--apple-title-white); text-shadow: none;
}
.hero-tactical-pill {
  display: inline-flex; align-items: center; gap: .32em;
  padding: .32em .56em .37em; border: 0; border-radius: 999px;
  background: rgb(42 42 45 / .92); color: #f5f5f7; -webkit-text-fill-color: #f5f5f7;
  box-shadow: none; font-size: .58em; font-weight: 600;
  line-height: 1.12; letter-spacing: -.01em; text-shadow: none;
  transition: background-color 180ms ease;
}
.hero-tactical-pill[data-visual-state="intro"] { background: rgb(42 42 45 / .92); }
.hero-tactical-pill::before {
  content: ""; flex: 0 0 auto; width: .28em; height: .28em; border-radius: 50%;
  background: #86868b; box-shadow: none;
}
.hero-tactical-labels {
  display: inline-block; overflow: hidden; white-space: nowrap;
  inline-size: var(--hero-tactical-label-width, auto);
  transition: inline-size 180ms var(--ease-out);
}
.hero-tactical-label {
  display: none; white-space: nowrap;
}
.hero-tactical-label[data-state="active"] {
  display: inline-block;
}
.hero-tactical-intro {
  color: var(--cyan); -webkit-text-fill-color: var(--cyan);
  font-weight: 500; letter-spacing: .08em;
}
html[lang="en"] .hero-tactical-pill { font-size: .48em; }
.hero-situation-curve {
  position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%;
  opacity: var(--hero-curve-opacity, 1);
  transform: scaleY(var(--hero-curve-compression, 1));
  transform-origin: 50% var(--hero-balance-line-y);
  will-change: transform, opacity;
}
.hero-curve-stream {
  position: absolute; left: 51.8%; top: var(--hero-balance-line-y); z-index: 4;
  width: min(38vw, 560px); height: 18px; pointer-events: none;
  opacity: var(--hero-stream-opacity, 0);
  background:
    radial-gradient(circle at 11% 22%, rgba(232,137,244,.7) 0 1.4px, transparent 2.1px),
    radial-gradient(circle at 23% 72%, rgba(120,162,255,.65) 0 1.3px, transparent 2.1px),
    radial-gradient(circle at 37% 34%, rgba(232,137,244,.58) 0 1.5px, transparent 2.3px),
    radial-gradient(circle at 51% 80%, rgba(124,226,255,.68) 0 1.3px, transparent 2.1px),
    radial-gradient(circle at 65% 18%, rgba(232,137,244,.52) 0 1.4px, transparent 2.2px),
    radial-gradient(circle at 78% 68%, rgba(124,226,255,.72) 0 1.3px, transparent 2px),
    linear-gradient(90deg, transparent 0%, rgba(232,137,244,.18) 38%, rgba(124,226,255,.7) 82%, #f5f5f7 100%) center / 100% 2px no-repeat;
  transform: translateY(-50%) translateX(var(--hero-stream-shift-x, 0)) scaleX(var(--hero-stream-scale-x, .18));
  transform-origin: 0 50%;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 24%, #000);
  mask-image: linear-gradient(90deg, transparent, #000 24%, #000);
  filter: drop-shadow(0 0 8px rgba(124,226,255,.28));
  will-change: transform, opacity;
}
.hero-curve-stream::after {
  content: ""; position: absolute; right: -2px; top: 50%; width: 5px; height: 5px;
  border-radius: 50%; background: #f5f5f7;
  box-shadow: 0 0 10px rgba(124,226,255,.82);
  transform: translateY(-50%);
}
.hero-player {
  position: absolute; left: 3.8vw; z-index: 3; width: 17px; height: 34px; color: #e889f4;
  filter: drop-shadow(0 0 7px rgba(232,137,244,.32));
  opacity: var(--hero-annotation-opacity, 1);
}
.hero-player svg { display: block; width: 100%; height: 100%; overflow: visible; }
.hero-player-upper { bottom: calc(100% - var(--hero-balance-line-y) + var(--hero-player-line-gap)); }
.hero-player-lower {
  top: calc(var(--hero-balance-line-y) + var(--hero-player-line-gap)); color: #78a2ff;
  filter: drop-shadow(0 0 7px rgba(120,162,255,.32));
}
.hero-player-lower svg { transform: scaleX(-1); }
.hero-key-marker {
  position: absolute; left: 51.8%; top: 72.2%; z-index: 5; width: 0; height: 0;
  opacity: var(--hero-annotation-opacity, 1);
}
/* 关键拍那一点保持近白且比逐拍点更大：它不属于任何一方，是被指出来的那一拍 */
.hero-key-node {
  position: absolute; left: 50%; top: 50%; width: 13px; height: 13px;
  margin: -6.5px; border-radius: 50%; background: #fff0fb;
  box-shadow: 0 0 12px rgba(255,190,246,.85);
}
/* 对焦框的竖直中心必须落在引线起点上：引线盒 right:14/bottom:14、100×52，起点在它的
   (2,4)，也就是锚点左 112px、上 62px。框右缘固定在 right:118px（起点在框外 6px），
   改高度时 bottom 要跟着改，保持 bottom + 高/2 = 61。 */
.hero-key-focus {
  position: absolute; right: 118px; bottom: 37px;
  /* 宽度跟着文字走，不写死：中文「关键拍」与英文「KeyMoment」差一倍，
     写死宽度必然一边挤一边空。左右各留 22px 呼吸，角框因此始终贴着字。 */
  width: max-content; height: 48px; padding: 0 22px;
  display: grid; place-items: center; white-space: nowrap;
}
.hero-key-focus b {
  color: #f7efff; text-indent: .16em;
}
.hero-key-focus-corners { position: absolute; inset: 0; pointer-events: none; }
.hero-key-focus::before, .hero-key-focus::after,
.hero-key-focus-corners::before, .hero-key-focus-corners::after {
  content: ""; position: absolute; width: 13px; height: 13px;
  border: 1px solid rgba(238,222,255,.82); opacity: .82;
  filter: drop-shadow(0 0 4px rgba(240,134,255,.5));
  /* 入场收拢一次之后，接一段极慢的呼吸，四个角一直在轻微伸缩。
     两条动画都动 transform，靠列表顺序交接：第二条在第一条结束的那一刻（3960+680）
     才开始，起始关键帧同样是 transform: none，接得上；opacity 只有第一条管，
     它的 forwards 填充继续生效。--focus-over-* 本来就是四个角各自朝外的方向。 */
  animation:
    hero-focus-corner 680ms cubic-bezier(.22, 1, .36, 1) 3960ms both,
    hero-focus-breathe 7200ms ease-in-out 4640ms infinite;
}
.hero-key-focus::before {
  --focus-x: 14px; --focus-y: 14px; --focus-over-x: -5px; --focus-over-y: -5px;
  top: 0; left: 0; border-right: 0; border-bottom: 0; border-top-left-radius: 6px;
}
.hero-key-focus-corners::before {
  --focus-x: -14px; --focus-y: 14px; --focus-over-x: 5px; --focus-over-y: -5px;
  top: 0; right: 0; border-left: 0; border-bottom: 0; border-top-right-radius: 6px;
}
.hero-key-focus::after {
  --focus-x: -14px; --focus-y: -14px; --focus-over-x: 5px; --focus-over-y: 5px;
  right: 0; bottom: 0; border-left: 0; border-top: 0; border-bottom-right-radius: 6px;
}
.hero-key-focus-corners::after {
  --focus-x: 14px; --focus-y: -14px; --focus-over-x: -5px; --focus-over-y: 5px;
  bottom: 0; left: 0; border-right: 0; border-top: 0; border-bottom-left-radius: 6px;
}
.hero-key-leader { position: absolute; right: 14px; bottom: 14px; width: 100px; height: 52px; overflow: visible; }
.hero-key-leader path {
  fill: none; stroke: #f086ff; stroke-opacity: .8; stroke-width: 1; stroke-linecap: round;
  stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 1;
  vector-effect: non-scaling-stroke;
}
.hero-key-leader circle { fill: #f086ff; }
.hero-scroll-cue {
  position: absolute; left: 50%; bottom: 5.5vh; z-index: 4; transform: translateX(-50%);
  width: 20px; height: 58px; overflow: hidden; pointer-events: auto;
}
.hero-scroll-cue::before {
  content: ""; position: absolute; left: 10px; top: 0; width: 1px; height: 100%;
  background: linear-gradient(180deg, rgba(115,232,255,.3), rgba(115,232,255,.06));
}
.hero-scroll-cue i {
  position: absolute; left: 10px; top: 0; width: 1px; height: 22px;
  background: linear-gradient(180deg, transparent, var(--cyan));
  box-shadow: 0 0 8px rgba(115,232,255,.6);
  animation: scroll-cue-travel 2.6s cubic-bezier(.6, 0, .35, 1) infinite;
}
/* 章节从视口底部进入时先露出的是它的顶部：文案放在章节底部要等整章滚完才出现，
   中间是大段空白。改为置顶起步 + sticky 停靠，章节一进入文案就在，读完再随章节离场。 */
/* 四个叙事章节的标题是固定层而不是 sticky：sticky 的释放时机与下一章的进入时机必然重叠，
   两个标题会在交接处叠成上下两行。改成固定在 64svh，同一时刻只有当前章节可见，
   章节之间在同一位置交叉淡化，节做纯滚动占位。 */
.chapter-video { min-height: 352svh; }
.chapter-orbit { min-height: 352svh; }
.chapter-caption {
  position: fixed; top: 64svh; left: var(--edge); right: var(--edge);
  max-width: 980px; pointer-events: none;
}
.chapter.is-active .chapter-caption { pointer-events: auto; }
.chapter-video .chapter-caption {
  top: 28svh; left: 6vw; right: auto; width: min(32vw, 440px);
  text-align: left;
  opacity: calc(var(--video-copy-reveal, 0) * (1 - var(--video-copy-exit, 0)));
  transform: translateX(calc(var(--video-copy-offset, -56px) - var(--video-copy-exit, 0) * 48px));
  will-change: transform, opacity;
}
.chapter-orbit .chapter-caption {
  top: 24svh; left: 6vw; right: auto; width: min(28vw, 440px); max-width: none;
  opacity: calc(var(--orbit-copy-reveal, 0) - var(--orbit-copy-exit, 0));
  transform: translateX(calc((1 - var(--orbit-copy-reveal, 0)) * -56px - var(--orbit-copy-exit, 0) * 48px));
  will-change: transform, opacity;
}
.chapter-orbit .chapter-caption h2 {
  max-width: none;
}
/* 文字逐行浮现：整块只负责显隐，位移与错峰由每一行自己承担 */
.chapter-caption .line { display: block; }
.chapter-caption .br-s { display: none; }
.chapter-caption .line {
  opacity: 0; transform: translateY(32px);
  transition: opacity 900ms var(--ease-reveal), transform 900ms var(--ease-reveal);
}
.chapter.is-active .chapter-caption .line { opacity: 1; transform: none; }
.chapter-video .chapter-caption .line { opacity: 1; transform: none; transition: none; }
.chapter.is-active .chapter-caption .line:nth-child(2) { transition-delay: 90ms; }
/* 三维标题作为一个稳定文字块从左侧进入，不再叠加逐行遮罩或纵向位移。 */
.chapter.is-active.chapter-orbit .chapter-caption .line {
  opacity: 1; transform: none; clip-path: none; transition: none;
}
/* 态势章节仍需在右侧三维证据经过亮部时维持文字对比度。 */
.chapter-curve .chapter-caption::before {
  content: ""; position: absolute; inset: -90% -20% -100% -12%; z-index: -1;
  background: radial-gradient(62% 130% at 14% 50%, rgba(2,6,14,.5), rgba(2,6,14,.18) 55%, transparent 86%);
  pointer-events: none;
}
/* 态势结论与曲线共享左侧分析列，右侧留给仍然可辨识的三维证据。 */
.chapter-curve .chapter-caption {
  top: 14svh; left: 6vw; right: auto; width: 44vw;
  opacity: var(--curve-copy-reveal, 0);
  transform: translateX(calc((1 - var(--curve-copy-reveal, 0)) * -36px));
  will-change: transform, opacity;
}
/* 关键词强调：与站点主色一致，字重比正文标题重一档 */
h2 .accent {
  font-weight: 650; font-style: normal; color: var(--cyan);
  -webkit-text-fill-color: var(--cyan);
  text-shadow: 0 0 24px rgba(115,232,255,.32);
}
.video-explainer { max-width: none; }
.capture-copy {
  margin: 22px auto 0; max-width: 760px; color: var(--apple-title-muted);
}
.capture-copy strong { color: var(--apple-title-white); font-weight: 600; }
.video-copy-stack {
  display: grid; margin: 22px 0 0; max-width: 760px;
}
.video-copy-stack .capture-copy {
  grid-area: 1 / 1; margin: 0;
  transform: none; transition: none; will-change: opacity;
}
.video-copy-primary {
  opacity: calc(1 - var(--video-primary-exit, 0));
}
.video-copy-detail {
  opacity: max(.001, var(--video-detail-reveal, 0));
}
.capture-detail-line { display: block; }
.video-copy-stack strong { white-space: nowrap; }
.orbit-copy-stack {
  display: grid; margin: 22px 0 0; max-width: 420px;
}
.chapter-orbit .orbit-copy {
  grid-area: 1 / 1; margin: 0; max-width: 420px;
  transform: none; transition: none; will-change: opacity;
}
.orbit-copy-primary {
  opacity: calc(1 - var(--orbit-primary-exit, 0));
}
.orbit-copy-detail {
  opacity: max(.001, var(--orbit-detail-reveal, 0));
}
.orbit-copy strong { white-space: nowrap; }
/* Apple 式标题以克制的材质渐变代替发光描边；纯色是旧浏览器的可读回退。 */
.hero-title h1,
.chapter-caption h2 .line {
  color: var(--apple-title-white);
  text-shadow: 0 4px 32px rgba(0,0,0,.7);
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero-headline-prefix,
  .chapter-caption h2 .line {
    background: var(--apple-headline-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    filter: drop-shadow(0 4px 22px rgba(0,0,0,.34));
  }
}

/* 章节显隐一律走 .chapter.is-active，不用 id 选择器——id 的优先级会盖掉
   首屏由 --hero-fade 驱动的淡出，也盖掉揭示阶段沿用态势章节文案的映射。 */
body.phase-video .cinema-shade { background: transparent; }
body.phase-curve .cinema-shade {
  background: linear-gradient(90deg, rgba(0,2,5,.82), rgba(0,3,6,.34) 48%, rgba(0,3,6,.08));
}

.hero-grid { animation: hero-fade-in 1200ms var(--ease-out) both; }
.hero-title p { animation: hero-rise 1000ms var(--ease-out) 160ms both; }
.hero-title h1 { animation: hero-rise 1100ms var(--ease-out) 300ms both; }
/* 曲线生长是首屏的主动作，走 3.4 秒；其余元素按它的进度顺次跟上，
   看得清「先有曲线、再有逐拍点、最后才是关键拍」这个顺序。
   缓动取 easeInOutCubic：原来的 (.32,.72,.2,1) 是强 ease-out，
   三分之一的时间就画掉七成路径，起笔一冲而过、收尾又磨蹭。 */
.hero-curve-line, .hero-curve-halo {
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: hero-draw var(--hero-curve-entry-duration) var(--hero-curve-entry-ease) var(--hero-curve-entry-delay) forwards;
}
/* 色带由一块随曲线同步生长的裁切揭示，本身不做淡入：整块淡入会先于笔画出现。
   裁切按 x 推进、笔画按弧长推进，陡升段两者会错开，因此裁切比笔画晚 120ms 起步——
   宁可带子略微跟在笔画后面，也不能跑到前面。 */
.hero-band-mask {
  transform-origin: 0 0; transform: scaleX(0);
  animation: hero-band-grow 3400ms cubic-bezier(.65, 0, .35, 1) 480ms forwards;
}
.hero-shot-ticks { animation: hero-fade-in 1100ms var(--ease-out) 1500ms both; }
/* 逐拍点按击球方交替上色，两个色就是左侧两个小人的色相：
   上方 #e889f4 / 下方 #78a2ff，各自提亮到 HSL 亮度 .85（#f1b9f8 / #b3caff）。
   直接用小人原色不行——曲线笔画本身就是中亮度的蓝紫渐变，原色与它的对比只有
   1.12–1.48（蓝点压在蓝线段上几乎看不见）；提亮后最低 1.73，比原来的单色点（1.58）还好。
   相位锚在峰值那一拍：曲线在它之后冲进上方选手的领域，所以 859 归上方，其余交替。

/* 逐拍点是零长度的圆头描边，不是 <circle>：viewBox 以 preserveAspectRatio="none" 拉伸
   （实测横 1.05、纵 0.9272，各向异性 13.2%），<circle> 会被压成椭圆；
   non-scaling-stroke 的圆头帽在设备空间里始终是正圆。零长度路径的 fill-box 是退化的，
   缩放入场因此要用 stroke-box 定原点。 */
.hero-shot-rings path,
.hero-shot-dots path {
  transform-box: stroke-box; transform-origin: center;
  animation: hero-dot-in 520ms var(--ease-out) both;
}
.hero-shot-rings path:nth-child(1),
.hero-shot-dots path:nth-child(1) { animation-delay: 1520ms; }
.hero-shot-rings path:nth-child(2),
.hero-shot-dots path:nth-child(2) { animation-delay: 1790ms; }
.hero-shot-rings path:nth-child(3),
.hero-shot-dots path:nth-child(3) { animation-delay: 1970ms; }
.hero-shot-rings path:nth-child(4),
.hero-shot-dots path:nth-child(4) { animation-delay: 2060ms; }
.hero-shot-rings path:nth-child(5),
.hero-shot-dots path:nth-child(5) { animation-delay: 2130ms; }
.hero-shot-rings path:nth-child(6),
.hero-shot-dots path:nth-child(6) { animation-delay: 2250ms; }
.hero-shot-rings path:nth-child(7),
.hero-shot-dots path:nth-child(7) { animation-delay: 2440ms; }
.hero-shot-rings path:nth-child(8),
.hero-shot-dots path:nth-child(8) { animation-delay: 2680ms; }
.hero-key-stroke { animation: hero-fade-in 900ms var(--ease-out) 2750ms both; }
.hero-key-drop { animation: hero-fade-in 800ms var(--ease-out) 3350ms both; }
.hero-key-node { animation: hero-fade-in 360ms var(--ease-out) 3600ms both; }
.hero-key-leader path { animation: hero-key-leader-draw 420ms var(--ease-out) 3680ms forwards; }
.hero-key-leader circle { animation: hero-fade-in 220ms var(--ease-out) 3680ms both; }
.hero-key-focus b { animation: hero-fade-in 320ms var(--ease-out) 4140ms both; }
.hero-scroll-cue { animation: hero-fade-in 900ms var(--ease-out) 4300ms both; }


@keyframes hero-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes hero-rise { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }
@keyframes hero-draw { to { stroke-dashoffset: 0; } }
@keyframes hero-band-grow { to { transform: scaleX(1); } }
@keyframes hero-dot-in { from { opacity: 0; transform: scale(.3); } to { opacity: 1; transform: none; } }
@keyframes hero-key-leader-draw { to { stroke-dashoffset: 0; } }
/* 极慢的伸缩：四个角朝各自的外侧推 3.1px 再收回，一圈 7.2 秒。
   幅度必须小、周期必须长——这一屏的主动作是曲线生长，角框只是余韵。 */
@keyframes hero-focus-breathe {
  0%, 100% { transform: none; }
  50% {
    transform: translate(
      calc(var(--focus-over-x) * .62),
      calc(var(--focus-over-y) * .62)
    );
  }
}
@keyframes hero-focus-corner {
  0% { opacity: 0; transform: translate(var(--focus-x), var(--focus-y)); }
  30% { opacity: .82; transform: translate(var(--focus-x), var(--focus-y)); }
  70% { transform: translate(var(--focus-over-x), var(--focus-over-y)); }
  100% { opacity: .82; transform: none; }
}
@keyframes scroll-cue-travel {
  0% { opacity: 0; transform: translateY(-24px); }
  18%, 76% { opacity: 1; }
  100% { opacity: 0; transform: translateY(58px); }
}

/* 窄桌面窗（两栏还在、说明列已被压到 200–260px）：
   标题按列宽再降一档，正文启用只在这一段生效的断行——与苹果中文站 <br class="small"> 同一种做法。 */
@media (min-width: 721px) and (max-width: 1023px) {
  .chapter-caption .br-s { display: inline; }
}

@media (max-width: 720px) {
  .sound-toggle { right: 3vw; top: 60px; }
  .chapter { min-height: 108vh; padding: 12vh 6vw; align-items: flex-start; text-align: left; }
  .chapter.chapter-video { min-height: 352svh; }
  .chapter.chapter-orbit { min-height: 352svh; }
  .chapter-hero { min-height: 100svh; padding: 0; }
  .hero-title { top: 13vh; }
  .hero-title p { gap: 14px; }
  .hero-title strong, .hero-title em { font-size: clamp(32px, 9vw, 42px); }
  .hero-title h1 { inline-size: 100%; max-inline-size: 100%; margin-top: 18px; row-gap: .24em; }
  .hero-headline-prefix { flex: 0 0 100%; min-inline-size: 0; }
  html[lang="en"] .hero-headline-prefix { white-space: normal; }
  .hero-tactical-pill { font-size: .54em; }
  html[lang="en"] .hero-tactical-pill { font-size: .42em; }
  .hero-badminton-backdrop {
    inset: 26svh -7vw 34svh 23vw;
    -webkit-mask-image: radial-gradient(96% 88% at 76% 30%, #000 0%, rgba(0,0,0,.88) 48%, transparent 94%);
    mask-image: radial-gradient(96% 88% at 76% 30%, #000 0%, rgba(0,0,0,.88) 48%, transparent 94%);
  }
  .hero-badminton-backdrop b { inset: 0 0 auto 0; width: 100%; height: auto; }
  .hero-player { left: 5vw; transform: scale(.92); transform-origin: left center; }
  .chapter-hero { --grid-minor: 26px; --grid-major: 130px; }
  .hero-key-marker { transform: scale(.84); }
  .hero-scroll-cue { bottom: 4vh; height: 48px; }
  .capture-copy { margin-top: 16px; }
  .video-copy-stack { margin-top: 16px; }
  .curve-shell { left: 6vw; right: 2vw; bottom: 8vh; top: auto; width: auto; height: 32vh; }
  .chapter-curve .chapter-caption { top: 11svh; left: 6vw; right: 6vw; width: auto; }
  .chapter-orbit .chapter-caption {
    top: 12svh; left: 6vw; right: 6vw; width: auto;
  }
  .chapter-video .chapter-caption { top: 11svh; left: 6vw; width: 88vw; }
  .video-macbook { top: 38svh; left: 50%; width: 94vw; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  #match-video, .three-shell, .curve-shell, #keyshot-link, .cinema-shade, .chapter {
    transition: opacity 180ms ease;
  }
  .curve-shell, .chapter-curve .chapter-caption { transform: none; }
  .chapter-orbit .chapter-caption { transform: none; }
  .chapter.is-active.chapter-orbit .chapter-caption .line { clip-path: none; transform: none; }
  .chapter-video .chapter-caption { opacity: var(--video-copy-reveal, 0); transform: none; }
  .video-macbook { transform: translate(-50%, 0) scale(1); }
  .video-macbook-display { clip-path: none; transform: none; }
  .video-macbook::before { transform: none; }
  .video-macbook::after { transform: none; }
  .hero-situation-curve { transform: none; }
  .hero-curve-stream { transform: none; opacity: 0; }
  .video-scan-curtain {
    transform: none;
    opacity: var(--video-scan-curtain-opacity, 0);
  }
  .video-scanline { transform: none; box-shadow: none; }
  .hero-grid, .hero-title p, .hero-title h1, .hero-band-mask, .hero-shot-ticks, .hero-shot-rings path, .hero-shot-dots path,
  .hero-key-stroke, .hero-key-drop, .hero-key-marker, .hero-key-node,
  .hero-key-leader path, .hero-key-leader circle, .hero-key-focus b,
  .hero-key-focus::before, .hero-key-focus::after,
  .hero-key-focus-corners::before, .hero-key-focus-corners::after {
    animation: none; opacity: 1; transform: none;
  }
  .hero-tactical-labels { transition: none; }
  .hero-badminton-backdrop i, .hero-badminton-backdrop b { animation: none; transform: none; }
  .hero-badminton-backdrop b::before {
    animation: hero-shuttle-reveal 600ms var(--ease-out) 120ms forwards;
  }
  .chapter-caption .line { transform: none; }
  .hero-scroll-cue { animation: none; opacity: 1; }
  .hero-scroll-cue i { animation: none; opacity: .8; transform: translateY(20px); }
  .hero-curve-line, .hero-curve-halo { animation: none; stroke-dashoffset: 0; }
  .hero-key-leader path { stroke-dashoffset: 0; }
  .hero-player, .hero-key-marker { opacity: var(--hero-annotation-opacity, 1); }
}

.court-poster {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; background: #041019;
  filter: brightness(calc(1 - .28 * var(--analysis-layout, 0)));
}
#rendered-3d-video { opacity: 0; transition: opacity 200ms ease; }
.has-video-frame #rendered-3d-video { opacity: 1; }
.court-loading {
  position: absolute; left: 50%; bottom: 12%; transform: translateX(-50%);
  z-index: 4; padding: 8px 12px; border-radius: 8px;
  background: rgba(2, 7, 11, .82); color: #d4dee5; font-size: 13px;
  pointer-events: auto;
}
.court-loading[hidden], .court-loading button[hidden] { display: none; }
.court-loading button {
  margin-left: 12px; border: 0; padding: 4px 8px;
  background: transparent; color: var(--cyan); font: inherit; cursor: pointer;
}
@media (prefers-reduced-motion: reduce) {
  #rendered-3d-video { transition: none; }
}
