/* ============================================================================
   styles.css — 四场景闭环的界面样式
   对比度守住《开发指引》G9：正文 ≥4.5:1、大字 ≥3:1。
   ========================================================================== */
:root{
  --bg:#0b1116; --bg-2:#121b22; --line:#25353f;
  --ink:#eef3f6; --ink-2:#b9c7d0; --ink-3:#8497a3;
  --accent:#E8743B; --ok:#8FB98A; --warn:#E0A24E; --bad:#e2705e;
  --radius:12px;
  --font: system-ui,-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;
}
*{box-sizing:border-box}
/* 类选择器里的 display 会盖过 [hidden] 的 display:none —— 浮层会隐形地挡住点击，必须显式压住 */
[hidden]{display:none!important}
html,body{margin:0;height:100%}
body{background:var(--bg);color:var(--ink);font:15px/1.7 var(--font);-webkit-font-smoothing:antialiased}
button{font:inherit;cursor:pointer}
h1,h2,h3{line-height:1.35;margin:0 0 .4em}

/* ── N0 主界面 ─────────────────────────────────────────────────────────── */
/* 开场是全屏影像，不是页面里的一张卡片：地图与片头都铺满视口，
   工具条、声明、跳过按钮全部浮在画面之上，四周不留黑边。 */
.hub{position:relative;width:100vw;height:100vh;height:100dvh;overflow:hidden;background:#05090c}
/* ── 镜头一：委内瑞拉矢量地图 ──────────────────────────────────────────────
   几何来自 Natural Earth 真实经纬度，震点按 USGS 坐标落位。
   配色思路：海深、陆浅、受灾州点名才亮——信息层级靠明度拉开，不靠花色。 */
.hub-map{position:absolute;inset:0;transition:opacity .6s}
/* slice = 按短边铺满并裁掉溢出。取景时左右预留了海与邻国，窄窗裁掉一点也不伤主体 */
.hub-svg{width:100%;height:100%;display:block;opacity:0;transition:opacity .8s ease-out}
.hub-svg.is-in{opacity:1}
.map-neighbours path{fill:#171f24;stroke:#232f37;stroke-width:.8}
.map-country{fill:url(#landGrad)}
.map-country-line{fill:none;stroke:#7fa79b;stroke-width:1.6;opacity:.95}
.map-state{fill:transparent;stroke:#41585a;stroke-width:.5;transition:fill .5s ease-out}
/* 点到名字才亮：字幕 B 每念到一个州，这个州就浮起来 */
.map-state.is-hit{fill:rgba(232,116,59,.26);stroke:rgba(232,116,59,.55);stroke-width:.9}
.map-cities circle{fill:#e7eef2;stroke:#0b1116;stroke-width:1}
.map-cities text{fill:#dce8ef;font:600 13px var(--font);letter-spacing:.04em;
  paint-order:stroke;stroke:rgba(6,11,15,.85);stroke-width:3px;stroke-linejoin:round}
.map-city--r1 text{font-size:15px;fill:#fff}
.map-city--r3 circle{fill:#9fb2bd;r:2.5}
.map-city--r3 text{font-size:11px;fill:#a9bcc7}
.map-city-zh{font-size:11px!important;font-weight:400!important;fill:#9db1bd!important}
.map-sealabels text{fill:#547486;font:400 14px var(--font);letter-spacing:.26em;text-transform:uppercase;
  paint-order:stroke;stroke:rgba(6,11,15,.7);stroke-width:3px;stroke-linejoin:round}
.map-sea-zh{font-size:11px!important;letter-spacing:.2em!important;fill:#46626f!important}
/* 震点扩散环。r 参与动画，Safari 上 CSS 动 r 有兼容坑，故用 transform: scale 驱动 */
.epi-ring{fill:none;stroke:#E8743B;stroke-width:1.6;transform-box:fill-box;transform-origin:center;
  animation:epi 2.6s cubic-bezier(.2,.6,.4,1) infinite}
.epi-ring--2{animation-delay:1.3s}
@keyframes epi{0%{transform:scale(.5);opacity:.95}100%{transform:scale(7);opacity:0}}
.epi-dot{fill:#E8743B;stroke:#2b0f06;stroke-width:1}
.map-lead{fill:none;stroke:rgba(255,255,255,.55);stroke-width:1;stroke-dasharray:4 4;
  opacity:0;transition:opacity .45s ease-out .1s}
.map-lead.is-on{opacity:1}

/* 字幕 C：图上的白框数据卡，照教师参考图（白底 + 红色震级徽章） */
.map-cards{position:absolute;inset:0;pointer-events:none}
/* 卡片宽度必须封顶：不封顶的话中文一长就把卡撑到盖住震中 */
.qcard{position:absolute;background:#fbfbf9;color:#15202a;border-radius:6px;padding:7px 10px 8px;
  box-shadow:0 6px 20px rgba(0,0,0,.5);width:clamp(196px,23%,244px);
  opacity:0;transform:translateY(-6px) scale(.96);transform-origin:top center;
  transition:opacity .38s ease-out,transform .38s cubic-bezier(.2,.9,.3,1.2)}
.qcard.is-on{opacity:1;transform:none}
.qcard p{margin:0}
.qcard-when{font-size:11.5px;color:#4a5a66;letter-spacing:.01em;line-height:1.4}
.qcard-mag{display:flex;align-items:center;gap:7px;margin:4px 0 3px!important}
.qcard-mag b{background:#c8332a;color:#fff;font-size:15px;font-weight:800;letter-spacing:.02em;
  padding:1px 7px;border-radius:3px;line-height:1.35;white-space:nowrap}
.qcard-mag span{font-size:12.5px;font-weight:700;letter-spacing:.05em;color:#15202a}
.qcard-mag i{font-style:normal;font-weight:400;font-size:11px;color:#6d7c87;margin-left:5px;letter-spacing:0}
.qcard-detail{font-size:11px;color:#5a6a76;font-variant-numeric:tabular-nums;line-height:1.45}

/* 字幕 A/B：英文主 + 中文小字同屏（国际新闻英文报道实训，先读英文，中文兜理解） */
.hub-type{position:absolute;left:4%;right:4%;bottom:5%;font-size:17px;color:#f2f7fa}
.type-line{margin:0 0 10px;background:rgba(6,11,15,.72);backdrop-filter:blur(3px);
  border-left:3px solid var(--accent);border-radius:8px;padding:9px 13px;max-width:74ch;
  transition:opacity .6s,border-color .6s}
.type-line.is-past{opacity:.62;border-left-color:#44575f}
.type-en{margin:0!important;font-size:16.5px;line-height:1.5;letter-spacing:.005em;min-height:1.5em}
.type-zh{margin:3px 0 0!important;font-size:13px;line-height:1.6;color:#a9bcc7}
/* 英文模式：中文那半全部撤掉（字幕小字、地名中文、海域中文）。
   只藏不删——打字机可能正打到一半，切回中文要立刻是正确的半截状态（见 hub-map.js setLang） */
.hub-map.is-en .type-zh,
.hub-map.is-en .map-city-zh,
.hub-map.is-en .map-sea-zh,
.hub-map.is-en .qcard-mag i{display:none}   /* 数据卡本来就是英文图表，只有「前震/主震」两个中文词 */
.hub-map.is-faded{display:none}
/* 镜头 01→02 的推进：SVG 朝震点放大并淡出，原点由 hub-map.js 按震点坐标写进 --epi-x/y */
.hub-map.is-zoom .hub-svg{transform-origin:var(--epi-x,50%) var(--epi-y,20%);transform:scale(6);opacity:0;
  transition:transform 1.4s cubic-bezier(.5,0,.85,.35),opacity 1.4s ease-in .3s}
.hub-map.is-zoom .hub-type,.hub-map.is-zoom .map-cards{opacity:0;transition:opacity .5s}
.hub-frame{position:absolute;inset:0;background:#05090c center/cover no-repeat;overflow:hidden}
/* 片头影片层：双 video 交叉淡化（切点衔接 100–200ms，见指引 5.1.4）；结束后停在末帧当落幅 */
.hub-film{position:absolute;inset:0;z-index:1}
.hub-film video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;
  transition:opacity .45s linear,transform .4s ease-out}
.hub-film video.is-on{opacity:1}
/* 换镜时只让**旧镜**在上层淡出，新镜已经在底下满亮（app.js: crossfadeTo）。
   两层同时淡的话，各半透明的那一刻底下的黑会透上来，每个切点都要暗一下。 */
.hub-film video.is-out{z-index:3}
.hub-film video.is-instant{transition:none}
/* 落幅停顿的「活冻结帧」：末帧极慢推进，把 3 秒的停顿从「卡住」变回「停住」。
   镜头本身已经不动了，这 3.5% 的位移只够让眼睛知道画面还活着。 */
.hub-film video.is-hold{transform:scale(1.035);transition:transform var(--hold,3s) linear}
.hub-cap{position:absolute;left:4%;bottom:5%;max-width:76%;margin:0;font-size:17px;color:#f2f7fa;
  background:rgba(8,14,18,.62);padding:.5em .7em;border-radius:8px;text-shadow:0 2px 12px rgba(0,0,0,.9);
  opacity:0;transition:opacity .3s}
.hub-cap.is-on{opacity:1}
/* 片头字幕的中英同屏，规则与播放器字幕一致：中文模式 = 主 + 英文小字；英文模式 = 只留英文 */
.hub-cap-main{display:block}
.hub-cap-alt{display:block;margin-top:3px;font-size:13px;line-height:1.5;color:#a9bcc7}
.hub-unmute{position:absolute;right:14px;bottom:14px;background:rgba(8,13,17,.72);border:1px solid var(--line);
  color:var(--ink);border-radius:999px;padding:8px 14px;font-size:13px}
.hub-frame.is-frame .hub-entries{position:absolute;inset:0;transform:none;display:block;width:auto;z-index:2}
/* 字幕与入口一律加半透明底板（老师明确要求），保证文字与底板对比度 ≥4.5:1 */
.hub-frame.is-frame .entry{position:absolute;transform:translate(-50%,-50%);width:min(260px,32%);
  background:rgba(8,13,17,.72);backdrop-filter:blur(3px);border-color:rgba(255,255,255,.14)}
.hub-frame.is-frame .entry:hover{transform:translate(-50%,-50%) scale(1.03)}

/* ── 进场转场（2026-08-30 换素材后重做）───────────────────────────────────
   旧版的主体是四段 r2v 穿梭影片（.warp-film），已下线：那是上一版影像用「两端参考图」
   生成的，画风、分辨率、光线都与新播放包不是一套，落地那一刻明显跳 ——
   一段为了掩盖切换而做的转场，自己成了最扎眼的切换。

   现在只剩两拍：
     ① `.is-picking` 点下去的即时反馈 —— 其余入口退场、被点那个轻微放大、主色泛起。**不动镜头**。
     ② `.is-fading`  0.35s 交叉淡化 —— 落地时场景页从同一主色里浮出（.scene.is-arrive）。
   `.is-warp`（推进 2.9× + 模糊 + 主色炸开）连同影片一起退役了：它当年是影片没出片时的
   替代转场，现在没有影片要替代，留着只会让两套转场再打一次架。 */

.hub-frame.is-picking .entry{opacity:0;transform:translate(-50%,-50%) scale(.96);transition:.22s}
.hub-frame.is-picking .entry.is-picked{opacity:1;transform:translate(-50%,-50%) scale(1.06);
  border-color:var(--tone);transition:.22s}
.hub-frame.is-picking .hub-warp{opacity:.22;transition:opacity .22s ease-out}
.hub-frame.is-picking .hub-cap,.hub-frame.is-picking .hub-unmute{opacity:0;transition:opacity .2s}

/* 主色泛起层。--wx/--wy 已经不再设置（不再朝某个方向推进），退化成整屏中心的一层色 */
.hub-warp{position:absolute;inset:0;z-index:3;pointer-events:none;opacity:0;
  background:radial-gradient(circle at 50% 50%,var(--warp-tone,#fff) 0%,transparent 62%)}

/* 交叉淡化出场。整个画框（含影片层与入口）一起淡，落地由 .scene.is-arrive 接住 */
.hub-frame.is-fading{opacity:0;transition:opacity .35s linear}
.hub-frame.is-fading .hub-warp{opacity:.34;transition:opacity .35s ease-out}
@media (prefers-reduced-motion:reduce){ .hub-frame.is-fading{transition:opacity .18s linear} }

/* 抵达：场景页从该场景主色里浮出来，接住上一段的冲势 */
.scene.is-arrive::after{content:'';position:fixed;inset:0;z-index:60;pointer-events:none;
  background:var(--arrive-tone,#000);animation:arrive .75s ease-out forwards}
@keyframes arrive{from{opacity:.92}to{opacity:0}}
@media (prefers-reduced-motion:reduce){
  .hub-frame.is-warp .hub-film,.hub-frame.is-warp .hub-warp,.hub-frame.is-warp .entry{transition-duration:.15s;transform:none;filter:none}
  .scene.is-arrive::after{animation-duration:.2s}
}
/* 影像都没就绪时的兜底：卡片栅格，居中铺在视口里（完整可用，不是残缺版） */
.hub-entries{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:2;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:14px;width:min(1000px,94vw)}
.entry{display:flex;flex-direction:column;gap:6px;align-items:flex-start;padding:18px 20px;border-radius:var(--radius);
  background:linear-gradient(180deg,rgba(255,255,255,.05),rgba(255,255,255,.02));
  border:1px solid var(--line);border-left:4px solid var(--tone,#666);color:var(--ink);text-align:left;transition:.18s}
.entry:hover{transform:translateY(-2px);border-color:var(--tone)}
/* 主标题 / 小字。按**主次**命名而不是按语言：中文模式下中文是主、英文是小字，
   英文模式下只剩主标题 —— 用 entry-en/entry-zh 命名的话，切一次语言类名就名不副实了 */
.entry-main{font-weight:700;letter-spacing:.02em}
.entry-alt{color:var(--ink-2);font-size:14px}
.entry-state{font-size:12px;color:var(--ink-3)}
.entry--done .entry-state{color:var(--ok)}
.entry--doing .entry-state{color:var(--warn)}
/* 工具条与声明浮在画面上，不再占版面高度 */
.hub-tools{position:absolute;left:50%;bottom:44px;transform:translateX(-50%);z-index:4;
  display:flex;gap:10px;flex-wrap:wrap;justify-content:center}
.tool{padding:9px 16px;border-radius:999px;background:rgba(8,13,17,.72);backdrop-filter:blur(4px);
  border:1px solid rgba(255,255,255,.16);color:var(--ink-2)}
.tool:hover:not(:disabled){color:var(--ink);border-color:#7d95a3}
.tool:disabled{opacity:.42;cursor:not-allowed}
.hub-notice{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);z-index:4;
  font-size:12px;color:var(--ink-3);margin:0;text-shadow:0 1px 6px rgba(0,0,0,.9)}
/* 右上角控件条：flex 排列，某个按钮 hidden 了其余的自动收拢，不留空洞 */
.hub-topbar{position:absolute;right:18px;top:18px;z-index:5;display:flex;align-items:center;gap:8px}
.hub-skip{background:rgba(8,13,17,.6);backdrop-filter:blur(4px);
  border:1px solid rgba(255,255,255,.18);color:var(--ink-2);border-radius:999px;padding:6px 12px;font-size:12px}
.hub-skip:hover{color:var(--ink)}
.hub-sound{background:rgba(232,116,59,.12);border-color:rgba(232,116,59,.5);color:#f0b195}
.hub-sound:hover{background:rgba(232,116,59,.2);color:#fff}
/* 背景声开关：正圆小喇叭，关掉后压暗——一眼能看出现在是静的。
   场景里的字幕开关与它配成一对（都是「关掉一路信息」），用同一副尺寸与同一种关掉态。 */
.hub-mute,.scene-cc{width:30px;height:30px;padding:0;font-size:14px;line-height:1;
  display:inline-flex;align-items:center;justify-content:center}
.hub-mute.is-off,.scene-cc.is-off{color:var(--ink-3);border-color:rgba(255,255,255,.1);background:rgba(8,13,17,.42)}
.hub-mute.is-off:hover,.scene-cc.is-off:hover{color:var(--ink-2)}
/* 关掉时在图标上划一道斜杠：只靠压暗的话，投影仪那种低对比屏上分不出开还是关 */
.scene-cc{position:relative}
.scene-cc.is-off::after{content:'';position:absolute;left:5px;right:5px;top:50%;height:1.5px;
  background:currentColor;transform:rotate(-32deg);border-radius:1px}
/* 界面语言开关：当前语言那一半点亮。主界面与场景顶部工具条共用这一个组件与同一个状态 */
.hub-lang{font-size:11.5px;letter-spacing:.02em;padding:6px 10px}
.hub-lang b{font-weight:700;color:var(--ink)}
.hub-lang i{font-style:normal;opacity:.55}

/* ── 场景页 ──────────────────────────────────────────────────────────────
   影像铺满视口，返回键 / 标题 / 计分 / 控制条**一律浮在画面上**，与 N0 主界面同一套语言
   （2026-08-20 改）。原来是「上边框分隔条 + 16px 内缩 + 圆角描边舞台」，等于给画面套了一圈黑框：
   画面被挤成一条，还和主界面完全不像。
   浮层一律加半透明底板 + blur（老师明确要求，保证文字与底板对比度 ≥4.5:1），
   这和入口卡片、字幕用的是同一条规矩。 */
.scene{position:relative;width:100vw;height:100vh;height:100dvh;overflow:hidden;background:#05090c}
/* 头部整条**不吃点击**，只有三个浮块自己吃：中间那大片透明区域下面是停点层，
   拦住了学生就点不到人物标记 */
/* 内距与主界面右上角那条对齐（.hub-topbar 是 right/top 18px），
   两个界面切换时工具条不会左右跳一下 */
.scene-head{position:absolute;left:0;right:0;top:0;z-index:6;display:flex;align-items:center;gap:12px;
  padding:18px;pointer-events:none}
.scene-head > *{pointer-events:auto}
/* 头部这几块与主界面的 .hub-skip 用同一副尺寸（padding 6px / 12px 字号 / 1px 描边），
   这样整条的高度一致，右上角工具条在两个界面里落在同一个像素上，切换时不会跳。 */
.scene-head h1{font-size:13px;font-weight:600;margin:0 auto 0 0;padding:6px 12px;border-radius:999px;
  background:rgba(8,13,17,.72);backdrop-filter:blur(4px);border:1px solid rgba(255,255,255,.12)}
.scene-back{background:rgba(8,13,17,.72);backdrop-filter:blur(4px);border:1px solid rgba(255,255,255,.18);
  color:var(--ink-2);border-radius:999px;padding:6px 12px;font-size:12px}
.scene-back:hover{color:var(--ink)}
.scene-score{font-size:12px;color:var(--ink-2);padding:6px 12px;border-radius:999px;
  background:rgba(8,13,17,.72);backdrop-filter:blur(4px);border:1px solid rgba(255,255,255,.12)}
/* 场景工具条：拍照 / 中英 / 声音。**和主界面右上角那条是同一个角、同一套组件** ——
   不另起一套样式，直接复用 .hub-skip / .hub-lang / .hub-mute，
   否则两个界面的同一个开关迟早长得不一样。
   这里不用绝对定位：.scene-head 本来就是一条 flex，挂在它末端即可，
   计分块用 margin-left:auto 顶开（h1 的 margin-right:auto 负责把左边推开）。 */
.scene-tools{display:flex;align-items:center;gap:8px}
/* 拍照：相机图标 + 文字。只放一个图标是不够的 —— 这是全条里唯一一个「产生副作用」的按钮
   （抓一帧存进素材篮），学生得先看懂它才会用，而 B1 的视觉报道全靠这些截图。 */
.scene-shot{display:inline-flex;align-items:center;gap:6px}
.scene-shot .ico{flex:0 0 auto;display:block}
.scene-shot .ico-ok,.scene-shot.is-done .ico-cam{display:none}
.scene-shot.is-done .ico-ok{display:block}
.scene-shot.is-done{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 55%,transparent)}
.player{position:absolute;inset:0;padding:0}

.sp-host{display:block}
.sp-stage{position:absolute;inset:0;min-height:0;border:0;border-radius:0;overflow:hidden;background:#05090c}
.sp-video,.sp-still,.sp-placeholder,.sp-freeze{position:absolute;inset:0;width:100%;height:100%}
.sp-video{object-fit:cover;background:#000}
.sp-still,.sp-freeze{background-size:cover;background-position:center}
.sp-freeze{display:none;z-index:2}
.sp-kenburns{animation:kb var(--dur,8s) linear both}
@keyframes kb{from{transform:scale(1.02)}to{transform:scale(1.10)}}
.sp-placeholder{display:flex;align-items:center;justify-content:center;
  background:radial-gradient(120% 90% at 30% 20%,color-mix(in srgb,var(--tone,#446) 42%,#0b1116),#0b1116)}
.sp-ph-inner{max-width:60ch;text-align:center;padding:24px}
.sp-ph-scene{font-size:13px;letter-spacing:.16em;color:var(--ink-3);text-transform:uppercase}
.sp-ph-motion{font-size:20px;margin:.5em 0;color:var(--ink)}
.sp-ph-note{font-size:12px;color:var(--ink-3)}
.sp-layer{position:absolute;inset:0;z-index:3;pointer-events:none}
.sp-layer.sl-on{pointer-events:auto}
/* bottom 要躲开浮在底部的控制条（实测 90px 高，见 .sp-bar），否则字幕会压在进度条上。
   2026-08-31 从 84 抬到 106：控制条为了给最底部那行合规声明让位，自己长高了 22px。 */
.sp-subtitle{position:absolute;left:50%;bottom:106px;transform:translateX(-50%);z-index:4;max-width:86%;text-align:center;
  background:rgba(6,10,13,.72);padding:8px 14px;border-radius:8px;font-size:16px;color:#f4f8fa}
.sp-sub-alt{display:block;font-size:13px;color:var(--ink-2);margin-top:2px}
.sp-sub-who{display:block;font-size:12px;letter-spacing:.06em;color:var(--warn);margin-bottom:4px}
.sp-subtitle:has(.sp-sub-who){max-width:72%;text-align:left;font-size:15px;line-height:1.75}
/* ── 底部坞：控制条 + 合规声明 ─────────────────────────────────────────
   **控制条默认收起，鼠标移到画面底部才浮现，移开自然淡出。**
   这门课要的是「现场感」，一条常驻的进度条会一直提醒学生「你在看一段素材」。

   **声明不跟着消失** —— 它是合规要求（验收 11.7「AI 生成声明常驻」），
   收起时画面底部就只剩这一行安静的小字。它落在进度条正下方、与进度条左端对齐，
   而不是居中飘在最底下：那样看着像一条没人管的孤立字幕。

   暗角也跟着分两档：收起时只留一点点（够垫住那行小字），浮现时才加深到能压住进度条。 */
.sp-dock{position:absolute;left:0;right:0;bottom:0;z-index:5;
  padding:16px 18px calc(14px + env(safe-area-inset-bottom,0px));   /* 14px = .hub-notice 的底距 */
  background:linear-gradient(to top,rgba(4,8,11,.42),rgba(4,8,11,.14) 58%,rgba(4,8,11,0));
  transition:background .28s ease}
.sp-dock.is-on{background:linear-gradient(to top,rgba(4,8,11,.84),rgba(4,8,11,.42) 62%,rgba(4,8,11,0))}
/* 收起时用 opacity 而不是 display:none —— 高度得留着，否则那行小字会跟着上下跳 */
.sp-bar{display:flex;align-items:center;gap:12px;
  opacity:0;transform:translateY(6px);pointer-events:none;
  transition:opacity .26s ease,transform .26s ease}
.sp-dock.is-on .sp-bar,.sp-dock:focus-within .sp-bar{opacity:1;transform:none;pointer-events:auto}
@media (prefers-reduced-motion:reduce){
  .sp-dock,.sp-bar{transition:none}
  .sp-bar{transform:none}
}
/* 底部居中，与主界面的 .hub-notice 一致（同字号、同色、同投影、不加底板）。
   试过跟进度条左端对齐，看着像给进度条加了个说明；居中才读得出「这是整页的一句声明」。 */
.sp-notice{margin:9px 0 0;text-align:center;font-size:12px;color:var(--ink-3);
  text-shadow:0 1px 6px rgba(0,0,0,.9)}
.sp-btn{background:rgba(8,13,17,.72);backdrop-filter:blur(4px);border:1px solid rgba(255,255,255,.18);
  color:var(--ink-2);border-radius:999px;width:auto;min-width:44px;height:36px;padding:0 12px}
.sp-btn:hover{color:var(--ink);border-color:#7d95a3}
.sp-track{position:relative;flex:1;height:8px;border-radius:99px;background:rgba(255,255,255,.24);cursor:pointer}
.sp-fill{height:100%;border-radius:99px;background:var(--accent);width:0}
.sp-marks{position:absolute;inset:0}
.sp-mark{position:absolute;top:-3px;width:3px;height:14px;background:var(--warn);border-radius:2px}
.sp-time{font-variant-numeric:tabular-nums;color:var(--ink-2);font-size:13px;min-width:44px;
  text-shadow:0 1px 6px rgba(0,0,0,.9)}

/* ── 停点层 ────────────────────────────────────────────────────────────── */
.sl-spot{position:absolute;transform:translate(-50%,-50%);min-width:52px;min-height:52px;border-radius:999px;
  display:flex;flex-direction:column;align-items:center;gap:4px;background:none;border:none;color:#fff}
.sl-spot svg{width:44px;height:44px;padding:10px;border-radius:999px;background:rgba(232,116,59,.92);
  box-shadow:0 0 0 0 rgba(232,116,59,.65);animation:pulse 2.2s infinite}
@keyframes pulse{70%{box-shadow:0 0 0 18px rgba(232,116,59,0)}100%{box-shadow:0 0 0 0 rgba(232,116,59,0)}}
.sl-spot:focus-visible svg{outline:3px solid #fff;outline-offset:3px}
.sl-spot-name{font-size:12px;background:rgba(6,10,13,.78);padding:2px 8px;border-radius:99px;white-space:nowrap}
/* 彩蛋标记：弱化样式，且只有它自己可点，不拦住播放层的其他事件 */
.sp-layer.sl-on--pass{pointer-events:none}
.sp-layer.sl-on--pass .sl-spot{pointer-events:auto}
/* 发布会：三位发言人各一个标记，选中的高亮——学生点谁就是在问谁 */
.sl-spot--speaker svg{width:38px;height:38px;padding:9px;background:rgba(78,127,168,.9)}
.sl-spot--speaker.is-on svg{background:var(--accent);box-shadow:0 0 0 3px rgba(255,255,255,.85)}
.sl-spot--speaker .sl-spot-name{display:flex;flex-direction:column;align-items:center;line-height:1.35}
.sl-spot--speaker .sl-spot-name i{font-style:normal;font-size:10px;opacity:.75}
.sl-spot--weak svg{width:34px;height:34px;padding:8px;background:rgba(143,185,138,.55);animation-duration:3.4s}
.sl-spot--weak .sl-spot-name{opacity:.75;font-size:11px}
.sl-card{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:min(520px,90%);z-index:5;
  background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);padding:18px;box-shadow:0 24px 60px rgba(0,0,0,.6)}
/* 人物立绘：从卡片左侧探出来。**2026-08-31 起没有调用方** ——
   人物卡的立绘已撤（见 stop-layer.js 的说明），立绘/口型归后面的 AI 对话互动引擎。
   样式留着不删：那个引擎多半还要一块同位置的画布，删了等于让它从头量一遍。 */
.sl-cutout{position:absolute;right:calc(100% - 34px);bottom:-6px;height:min(340px,42vh);width:auto;
  filter:drop-shadow(0 18px 28px rgba(0,0,0,.55));pointer-events:none}
/* 2026-08-30：立绘从绿幕抠像的静图换成该角色的 idle 近景视频 —— 人是活的，有呼吸和眨眼。
   视频不像抠像图那样带透明通道，所以自己做圆角与描边，不然会是一块硬边矩形。 */
.sl-cutout--live{height:min(300px,38vh);aspect-ratio:16/9;object-fit:cover;object-position:center 28%;
  border-radius:14px;border:1px solid rgba(255,255,255,.14);right:calc(100% - 18px);bottom:8px}
@media(max-width:900px){.sl-cutout{display:none}}
.sl-card-head{display:flex;gap:14px;align-items:flex-start}
.sl-card-head h3{margin:0;font-size:18px}
.sl-role{margin:2px 0 0;color:var(--ink-3);font-size:13px}
.sl-thumb{width:64px;height:64px;border-radius:10px;background:#223039 center/cover}
.sl-x{margin-left:auto;background:none;border:none;color:var(--ink-3);font-size:22px;line-height:1}
.sl-brief{color:var(--ink-2);font-size:14px}
.sl-warn{color:var(--warn);font-size:13px;border-left:3px solid var(--warn);padding-left:10px}
.sl-card-actions{display:flex;gap:10px;justify-content:flex-end}
.sl-card-actions button,.sl-dialog-actions button{background:var(--accent);border:none;color:#120803;font-weight:700;padding:9px 16px;border-radius:8px}
.sl-dialog-actions .sl-secondary,.sl-card-actions .sl-secondary{background:var(--bg);color:var(--ink-2);border:1px solid var(--line);font-weight:400}
/* 「不采访」放在「开始采访」左边：主次分明，但两个都是正经出口，不能做成不可见 */
.sl-card-actions{justify-content:space-between}
.sl-card-actions .sl-secondary:hover{color:var(--ink);border-color:#7d95a3}
/* 同上，控制条现在浮在画面底部，停点这两层要相应抬高 */
.sl-bar{position:absolute;left:50%;bottom:106px;transform:translateX(-50%);display:flex;gap:10px;z-index:4}
.sl-bar button{padding:10px 16px;border-radius:999px;border:1px solid var(--line);background:rgba(10,16,20,.86);color:var(--ink)}
.sl-hint{color:var(--ink-3)!important;font-size:13px}
.sl-hintbox,.sl-note{position:absolute;left:50%;bottom:162px;transform:translateX(-50%);z-index:5;max-width:min(620px,88%);
  background:rgba(10,16,20,.92);border:1px solid var(--line);border-left:3px solid var(--warn);padding:12px 16px;border-radius:10px;color:var(--ink-2);font-size:14px}
.sl-note{border-left-color:var(--ok)}
.sl-dialog{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:min(560px,92%);z-index:6;
  background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);padding:18px;box-shadow:0 24px 60px rgba(0,0,0,.6)}
.sl-dialog-head{font-weight:700;margin-bottom:10px}
.sl-dialog-body{max-height:40vh;overflow:auto;margin-bottom:12px}
.sl-line{background:#182229;padding:10px 12px;border-radius:10px;margin:0 0 8px}
.sl-line--reply{background:#1d2a24}
.sl-dialog-actions{display:flex;gap:10px;justify-content:flex-end}
.sl-live{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}

/* ── 固定拒绝（停点 A）─────────────────────────────────────────────────
   胡安抬头对着镜头说「现在不行」。这不是对话框而是一段戏，所以铺满画面居中放，
   字幕压在下方 —— **短片保留原声**，字幕只是给听不清的学生兜底。
   按钮等短片播完才出现：让学生先把话听完，再决定还问不问。 */
.sl-refuse{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;
  align-items:center;justify-content:center;background:rgba(4,8,11,.55);backdrop-filter:blur(2px)}
.sl-refuse-video{width:min(880px,86%);aspect-ratio:16/9;object-fit:cover;border-radius:12px;
  border:1px solid rgba(255,255,255,.12);box-shadow:0 28px 70px rgba(0,0,0,.66);background:#0b1116}
.sl-refuse-cap{width:min(880px,86%);margin:14px 0 0;padding:12px 16px;border-radius:10px;
  background:rgba(10,16,20,.92);border:1px solid var(--line);border-left:3px solid var(--warn)}
.sl-refuse-who{display:block;color:var(--ink-3);font-size:12px;letter-spacing:.04em;margin-bottom:4px}
.sl-refuse-main{display:block;color:var(--ink);font-size:16px;line-height:1.5}
.sl-refuse-alt{display:block;color:var(--ink-3);font-size:13px;line-height:1.45;margin-top:4px}
.sl-refuse-actions{display:flex;gap:10px;margin-top:14px;min-height:40px}
.sl-refuse-actions button{background:var(--accent);border:none;color:#120803;font-weight:700;
  padding:9px 16px;border-radius:8px}
.sl-refuse-actions .sl-secondary{background:var(--bg);color:var(--ink-2);border:1px solid var(--line);font-weight:400}

/* ── 浮层：成绩卡 / 采访本 / 报告 / 作品包 ───────────────────────────── */
/* z-index 140：**必须压过采访面板（100）与沉浸式外壳（120）**。
   原来是 60 —— 成绩卡永远在这两层底下，于是学生守在「批阅中」等到结果时它弹了也看不见，
   只有把面板关掉之后才露出来。表现就是「成绩卡总在不该出现的地方冒出来」（2026-09-01）。
   上限是配置告警的 200，别越过它。 */
.modal{position:fixed;inset:0;background:rgba(4,7,10,.72);display:flex;align-items:center;justify-content:center;z-index:140;padding:24px}
.modal-box{position:relative;width:min(880px,96vw);max-height:88vh;overflow:auto;background:var(--bg-2);
  border:1px solid var(--line);border-radius:16px;padding:26px;
  box-shadow:0 24px 64px rgba(0,0,0,.45)}
/* 内容自己管滚动的浮层（采访本）：外壳不滚，头部的概览与底部的导出按钮才能常驻。
   padding 交给内部各区自己给，否则 sticky 的头尾会露出外壳的内边距。 */
.modal-box--flush{overflow:hidden;padding:0;display:flex;flex-direction:column}
.modal-x{position:absolute;right:14px;top:12px;z-index:2;width:34px;height:34px;border-radius:8px;
  background:none;border:none;color:var(--ink-3);font-size:24px;line-height:1;
  display:flex;align-items:center;justify-content:center;transition:color .15s,background .15s}
.modal-x:hover{color:var(--ink);background:rgba(255,255,255,.07)}
/* 滚动条：默认那条亮灰在深色底上非常刺眼，压成和分隔线同一档 */
.modal-box *{scrollbar-width:thin;scrollbar-color:#2f434d transparent}
.modal-box ::-webkit-scrollbar{width:10px;height:10px}
.modal-box ::-webkit-scrollbar-thumb{background:#2f434d;border:3px solid var(--bg-2);border-radius:99px}
.modal-box ::-webkit-scrollbar-thumb:hover{background:#3d5764}
.modal-box ::-webkit-scrollbar-track{background:transparent}
/* 键盘用户要看得见焦点在哪 —— 浮层里全是可点的东西，没有焦点环就没法用键盘走 */
.modal-box :focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:6px}
/* 触屏上把小按钮撑到 44px 的可点范围（鼠标端保持紧凑，不必为触屏牺牲桌面排版）。
   这门课在平板上也会用，关闭键点不中是最恼人的那种问题。 */
@media(pointer:coarse){
  .modal-x{width:44px;height:44px}
  .nb-tab{min-height:44px}
  .nb-dl,.nb-card-h{min-height:44px}
}
@media(prefers-reduced-motion:reduce){
  .modal-box *,.modal-box *::before,.modal-box *::after{transition-duration:.01ms!important;animation-duration:.01ms!important}
}
.sc-head{display:flex;gap:14px;align-items:center}
.sc-thumb{width:64px;height:64px;border-radius:10px;background:#223039 center/cover}
.sc-sub{margin:2px 0 0;color:var(--ink-3);font-size:13px}
.sc-score{margin-left:auto;font-size:15px;color:var(--ink-3)}
.sc-score b{font-size:34px;color:var(--accent);margin-right:2px}
.sc-bar{height:8px;border-radius:99px;background:#1b262d;margin:14px 0}
.sc-bar i{display:block;height:100%;border-radius:99px;background:var(--accent)}
/* 雷达列 300px：viewBox 为了容下两侧标签比正方形宽了不少（见 ui/radar.js），
   列宽不给够的话整张图会被 width:100% 压小，四个维度的得分就看不清了 */
.sc-body{display:grid;grid-template-columns:300px 1fr;gap:20px;align-items:start}
/* 没有雷达图时评语独占整宽。不加这条的话评语会掉进 260px 那列被挤扁 */
.sc-body--solo{grid-template-columns:1fr}
@media(max-width:760px){.sc-body{grid-template-columns:1fr}}
.sc-comment{font-size:14px;color:var(--ink-2)}
.sc-comment h3{color:var(--ink);font-size:15px}
.sc-table{width:100%;border-collapse:collapse;margin:14px 0;font-size:14px}
.sc-table th,.sc-table td{border-bottom:1px solid var(--line);padding:8px 6px;text-align:left}
.sc-table .num{font-variant-numeric:tabular-nums}
.sc-tip{color:var(--ink-3);font-size:13px}
.sc-actions,.rp-actions,.nb-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:16px}
.sc-actions button,.rp-actions button,.nb-actions button{background:var(--accent);border:none;color:#120803;font-weight:700;padding:10px 18px;border-radius:8px}
.rp-actions .rp-download,.nb-actions button{background:var(--bg);color:var(--ink);border:1px solid var(--line);font-weight:400}

/* ── 采访本 / 素材篮 ────────────────────────────────────────────────────────
   布局的核心判断：**这是一份素材清单，不是一篇文章**。学生打开它是来找东西的
   （我采了谁、分数多少、哪条数字能用），所以头部的概览与标签页要常驻、
   中间才滚动，导出按钮永远够得着。
   旧版把 8 个受访者一律铺成等宽等重的长区块，未采访的也占满一屏说「暂无对话记录」，
   结果是一屏之内零信息、导出按钮被推到屏幕外。现在按「有内容 / 没内容」分权重排。 */
.nb{display:flex;flex-direction:column;min-height:0;max-height:inherit}
.nb-head{padding:22px 26px 0;border-bottom:1px solid var(--line);background:var(--bg-2)}
.nb-title{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 16px;padding-right:34px}
.nb-title h2{margin:0}
/* 概览条：一行说完「我现在有多少素材」。数字用等宽字形，切标签页时不会左右跳动 */
.nb-sum{display:flex;flex-wrap:wrap;gap:4px 16px;margin:0;color:var(--ink-3);font-size:13px}
.nb-sum b{color:var(--ink);font-variant-numeric:tabular-nums;font-size:15px}
.nb-tabs{display:flex;gap:8px;margin:14px 0 0}
.nb-tab{display:flex;align-items:center;gap:7px;padding:9px 14px;border:none;border-bottom:2px solid transparent;
  background:none;color:var(--ink-3);border-radius:8px 8px 0 0;transition:color .18s,background .18s}
.nb-tab:hover{color:var(--ink-2);background:rgba(255,255,255,.04)}
.nb-tab.is-on{color:var(--ink);border-bottom-color:var(--accent)}
/* 计数徽章：不点进去也知道哪一栏有东西 */
.nb-n{min-width:20px;padding:0 6px;border-radius:99px;background:rgba(255,255,255,.08);
  color:var(--ink-2);font-size:12px;line-height:18px;text-align:center;font-variant-numeric:tabular-nums}
.nb-tab.is-on .nb-n{background:var(--accent);color:#180b04;font-weight:700}
/* 上下留白交给内容自己给，滚动容器只留左右内边距：
   事实卡的表头是 sticky top:0，而 sticky 的原点是**内边距盒的上沿** ——
   容器一旦有 padding-top，表头就会停在下方，数据行从它上面那道缝里穿过去。 */
.nb-body{flex:1;min-height:0;overflow:auto;padding:0 26px;overscroll-behavior:contain}
.nb-body>:first-child:not(.nb-blank){margin-top:18px}
.nb-body::after{content:"";display:block;height:18px}
.nb-actions{display:flex;align-items:center;gap:14px;justify-content:flex-end;margin:0;
  padding:14px 26px;border-top:1px solid var(--line);background:var(--bg-2)}
.nb-foot-tip{margin:0;margin-right:auto;color:var(--ink-3);font-size:12px}

/* 场景分组：学生是按场景走的，素材也按场景归堆才对得上他的记忆 */
.nb-group + .nb-group{margin-top:22px}
.nb-group-h{display:flex;align-items:center;gap:10px;margin:0 0 10px;font-size:13px;font-weight:600;
  letter-spacing:.04em;color:var(--ink-3)}
.nb-group-h::after{content:"";flex:1;height:1px;background:var(--line)}
.nb-group-n{order:1;color:var(--ink-2);font-variant-numeric:tabular-nums}

/* 已采访 = 可展开的卡片。默认收起，一行摘要就够判断「是不是我要找的那条」 */
.nb-card{background:var(--bg);border:1px solid var(--line);border-radius:var(--radius);margin-bottom:8px}
.nb-card[open]{border-color:#33474f}
.nb-card-h{display:flex;align-items:center;gap:12px;padding:10px 14px;cursor:pointer;list-style:none;border-radius:var(--radius)}
.nb-card-h::-webkit-details-marker{display:none}
.nb-card-h:hover{background:rgba(255,255,255,.03)}
.nb-face{width:44px;height:44px;border-radius:10px;object-fit:cover;background:#1b262d;flex:none}
.nb-face--none{display:block}
.nb-who{display:flex;flex-direction:column;min-width:0}
.nb-who b{font-size:15px}
.nb-who em{font-style:normal;font-size:12px;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nb-tally{display:flex;align-items:center;gap:10px;margin-left:auto;flex:none}
.nb-rounds{color:var(--ink-3);font-size:12px}
.nb-score{font-size:12px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.nb-score b{font-size:17px;margin-right:1px}
.nb-score--ok b{color:var(--ok)} .nb-score--warn b{color:var(--warn)} .nb-score--bad b{color:var(--bad)}
/* 展开箭头：形状变化本身就是状态提示，不只靠颜色 */
.nb-chev{width:8px;height:8px;flex:none;border-right:1.5px solid var(--ink-3);border-bottom:1.5px solid var(--ink-3);
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .2s ease-out}
.nb-card[open] .nb-chev{transform:rotate(-135deg) translate(-2px,-2px)}
.nb-card-b{padding:2px 14px 14px 70px}

/* 未采访 = 压成一行，降对比度排在组末。它只需要回答「还有谁没采」 */
.nb-todo{display:flex;flex-wrap:wrap;gap:6px 8px;margin:8px 0 0;padding:0;list-style:none}
.nb-todo li{display:flex;align-items:center;gap:7px;padding:5px 11px;border:1px dashed var(--line);
  border-radius:99px;color:var(--ink-3);font-size:13px}
.nb-dot{width:6px;height:6px;border-radius:50%;border:1px solid var(--ink-3);flex:none}
.nb-todo-tag{font-size:11px;opacity:.75}

.nb-lines{max-width:68ch}
.nb-lines p{margin:0 0 8px;font-size:14px;color:var(--ink-2)}
.nb-lines b{display:block;font-size:11px;font-weight:600;letter-spacing:.06em;color:var(--ink-3);margin-bottom:1px}
/* 记者自己的话左侧加一道竖线：翻长对话时一眼分得出问与答 */
.nb-lines .is-me{color:var(--ink);border-left:2px solid var(--accent);padding-left:10px;margin-left:-12px}
.nb-lines .is-me b{color:var(--accent)}

.nb-empty,.nb-note{color:var(--ink-3);font-size:13px}
.nb-tip{margin:0 0 16px;padding:12px 14px;border-radius:10px;background:rgba(232,116,59,.07);
  border:1px solid rgba(232,116,59,.22)}
.nb-tip p{margin:0;color:var(--ink-2);font-size:13px}

/* 空状态：一句说清现在没有什么，一句说清怎么才会有 */
.nb-blank{max-width:46ch;margin:52px auto;text-align:center;color:var(--ink-3)}
.nb-blank svg{width:40px;height:40px;color:var(--ink-3);opacity:.55;margin-bottom:12px}
.nb-blank h3{margin:0 0 6px;color:var(--ink-2);font-size:16px}
.nb-blank p{margin:0;font-size:13px;line-height:1.75}

/* 徽章。事实卡三态（nb-ok/nb-bad）随「事实卡」页签一起撤了（2026-09-01），
   这里只剩「选择了不提问」还在用 nb-warn */
.nb-badge{display:inline-flex;align-items:center;gap:6px;padding:3px 9px;border-radius:99px;font-size:12px;white-space:nowrap}
.nb-badge i{font-style:normal;font-weight:700;line-height:1}
.nb-warn{background:rgba(224,162,78,.18);color:#e9be7f}

/* 过程报告顶部的平台任务信息条（截止时间 / 次数 / 满分，全部来自平台，前端不写死） */
.rp-task{margin:-4px 0 14px;padding:9px 12px;border-radius:8px;font-size:12px;color:var(--ink-3);
  background:rgba(255,255,255,.04);border:1px solid var(--line)}
.rp-task b{color:var(--ink-2)}
.rp-overdue{color:#f0a091}

/* 离线缓存面板 */
.of-table{width:100%;border-collapse:collapse;font-size:13px}
.of-table td{border-bottom:1px solid var(--line);padding:11px 8px;vertical-align:middle}
.of-table td:first-child{width:42%}
.of-n{display:block;color:var(--ink-3);font-size:12px;margin-top:2px}
.of-barcell{width:auto}
.of-bar{height:7px;border-radius:99px;background:#1b262d;overflow:hidden}
.of-bar i{display:block;height:100%;border-radius:99px;background:var(--accent);transition:width .25s}
.of-pct{display:inline-block;margin-top:5px;font-size:12px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.of-btn{border:1px solid var(--line);background:transparent;color:var(--ink-2);border-radius:8px;
  padding:5px 12px;font-size:12px;cursor:pointer;white-space:nowrap}
.of-btn:hover:not(:disabled){border-color:var(--accent);color:var(--ink)}
.of-btn:disabled{opacity:.45;cursor:default}
.of-quota{margin:14px 0 0;color:var(--ink-3);font-size:12px}
.of-warn{color:#f0a091}

.nb-shots{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px}
.nb-shots figure{margin:0;background:var(--bg);border:1px solid var(--line);border-radius:10px;overflow:hidden}
/* 写死 16:9：图是异步解码的，不占位的话每张加载完都会把下面的内容顶一下 */
.nb-shots img{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover;background:#1b262d}
.nb-shots figcaption{font-size:12px;color:var(--ink-3);display:flex;align-items:center;gap:8px;
  justify-content:space-between;padding:8px 10px}
.nb-tc{font-variant-numeric:tabular-nums}
.nb-dl{background:var(--bg-2);border:1px solid var(--line);color:var(--ink-2);border-radius:6px;padding:4px 11px;font-size:12px;flex:none}
.nb-dl:hover{border-color:var(--accent);color:var(--ink)}

.nb-comment{margin-top:10px}
.nb-comment summary{color:var(--ink-3);font-size:12px;cursor:pointer;width:max-content}
.nb-comment summary:hover{color:var(--ink-2)}
.nb-comment pre{white-space:pre-wrap;font:13px/1.6 var(--font);color:var(--ink-2);margin:6px 0 0;
  padding:10px 12px;background:var(--bg-2);border-radius:8px;max-width:68ch}

@media(max-width:600px){
  .nb-head{padding:18px 16px 0}
  .nb-body,.nb-actions{padding-left:16px;padding-right:16px}
  .nb-card-b{padding-left:14px}
  .nb-tally{width:100%;margin-left:56px;order:1}
  .nb-card-h{flex-wrap:wrap}
}

.rp-tip{color:var(--ink-3);font-size:13px}
.rp-self{display:block;margin:14px 0;font-size:14px;color:var(--ink-2)}
.rp-self textarea,.dv-table input{width:100%;margin-top:6px;background:#0e161c;border:1px solid var(--line);border-radius:8px;color:var(--ink);padding:10px;font:14px/1.6 var(--font)}
.rp-preview{margin-top:10px}
.rp-preview summary{cursor:pointer;color:var(--ink-3);font-size:13px}
.rp-md{font-size:13px;color:var(--ink-2);max-height:46vh;overflow:auto;border:1px solid var(--line);border-radius:10px;padding:4px 16px 16px;margin-top:10px}
.rp-status{margin-top:12px;font-size:14px;color:var(--ok)}
.rp-comment{color:var(--ink-2);font-size:13px;margin-top:8px}
.dv-table{width:100%;border-collapse:collapse;font-size:13px;margin:12px 0}
.dv-table th,.dv-table td{border-bottom:1px solid var(--line);padding:8px 6px;text-align:left}
.dv-ddl{color:var(--ink-3);white-space:nowrap}
.dv-upload{display:flex;align-items:center;gap:12px;font-size:13px;color:var(--ink-3)}

/* ── Markdown 渲染物的统一外观 ──────────────────────────────────────────────
   同一份渲染器供五处使用：过程报告预览、作品包页、场景成绩卡、采访面板评语、
   沉浸式采访评语。样式挂在渲染器产出的类上（.md-table 等）而不是各自的容器类上，
   否则换一处用就得再抄一遍 CSS，迟早对不齐。 */
.md-table-wrap{overflow-x:auto;margin:10px 0;border:1px solid var(--line);border-radius:8px}
.md-table{width:100%;border-collapse:collapse;font-size:13px}
.md-table th,.md-table td{padding:8px 12px;text-align:left;border-bottom:1px solid var(--line);vertical-align:top}
.md-table th{background:rgba(255,255,255,.04);color:var(--ink);font-weight:600;font-size:12px;
  letter-spacing:.03em;white-space:nowrap}
.md-table tbody tr:last-child td{border-bottom:none}
.md-table tbody tr:nth-child(even){background:rgba(255,255,255,.018)}
/* 数字列用等宽字形：得分/满分/轮次上下对不齐时，一眼看不出哪个停点丢了分 */
.md-table td{font-variant-numeric:tabular-nums}

/* 报告与评语的正文排版。五个消费方一起选中：报告预览 / 报告内评语 / 成绩卡 /
   采访面板 / 沉浸式采访 —— 它们渲染的是同一种东西，排版就该长一样。 */
.rp-md h3,.rp-md h4,.rp-md h5,.rp-md h6,
.rp-comment h3,.rp-comment h4,.rp-comment h5,.rp-comment h6,
.sc-comment h4,.sc-comment h5,.sc-comment h6,
.qp-comment h3,.qp-comment h4,.qp-comment h5,.qp-comment h6,
.qi-comment h3,.qi-comment h4,.qi-comment h5,.qi-comment h6{color:var(--ink);margin:18px 0 6px}
.rp-md h3{font-size:16px;margin-top:6px}
.rp-md h4,.rp-comment h4,.sc-comment h4,.qp-comment h4,.qi-comment h4{font-size:14px}
.rp-md h5,.rp-comment h5,.sc-comment h5,.qp-comment h5,.qi-comment h5,
.rp-md h6,.rp-comment h6,.sc-comment h6,.qp-comment h6,.qi-comment h6{font-size:13px;color:var(--ink-2)}
/* 一级小节前的橙色竖条 —— 有它才扫得出结构。两处的「一级」不是同一个标题级别：
   · 报告自己写的是 `##`（渲染成 h4）；
   · AI 评语按 standard 的 rubric 写的是 `###`（渲染成 h5），
     而那四节正是雷达图的四根轴，最该被一眼扫到。
   所以按容器分别挂，别图省事合成一条选择器。 */
.rp-md h4::before,
.rp-comment h5::before,.sc-comment h5::before,
.qp-comment h5::before,.qi-comment h5::before{content:"";display:inline-block;width:3px;height:12px;
  margin-right:7px;vertical-align:-1px;background:var(--accent);border-radius:2px}
.rp-md p,.rp-comment p,.sc-comment p,.qp-comment p,.qi-comment p{margin:6px 0}
.rp-md ul,.rp-md ol,.rp-comment ul,.rp-comment ol,.sc-comment ul,.sc-comment ol,
.qp-comment ul,.qp-comment ol,.qi-comment ul,.qi-comment ol{margin:6px 0;padding-left:20px}
.rp-md li,.rp-comment li,.sc-comment li,.qp-comment li,.qi-comment li{margin:3px 0}
.rp-md hr,.rp-comment hr,.sc-comment hr,.qp-comment hr,.qi-comment hr{border:none;border-top:1px solid var(--line);margin:16px 0}
.rp-md blockquote,.rp-comment blockquote,.sc-comment blockquote,
.qp-comment blockquote,.qi-comment blockquote{margin:8px 0;padding:2px 0 2px 12px;
  border-left:2px solid var(--line);color:var(--ink-3)}
.rp-md code,.rp-comment code,.sc-comment code,.qp-comment code,.qi-comment code{
  background:rgba(255,255,255,.07);padding:1px 5px;border-radius:4px;font-size:12px}
.rp-md>:first-child,.rp-comment>:first-child,.sc-comment>:first-child,
.qp-comment>:first-child,.qi-comment>:first-child{margin-top:0}

/* ── 提示与报警 ────────────────────────────────────────────────────────── */
/* 跟着 .modal 一起抬（原来 90 在 modal 的 60 之上，把 modal 提到 140 后这里不抬就被盖住了） */
.toast{position:fixed;left:50%;bottom:28px;transform:translateX(-50%);z-index:150;max-width:min(560px,90vw);
  background:#1d2a33;border:1px solid var(--line);border-left:3px solid var(--warn);padding:12px 16px;border-radius:10px;
  color:var(--ink);font-size:14px;white-space:pre-wrap;box-shadow:0 16px 40px rgba(0,0,0,.5)}
.cfg-problems{position:fixed;left:12px;bottom:12px;z-index:200;max-width:min(90vw,420px);background:#3a1f1f;color:#ffb4a2;
  border:1px solid #7a3b30;border-radius:10px;padding:10px 12px;font-size:12px;line-height:1.6;cursor:pointer}

@media (prefers-reduced-motion: reduce){
  .sp-kenburns,.epi-ring,.sl-spot svg{animation:none}
}
