/* =============================================================================
   班级喊话助手 · 官网样式
   概念：「安静的教室工具」—— 暖白极简（Notion）+ 渐变只出现在 Hero（Stripe）
        + 滚动叙事与超大标题（Apple）。给老师用的工具，界面本身要安静。

   设计系统先行：所有颜色 / 字号 / 间距 / 圆角都从变量取，页面里不写死 hex。
   -----------------------------------------------------------------------------
   三条来自参考报告的硬规矩（违反即返工）：
     · 卡片用**发丝边框**（1px rgba(26,26,24,.08)）而不是阴影；阴影只给"浮起来的产品图"且极轻
     · **不用 backdrop-filter**（老设备性能差）、**不用 transition: all**、**不用视差滚动**
     · 动效只两种：hover/focus 用 CSS transition（.18s ease）；
       区块入场用 IntersectionObserver + transition（.6s cubic-bezier(.16,1,.3,1)，位移 16px）
   对比度（按 WCAG 相对亮度算过，不是估的）：
     · 正文 #1a1a18 / 底 #fafaf8 = 16.4:1　副文 #6b6b63 = 5.6:1
     · 白字 / #2563eb 按钮 = 5.17:1　链接 #2563eb / #fafaf8 = 5.0:1
     · 暗色：正文 #ededed / #0a0a0a = 16.9:1　链接 #7aa2ff = 7.99:1　白字 / #3b6bf5 = 4.56:1
   ============================================================================= */

/* ---------------------------------------------------------------- 设计令牌 */
:root {
  /* 配色：暖白极简。底色刻意不用纯白 —— 大面积纯白刺眼 */
  --bg:          #fafaf8;
  --bg-alt:      #f5f4f0;
  --surface:     #ffffff;
  --text:        #1a1a18;
  --text-2:      #56564f;
  --text-3:      #6e6a61;   /* 最弱的一档也必须过 AA：在 #fafaf8 上 5.15:1（原来 #8b8578 只有 3.5:1，Lighthouse 报红） */
  --border:      rgba(26, 26, 24, .08);
  --border-2:    rgba(26, 26, 24, .14);

  --accent:      #2563eb;   /* 链接 / 图标 / 强调文字（#fafaf8 上 5.0:1） */
  --accent-soft: #3b82f6;   /* 只用于渐变与装饰，不承载文字 */
  --accent-fill: #2563eb;   /* 按钮底色（配白字 5.17:1） */
  --accent-hover:#1d4ed8;
  --accent-hover-soft: #dbeafe;             /* 图标底色的 hover 档（比 --wash 明显，但不抢视线） */
  --on-accent:   #ffffff;
  --wash:        rgba(59, 130, 246, .10);   /* 图标底色 */

  /* 字体：系统栈，不引外部字体 */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
          "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;

  /* 字号：层级差距要拉大（56-72 / 20-24 / 16-18） */
  --fs-hero:    clamp(40px, 5.6vw, 72px);
  --fs-h2:      clamp(28px, 3.4vw, 46px);
  --fs-h3:      19px;
  --fs-lead:    clamp(17px, 1.5vw, 22px);
  --fs-body:    17px;
  --fs-small:   14.5px;
  --fs-eyebrow: 12.5px;

  /* 行高：标题紧、正文松 */
  --lh-hero: 1.08;
  --lh-h2:   1.18;
  --lh-body: 1.75;

  /* 间距：4/8 基准 */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px; --s5: 24px;
  --s6: 32px; --s7: 40px; --s8: 56px; --s9: 80px;  --s10: 120px; --s11: 160px;

  /* 区块节奏：刻意不统一（Hero 更宽、功能更紧），形成呼吸感 */
  --pad-hero:  var(--s11);
  --pad-sec:   var(--s10);
  --pad-tight: 100px;

  --maxw:      1120px;
  --maxw-read: 720px;      /* 正文阅读宽度（65-75 字符） */
  --pad-x:     24px;

  --r-sm: 10px;
  --r:    14px;
  --r-lg: 20px;
  --r-pill: 980px;

  --ease-out: cubic-bezier(.16, 1, .3, 1);   /* 区块入场 */
  --ease:     cubic-bezier(.4, 0, .2, 1);    /* 状态变化 */
  --t-fast:   .18s;                          /* hover / focus */
  --t-enter:  .6s;                           /* 区块入场 */
  --t-hero:   .56s;                          /* Hero 里单个元素的入场时长（错峰靠 delay，不靠拉长） */
  --t-theme:  .2s;                           /* 深浅色切换：≤200ms，长于这个会"糊"一下 */

  --nav-h: 60px;

  /* 唯一的阴影：给"浮起来的产品图"，极轻；卡片一律不用 */
  --shadow-shot: 0 1px 2px rgba(26, 26, 24, .04);
}

[data-theme="dark"] {
  --bg:          #0a0a0a;
  --bg-alt:      #141414;
  --surface:     #1a1a1a;
  --text:        #ededed;
  --text-2:      #a1a1a1;
  --text-3:      #8a8a8a;
  --border:      rgba(255, 255, 255, .08);
  --border-2:    rgba(255, 255, 255, .16);

  --accent:      #7aa2ff;   /* 暗底上做文字/链接：7.99:1 */
  --accent-soft: #5b6cff;
  --accent-fill: #3b6bf5;   /* 白字压在上面 4.56:1 */
  --accent-hover:#2f5ce8;
  --accent-hover-soft: rgba(122, 162, 255, .26);
  --on-accent:   #ffffff;
  --wash:        rgba(122, 162, 255, .14);

  --shadow-shot: 0 1px 2px rgba(0, 0, 0, .5);
}

/* ---------------------------------------------------------------- 基础 */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; height: auto; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* 主题切换：只给**颜色类**属性加过渡，且只在脚本挂上 `.theming` 的那 ~200ms 内生效
   （见 js/site.js 的 applyTheme）。为什么不做成常驻：
     · 常驻会让首次绘制前的那次主题落地也变成"从浅色淡到深色"，那才是真的闪；
     · 常驻还得给 body/每个组件都挂一遍，容易碰到不该过渡的属性。
   切之前挂类、切完（--t-theme + 40ms）移除，从根上杜绝"过渡未结束又切一次"的叠加。 */
.theming,
.theming body,
.theming .nav,
.theming .nav__theme,
.theming .nav__brand,
.theming .nav__links > a,
.theming .card,
.theming .card__ico,
.theming .scene__frame,
.theming .dl__card,
.theming .btn,
.theming .foot,
.theming .foot a,
.theming .hero,
.theming .stats {
  transition:
    background-color var(--t-theme) ease,
    border-color var(--t-theme) ease,
    color var(--t-theme) ease,
    fill var(--t-theme) ease;
}

/* 焦点环只在键盘导航时出现（鼠标点击不显示）—— 报告 5.1 的明确要求。
   颜色用 --accent：浅色下 #2563eb / 暖白 5.0:1，深色下 #7aa2ff 更亮（原来的 #097fe8 在深色底上偏暗）。
   <a> 的圆角用 --r-sm，跟着按钮/导航项的形状走，不被这里统一成 14px。 */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
.btn:focus-visible { border-radius: var(--r-pill); }
.nav__theme:focus-visible { border-radius: 50%; }

.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--pad-x); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  padding: var(--s3) var(--s5);
  background: var(--accent-fill); color: var(--on-accent);
  border-radius: 0 0 var(--r-sm) 0;
}
.skip:focus { left: 0; }

/* 主题切换：两张截图只显示对应的一张 */
.only-dark { display: none; }
[data-theme="dark"] .only-light { display: none; }
[data-theme="dark"] .only-dark { display: block; }

/* ---------------------------------------------------------------- 文字层级 */
.eyebrow {
  margin: 0 0 var(--s4);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: .16em;          /* 中文页面里的小标签靠字距拉开，不靠加粗 */
  text-transform: uppercase;
  color: var(--text-3);
}
.h2 {
  margin: 0 0 var(--s5);
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -.02em;
  font-weight: 650;
}
.lead {
  margin: 0 auto;
  max-width: var(--maxw-read);    /* 正文不超过 720px */
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: var(--text-2);
}

/* ---------------------------------------------------------------- 按钮 */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: 46px;                       /* 触控目标 ≥44px */
  padding: 13px 24px;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font: inherit;
  font-size: 16.5px;
  font-weight: 550;
  line-height: 1;
  cursor: pointer;
  background: none;
  transition: background-color var(--t-fast) ease, border-color var(--t-fast) ease,
              color var(--t-fast) ease, transform var(--t-fast) ease;
}
.btn:hover { text-decoration: none; }
.btn--primary { background: var(--accent-fill); color: var(--on-accent); }
.btn--primary:hover { background: var(--accent-hover); }
.btn--primary:active { transform: translateY(1px); }
.btn--ghost { color: var(--text); border-color: var(--border-2); }
.btn--ghost:hover { background: var(--surface); border-color: var(--text-3); }
.btn--ghost:active { transform: translateY(1px); }
.btn--lg { font-size: 17.5px; padding: 16px 30px; min-height: 52px; }
.btn__in {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  transition: opacity var(--t-fast) ease;
}
.btn[aria-disabled="true"] { opacity: .45; pointer-events: none; }
/* 还没拿到版本号 / 链接时，按钮内容半隐 —— 状态是真的，但看起来是"在等"而不是"坏了"。
   数据到了由 JS 加 .is-ready，内容淡入（只动 opacity，不动尺寸，不触发 CLS）。 */
.js .btn[aria-disabled="true"] .btn__in { opacity: .7; }
.js .btn.is-ready .btn__in { opacity: 1; }

/* ---------------------------------------------------------------- 顶栏 */
/* 刻意**不用 backdrop-filter**（报告列为禁止项）：实底 + 一条发丝下边线，安静且不挑设备。
   「滚过 Hero」是一档状态（.nav.is-solid，由 IntersectionObserver 盯 .hero__sentinel 得到，
   全程不监听 scroll）：底色从 --bg 提到 --surface、下边线从透明变成发丝线、
   栏高由 60 → 56px。三样都只动颜色与尺寸，不动透明度，所以它任何时候都是**实底**，
   贴着正文滚动也不会透出字来。 */
.nav {
  position: sticky; top: 0; z-index: 100;
  height: var(--nav-h);
  background: var(--bg);
  border-bottom: 1px solid transparent;
  transition:
    height var(--t-fast) ease,
    background-color var(--t-fast) ease,
    border-bottom-color var(--t-fast) ease;
}
.nav.is-solid {
  height: 56px;
  background: var(--surface);
  border-bottom-color: var(--border);
}
.nav__inner {
  max-width: var(--maxw); height: 100%; margin: 0 auto; padding: 0 var(--pad-x);
  display: flex; align-items: center; gap: var(--s5);
}
.nav__brand { display: inline-flex; align-items: center; gap: var(--s2); color: var(--text); font-weight: 600; font-size: 15.5px; }
.nav__brand:hover { text-decoration: none; }
.nav__logo { display: inline-flex; color: var(--accent); }
.nav__links { margin-left: auto; display: flex; align-items: center; gap: var(--s6); }
.nav__links > a { color: var(--text-2); font-size: 15px; transition: color var(--t-fast) ease; }
.nav__links > a:hover { color: var(--text); text-decoration: none; }
/* 当前所在区块：在链接下面长出一条 2px 的短横线而不是换色加粗 ——
   换色会和 hover 撞车（用户分不清"我在哪"和"我指着哪"）。
   线宽用 transform: scaleX 展开，不改布局，也不会让导航项宽度跳。 */
.nav__links > a:not(.nav__cta) { position: relative; }
.nav__links > a:not(.nav__cta)::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -10px;
  height: 2px; border-radius: 2px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: center;
  transition: transform var(--t-fast) var(--ease);
}
.nav__links > a.is-active { color: var(--text); }
.nav__links > a.is-active::after { transform: scaleX(1); }
.nav__cta {
  color: var(--on-accent) !important;
  background: var(--accent-fill); padding: 9px 18px; border-radius: var(--r-pill);
  transition: background-color var(--t-fast) ease;
}
.nav__cta:hover { background: var(--accent-hover); }
.nav__theme {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;              /* 触控目标 */
  border: 1px solid var(--border-2); border-radius: 50%;
  background: none; color: var(--text-2); cursor: pointer;
  transition: color var(--t-fast) ease, border-color var(--t-fast) ease;
}
.nav__theme:hover { color: var(--text); border-color: var(--text-3); }
[data-theme="light"] .ico-moon { display: none; }
[data-theme="dark"] .ico-sun { display: none; }

/* 滚动进度条：2px，压在顶栏上沿，只在真正有东西可滚时出现（JS 挂 .is-on）。
   用 scaleX 而不是 width —— 每帧只合成、不重排（这是我们不用 scroll 事件做**动画**的前提：
   这里读的位置来自 IntersectionObserver，只有进度条这一个值走 rAF，且只写 transform）。 */
.progress {
  position: fixed; top: 0; left: 0; z-index: 101;
  width: 100%; height: 2px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: 0 50%;
  opacity: 0;
  transition: opacity var(--t-fast) ease;
  pointer-events: none;
}
.progress.is-on { opacity: 1; }

/* ---------------------------------------------------------------- ① Hero */
/* 渐变**只在这里**出现一次（Stripe 的做法）：一层极淡的径向光 + 一层暖白→白 的线性 */
.hero {
  padding: var(--pad-hero) 0 var(--s9);
  background:
    radial-gradient(ellipse 70% 55% at 50% -10%, rgba(59, 130, 246, .13), transparent 70%),
    linear-gradient(180deg, var(--bg) 0%, var(--surface) 100%);
}
[data-theme="dark"] .hero {
  background:
    radial-gradient(ellipse 70% 55% at 50% -10%, rgba(91, 108, 255, .18), transparent 70%),
    linear-gradient(180deg, var(--bg) 0%, var(--bg-alt) 100%);
}
.hero__inner { text-align: center; }
.hero__title {
  margin: 0 0 var(--s5);
  font-size: var(--fs-hero);
  line-height: var(--lh-hero);
  letter-spacing: -.03em;
  font-weight: 680;                        /* 报告：600-700，不用 800-900 */
}
.hero__sub {
  margin: 0 auto var(--s7);
  max-width: 620px;
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: var(--text-2);
}
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s3); justify-content: center; margin-bottom: var(--s9); }

/* 产品图：发丝边框 + 唯一的、极轻的阴影 */
.shot { margin: 0; }
.shot--hero {
  max-width: 960px; margin: 0 auto;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow-shot);
}
.shot__img { width: 100%; }

.scrollhint {
  display: inline-flex; flex-direction: column; align-items: center; gap: var(--s1);
  margin-top: var(--s7);
  font-size: 12.5px; letter-spacing: .08em; color: var(--text-3);
}
.scrollhint:hover { color: var(--text-2); text-decoration: none; }
.scrollhint svg { animation: bob 2.4s var(--ease) 1.1s infinite; }
@keyframes bob { 0%, 100% { transform: translateY(0); opacity: .55 } 50% { transform: translateY(6px); opacity: 1 } }

/* Hero 错峰入场：eyebrow → h1 → 副标题 → 按钮 → 滚动提示，每个 60-70ms 一步。
   ⚠️ 产品图（.shot--hero）**不参与**这套动画 —— 它是首屏的 LCP 元素，
      任何 opacity/transform 都会把它记成"更晚才画完"，直接把 LCP 推后。
      让它就地出现，只动它周围的东西，视觉上照样是"一层层落下来"。
   为什么用 @keyframes 而不是 .reveal 那套 transition：
     入场必须在**首帧之后**就开始，而 .reveal 要等 IntersectionObserver 回调（下一帧或更晚），
     中间会闪一下"全部已显示"。keyframes 的 backwards 填充让元素从第一帧就是 opacity:0，
     到点自己播放，中间没有时间窗。
   没有 JS（`.js` 不在）时这段整个不生效 —— 文字直接可读。 */
/* 导航哨兵：给顶栏"滚过 Hero"用的观测点。
   ⚠️ 位置**必须落在首屏以内**才算对 —— 一开始写成 Hero 的末尾，
      而 Hero 高 1245px、视口只有 900px，哨兵在 scrollY=0 时就在折线以下，
      于是页面一打开顶栏就是"实底"（实测：navSolidAtTop 一直是 true）。
   `calc(100vh - 140px)` 保证它停在首屏里（贴着底边往上留 140px），
   min(120px) 兜住极矮视口，max(..., var(--nav-h)) 保证 Hero 特别矮时也不会跑到区块外面。
   绝对定位、零高度：不参与排版，不挤任何东西。 */
.hero { position: relative; }
.hero__sentinel {
  position: absolute; left: 0;
  top: max(clamp(120px, calc(100vh - 140px), 640px), var(--nav-h));
  width: 100%; height: 0;
}
.js .hero-eyebrow,
.js .hero__title,
.js .hero__sub,
.js .hero__actions,
.js .scrollhint { opacity: 0; }
.js.hero-in .hero-eyebrow,
.js.hero-in .hero__title,
.js.hero-in .hero__sub,
.js.hero-in .hero__actions,
.js.hero-in .scrollhint { animation: heroIn var(--t-hero) var(--ease-out) both; }
.js.hero-in .hero-eyebrow { animation-delay: 40ms; }
.js.hero-in .hero__title { animation-delay: 110ms; }
.js.hero-in .hero__sub { animation-delay: 190ms; }
.js.hero-in .hero__actions { animation-delay: 260ms; }
.js.hero-in .scrollhint { animation-delay: 520ms; }
/* 位移 18px：和 .reveal 的 16px 同一量级，克制、不干扰阅读（报告：8-16px 档） */
@keyframes heroIn {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}
/* 下载区三条内容各晚 60-70ms 进场。
   ⚠️ 用**延迟 420ms 的动画**而不是"加载时就在播的动画"：这个区块远在首屏之外，
      如果它一上来就播，下载区的文字会参与首屏的 LCP 竞争；延迟到首屏画完再动，
      既拿不到 LCP 头上，用户滚到底时也照样看得到这一步。
      无 JS 时 dlIn 不挂 class，内容停在正常状态（不是停在 opacity:0）。 */
.js .dl__card #dl-version { animation: dlIn .34s var(--ease-out) 420ms both; }
.js .dl__card #dl-main { animation: dlIn .34s var(--ease-out) 490ms both; }
.js .dl__card #dl-note { animation: dlIn .34s var(--ease-out) 560ms both; }
@keyframes dlIn {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: none; }
}

/* ------------------------------------------- 数字条（Hero 下沿，不单独成区块） */
.stats { border-top: 1px solid var(--border); background: var(--surface); }
.stats__grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s5);
  padding-top: var(--s8); padding-bottom: var(--s8);
}
.stat { text-align: center; }
.stat__num {
  display: block;
  font-size: clamp(30px, 3vw, 40px);
  font-weight: 650; letter-spacing: -.02em; line-height: 1.15;
  font-variant-numeric: tabular-nums;      /* 数字等宽，四个数才对得齐 */
}
.stat__unit { margin-left: 3px; font-size: .4em; font-weight: 600; color: var(--text-3); letter-spacing: 0; }
.stat__label { display: block; margin-top: var(--s2); font-size: var(--fs-small); color: var(--text-2); }

/* ---------------------------------------------------------------- 区块骨架 */
.section { padding: var(--pad-sec) 0; }
.section--alt { background: var(--bg-alt); }
.section--tight { padding: var(--pad-tight) 0; }
.section > .wrap { text-align: center; }

/* ---------------------------------------------------------------- ② 特性 */
.cards {
  margin-top: var(--s9);
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s5);
  text-align: left;
}
.card {
  padding: var(--s6) var(--s6) var(--s7);
  background: var(--surface);
  border: 1px solid var(--border);          /* 发丝边框，不用阴影 */
  border-radius: var(--r);
  transition: border-color var(--t-fast) ease, transform var(--t-fast) ease;
}
/* 四张卡是 <article>，本身不可聚焦；hover 与 :focus-within 走同一套反馈，
   所以键盘 Tab 到的按钮/链接也会让卡片"亮起来"，指针和键盘看到的是同一个界面。
   transform 仍只 2px —— 报告允许 8-16px 的**入场**位移，但 hover 位移要更小，
   大了会让整行卡片看起来在抖。 */
.card:hover,
.card:focus-within { border-color: var(--border-2); transform: translateY(-2px); }
.card__ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin-bottom: var(--s5);
  border-radius: var(--r-sm);
  background: var(--wash); color: var(--accent);
  transition: background-color var(--t-fast) ease, transform var(--t-fast) ease;
}
.card:hover .card__ico,
.card:focus-within .card__ico {
  background: var(--accent-hover-soft);
  transform: translateY(-2px) scale(1.04);   /* 图标自己再抬一点点，和卡片的 2px 叠成层次 */
}
.card h3 { margin: 0 0 var(--s2); font-size: var(--fs-h3); font-weight: 620; letter-spacing: -.01em; }
.card p { margin: 0; font-size: 15.5px; line-height: 1.7; color: var(--text-2); }

/* ---------------------------------------------------------------- ③ 场景 */
.scenes {
  margin-top: var(--s9);
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s6);
  text-align: left;
}
.scene { margin: 0; }
/* 边框搬到 .scene__frame（裁切盒）上：图片放大后仍被 overflow:hidden 裁在圆角里，
   边框本身也保持 1px 不变粗（如果让图片自己放大，边框会跟着被放大成模糊的粗边）。 */
.scene__frame {
  display: block;
  /* ⚠️ 三张图的原图比例并不一样（1920×1080 / 1920×1044 / 1440×900），
     只给 width:100% 的话三块画框会各自高 190 / 184 / 211px，
     三条说明文字就错开到 544 / 538 / 565 —— 实测过，一眼能看出"不是一套"。
     锁成 16:9 后三块画框同高（189px），说明文字落在同一条基线上。 */
  aspect-ratio: 16 / 9;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  overflow: hidden;
  transition: border-color var(--t-fast) ease;
}
.scene:hover .scene__frame,
.scene:focus .scene__frame { border-color: var(--border-2); }
.scene img {
  width: 100%;
  height: 100%;
  object-fit: cover;      /* 16:9 裁剪：截图的 UI 按比例缩小，裁掉的是最外侧不到 3% */
  object-position: top center;
  border: 0;
  border-radius: 0;
  transform: scale(1);
  transition: transform var(--t-enter) var(--ease-out);
}
/* 图片放大 1.5%，用入场那档 .6s + 同一条缓动曲线 —— 三块图共用同一个
   .scene / .scene__frame / img 结构，所以两张教室端和一张教师端的反馈天然是同一套系统。 */
.scene:hover img,
.scene:focus img { transform: scale(1.015); }
.scene figcaption { margin-top: var(--s4); display: flex; flex-direction: column; gap: var(--s1); }
.scene figcaption b { font-size: 15.5px; font-weight: 620; }
.scene figcaption span { font-size: var(--fs-small); line-height: 1.65; color: var(--text-2); }
/* 三块场景图**没有可点的动作**（点开也不是能放大的原图），所以不塞 <a href>：
   那会凭空多出 3 个 tab 停靠点，还会让屏幕阅读器把它们念成一串"链接"。
   改成 figure 自己可聚焦（tabindex="0"），焦点环画在裁切盒上 ——
   于是"键盘走到这里"和"鼠标扫过这里"看到的是同一个状态。 */
.scene:focus { outline: none; }
.scene:focus .scene__frame { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---------------------------------------------------------------- ④ 下载 */
.dl { padding: var(--s10) 0 var(--s11); }
.dl__card {
  max-width: 560px; margin: var(--s8) auto 0;
  padding: var(--s7) var(--s6) var(--s6);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  display: flex; flex-direction: column; align-items: center; gap: var(--s3);
}
.dl__meta { display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap; justify-content: center; }
.dl__ver { font-size: 21px; font-weight: 630; letter-spacing: -.01em; }
.dl__size { font-size: var(--fs-small); color: var(--text-3); font-variant-numeric: tabular-nums; }
/* → 下载区的 dlIn 定义在 ① Hero 之后（那里有完整理由），这里只用到它 */
.js .dl__ver { opacity: .55; }
.js .dl__card.is-ready .dl__ver { opacity: 1; animation: dlIn .3s var(--ease-out) both; }
/* 便携版按钮是**后出现**的（要先 HEAD 探测产物在不在），它一出现就会把
   系统要求那行往下推 ~58px；只让它自己淡入上浮，别让整张卡跟着抖。
   ⚠️ 这里必须写成 `animation: dlIn ...` 而不是 `animation-name: dlIn` ——
      只写 animation-name 会继承上面那条 .is-ready 的简写里的 delay，
      按钮会白白晚 0.3s 才出现（一开始就是这么写的，靠读计算样式才发现）。 */
.js .dl__card .btn[hidden] { display: none; }
.js .dl__card #dl-portable:not([hidden]) { animation: dlIn .3s var(--ease-out) both; }
.dl__note { margin: var(--s3) 0 0; font-size: var(--fs-small); color: var(--text-3); }
.dl__notes {
  width: 100%; margin: var(--s2) 0 0; padding-top: var(--s5);
  border-top: 1px solid var(--border);
  font-size: var(--fs-small); line-height: 1.7; color: var(--text-2);
  white-space: pre-line; text-align: left;
}
.dl__notes b { display: block; margin-bottom: var(--s2); color: var(--text); font-weight: 620; }

/* ---------------------------------------------------------------- ⑤ 教师端 */
.teacher__inner { text-align: center; }
.teacher .btn { margin-top: var(--s6); }
.teacher__hint { margin: var(--s5) 0 0; font-size: var(--fs-small); color: var(--text-2); }

/* ---------------------------------------------------------------- ⑥ 底部 */
.foot { padding: var(--s9) 0 var(--s6); background: #17171a; color: #b9b9b3; }
[data-theme="dark"] .foot { background: #060607; border-top: 1px solid var(--border); }
.foot a { color: #d8d8d2; transition: color var(--t-fast) ease; }
.foot a:hover { color: #fff; }
.foot__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s6); }
.foot__col h3 { margin: 0 0 var(--s4); font-size: var(--fs-small); font-weight: 600; color: #fff; }
.foot__col ul { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--s3); }
.foot__col li { font-size: var(--fs-small); color: #9c9c96; }
.foot__bar {
  margin-top: var(--s8); padding-top: var(--s5);
  border-top: 1px solid rgba(255, 255, 255, .1);
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--s3);
  font-size: 13.5px; color: #8b8b85;
}
.foot__muted { color: #8b8b85; }

/* ---------------------------------------------------------------- ⑦ 入场动画 */
/* 只动 opacity + transform（合成层），位移 16px（报告：8-16px，不干扰阅读）
   ⚠️ 初始隐藏只在 `.js` 下生效：JS 被拦/未加载时，内容**必须直接可读**，
      否则 .reveal 会永远停在 opacity:0（看不见）。`js` 类由 index.html 的内联脚本加。 */
.js .reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--t-enter) var(--ease-out), transform var(--t-enter) var(--ease-out);
}
.js .reveal.is-visible { opacity: 1; transform: none; }

/* 关掉动效的用户：内容**直接呈现**，不是变慢。
   这里不止把时长改 0，而是把整套入场/悬停/循环动画的**属性**全部复位：
   时长设 0 时，带 delay 的 keyframes 仍可能先停在 backwards 的 opacity:0 上闪一下，
   对"不要动"的用户来说那是最糟的结果。所以逐条写明终态。 */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .js .hero-eyebrow,
  .js .hero__title,
  .js .hero__sub,
  .js .hero__actions,
  .js .scrollhint { opacity: 1; }
  .js.hero-in .hero-eyebrow,
  .js.hero-in .hero__title,
  .js.hero-in .hero__sub,
  .js.hero-in .hero__actions,
  .js.hero-in .scrollhint { animation: none; }
  .scrollhint svg { animation: none; opacity: 1; }
  .card:hover,
  .card:focus-within,
  .card:hover .card__ico,
  .card:focus-within .card__ico { transform: none; }
  .scene:hover img,
  .scene:focus img { transform: none; }
  .btn--primary:active,
  .btn--ghost:active { transform: none; }
  .js .dl__ver { opacity: 1; }
  .js .dl__card.is-ready .dl__ver,
  .js .dl__card #dl-portable:not([hidden]),
  .js .dl__card #dl-version,
  .js .dl__card #dl-main,
  .js .dl__card #dl-note { animation: none; }
  /* 进度条不"动"，只在滚动时改变长度：长度本身是状态，不是装饰 */
  .progress { transition: none; }
  :root { --t-enter: .001s; }
}

/* =============================================================================
   响应式：报告要求四档 ≥1440 / 1024-1440 / 768-1024 / ≤768。
   三档都用 CDP 实测过 scrollWidth == innerWidth（无横向滚动）。
   ============================================================================= */
@media (max-width: 1440px) {
  :root { --pad-hero: 120px; --pad-sec: 108px; --pad-tight: 92px; }
}
@media (max-width: 1024px) {
  :root { --pad-hero: 96px; --pad-sec: 88px; --pad-tight: 76px; }
  .cards { grid-template-columns: repeat(2, 1fr); }
  .scenes { grid-template-columns: 1fr; max-width: 720px; margin-left: auto; margin-right: auto; }
  .stats__grid { grid-template-columns: repeat(2, 1fr); gap: var(--s6) var(--s5); }
}
@media (max-width: 768px) {
  :root { --pad-hero: 56px; --pad-sec: 64px; --pad-tight: 56px; --pad-x: 20px; }
  body { font-size: 16.5px; }
  .nav__links { gap: var(--s4); }
  .nav__links > a:not(.nav__cta) { display: none; }   /* 手机只留主 CTA */
  .hero__actions { margin-bottom: var(--s8); }
  .hero__actions .btn { width: 100%; }
  .cards, .scenes { margin-top: var(--s7); }
  .dl__card .btn { width: 100%; }
  .foot__grid { grid-template-columns: 1fr; gap: var(--s6); }
  .foot__bar { margin-top: var(--s6); }
}
