/* ============================================================================
   T54 第二波② · 视频叠加层（艺术字 / 贴纸 / 字幕）—— 两端共用的一份样式
   ----------------------------------------------------------------------------
   为什么单开一个文件（同 `bgm.css` / `loc.css`）：这套东西**两端长得一样、行为也一样**
   —— 沉浸流、两端详情页、发布页的剪辑预览都画同一批层。写成两份必然会慢慢分家，
   而「同一口径两个真身」是本项目明令禁止的（派总实报过：预览里在中间、发出去跑到边上）。
   ⚠️ 因此两端 base 都必须 <link> 它（`scripts/audit_css.py` 的 SHARED_CSS 认这一点）。

   两段：
     `.mov-*`  渲染出来的层（播放页 / 详情页 / 预览都读它）
     `.mve-*`  发布页那个剪辑器（加层、改字、调色、拖时间轴）

   层的字号与落点由 JS 按**画面高度**算成 px 写在行内（比例 → 像素只在一处换算），
   这里只负责「长什么样」：描边、阴影、居中锚点、层与层之间的叠序。
   ============================================================================ */

/* ---- 一、渲染出来的层 ---------------------------------------------------- */
.mov-stage {
  position: absolute;
  inset: 0;
  z-index: 2;                  /* 在画面（0/1）之上、在文字信息与按钮（3）之下 */
  overflow: hidden;            /* 用户把字拖出画面外时，不许溢出去压在按钮上 */
  pointer-events: none;        /* 播放页：层只是画，点它等于点画面（暂停） */
}
.mov-stage.is-editing { pointer-events: auto; }   /* 剪辑预览里这一层要能被拖动 */

/* 挂载点的宿主：`.mov-stage` 是 `inset:0` 的绝对定位层，所以它**爹必须是定位元素**。
   · 沉浸流 `.mv-stage`、发布页 `#pcnVStage` 本来就 `position:relative`（m.css 里已有）；
   · 网页版详情页 `.pcp-video` 原来只靠 margin 排版（没定位上下文），层的坐标会算到
     整个页面身上 —— 这一条把它对齐到 App 端已有的写法（同一口径只有一份，铁律 40②）。
   圆角跟着视频那块走，不然层是直角方块、画面是 14px 圆角，边缘会看见一层边框。 */
.pcp-video { position: relative; }
.pcp-video > .mov-stage { border-radius: 14px; }

.mov {
  position: absolute;
  /* 锚点是**字的中心**（x/y 就是中心比例），所以拖到哪都指哪个点，
     不会出现「拖右下角时字整个跳走」那种偏移。 */
  transform: translate(-50%, -50%);
  max-width: 92%;
  margin: 0;
  line-height: 1.18;
  font-weight: 800;
  letter-spacing: .01em;
  text-align: center;
  white-space: pre-wrap;       /* 服务端已把换行压成一行，这里只兜住中文不断词 */
  word-break: break-word;
  font-family: var(--font-sans, system-ui, -apple-system, "PingFang SC",
                 "Microsoft YaHei", sans-serif);
  user-select: none;
  -webkit-user-select: none;
}
.mov[hidden] { display: none; }

/* 艺术字：描边 + 双层阴影。压在任何画面上都读得清 —— 白字直接压在雪景/白墙上必瞎。 */
.mov-f-art {
  -webkit-text-stroke: .055em rgba(8, 10, 12, .62);
  paint-order: stroke fill;    /* 描边画在字背后，笔画不会被自己啃细 */
  text-shadow: 0 2px 10px rgba(0, 0, 0, .45), 0 1px 2px rgba(0, 0, 0, .55);
}
.mov-f-bold { font-weight: 900; text-shadow: 0 1px 6px rgba(0, 0, 0, .55); }
.mov-f-plain { font-weight: 600; text-shadow: 0 1px 4px rgba(0, 0, 0, .5); }

/* 字幕：默认贴在画面下方那一档，细一号、带一点底衬 —— 一句一句读的东西不要抢戏。 */
.mov-caption {
  padding: .12em .34em;
  border-radius: .2em;
  background: rgba(10, 12, 14, .34);
  -webkit-text-stroke: 0;
  text-shadow: none;
  font-weight: 700;
}

/* 贴纸：emoji 自己就是画，描边只会把它糊成一团（所以 JS 不给它上色）。 */
.mov-sticker {
  -webkit-text-stroke: 0;
  text-shadow: 0 2px 8px rgba(0, 0, 0, .3);
  line-height: 1;
  white-space: nowrap;
}

/* T55② 花字的三种底衬（表在 `settings.VIDEO_OVERLAY_DECOS`；「无底」没有 class）。
   只画底、不动字的内容与落点 —— 于是**预览、播放、导出**读的是同一份 CSS：
   `js/video-export.js` 录的是这些真元素的计算样式，不存在第二处实现（铁律 40②）。
   ⚠️ 气泡与标签**自带配色**（`own_ink: True`）：字色用 `!important` 钉死，
      行内样式压不过它 —— 这正是剪辑器遇到这两种底衬时把调色板收起来的原因
      （留一颗「点了颜色没变化」的钮比不给更坏，口径②）。
   padding 用 em：跟着字号走，字号调大底衬也长，不会出现「字撑出底色」那种对不上。 */
.mov-d-plate {
  padding: .18em .34em; border-radius: .16em;
  background: rgba(10, 12, 14, .42);
}
.mov-d-bubble {
  padding: .3em .52em; border-radius: .8em .8em .8em .2em;
  background: #fff; color: #111418 !important;
  -webkit-text-stroke: 0; text-shadow: none;
}
.mov-d-tag {
  padding: .16em .46em; border-radius: 999px;
  background: #111418; color: #fff !important;
  -webkit-text-stroke: 0; text-shadow: none;
}

/* ---- 二、发布页那一屏「剪辑台」（整屏，T55②） ------------------------------ */
/* ⚠️ 这一条是整套「收起/展开」的地基：浏览器默认的 `[hidden]{display:none}` 来自 UA 表，
   作者样式里任何一条 `display:flex/block` 都会**把它顶掉**（本项目吃过好几回暗亏）。
   剪辑台里 `.mve-swatches / .mve-emo / .mve-row-scale / .mve-emo-g` 全是 flex 或 contents，
   JS 收起来时只是挂 `hidden` 属性 —— 不加这一条就是「点了没收起」，而且页面不报任何错。 */
[data-mve-field] [hidden] { display: none !important; }

/* 发布页上只留一条门：进剪辑台。没选片时那颗钮是 disabled（不给一屏黑的死入口，口径①） */
.mve { margin-top: 10px; }
.mve-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 2px; }
.mve-open {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; border: 0; border-radius: var(--r-pill, 999px);
  background: var(--brand-soft, rgba(0, 189, 166, .12)); color: var(--brand-deep, #0a8f80);
  font-size: 13px; font-weight: 700;
}
.mve-open .ic { width: 16px; height: 16px; }
.mve-open[disabled] { opacity: .45; }
.mve-n {
  padding: 1px 7px; border-radius: var(--r-pill, 999px);
  background: var(--brand, #00bda6); color: #fff; font-size: 11px; font-weight: 800;
}

/* 整屏的三个零件：顶栏 + 画面（还是发布页那条 video，只是被 CSS 抬上来）+ 底栏。
   · 为什么**不搬** video 元素：它的 src 挂着 objectURL、`video-publish.js` 抓着它的引用
     截封面（T54 那回「预览 objectURL 被回收 → 导出卡死」就是动了它）。CSS 挪位置零风险。
   · 顶栏/底栏高各由 JS **量出来**写进 `--mve-top` / `--mve-bottom`（不写死数字：
     改 CSS 不用回来改 JS，两处各猜一个数必对不上，铁律 40②）。
   · `object-fit:contain` 是这一屏必须的：渲染器 `pictureRect()` 只认 contain 才留黑边、
     把层画在真画面里；发布页那一格没这条也能量（量不到就用整个元素），整屏必须钉死。 */
body.mve-live { overflow: hidden; background: #0b0d10; }
/* T59②（派总 2026-11-04 第 1 条）：App 端这一格换成与发图文同款的预览台 `.pcn-stage--v`，
   网页版还是 `.pcn-vstage` —— 两个选择器并列，剪辑台的整屏几何只有一份口径（铁律 40②）。 */
body.mve-live .pcn-vstage,
body.mve-live .pcn-stage--v {
  position: fixed; left: 0; right: 0; top: var(--mve-top, 44px);
  height: calc(100% - var(--mve-top, 44px) - var(--mve-bottom, 240px));
  max-width: none; margin: 0; border: 0; border-radius: 0; background: #000; z-index: 59;
}
body.mve-live .pcn-vstage video,
body.mve-live .pcn-stage--v video {
  display: block; width: 100%; height: 100%; max-height: none;
  object-fit: contain; background: #000;
}
/* 状态条（时长读数 / 用这一帧做封面 / 重选）在剪辑台里用不上：回发布页那一格还在。
   收起来而不是删掉 —— 剪辑台不改封面，留两颗点了没用的钮比不给更坏。
   T59② 之后这一排是台子的**兄弟**（`.pcn-emenu--v`），不再跟着台子一起被 fixed 抬走，
   所以要自己收；角上那颗读数同理（它现在住在台子里）。 */
body.mve-live .pcn-vstage .pcn-vbar,
body.mve-live .pcn-emenu--v,
body.mve-live .pcn-stage--v .pcn-stage-count { display: none; }

/* 网页版这一屏：站点导航条必须让位。
   `.topbar` 是 `position:sticky; z-index:60`（app.css:254），而剪辑台挂在
   `main`（`position:relative; z-index:1`）里 —— 祖先一旦造出层叠上下文，
    descendants 的 `z-index:60` 只在那一层里排序，出门就跟着祖先排到 1，
   于是台子自己那一排「退出 / 完成」（贴视口 y=0）正好被导航条压在下面：
   桌面闸门实测 `page.click('[data-mve-done]')` 30 秒超时，报
   `<header class="topbar">…</header> intercepts pointer events`（2026-11-04，
   探针 `_probe_z` 量到 main / .wrap 两级 z-index:1 各自成上下文）。
   剪辑台本来就是整屏模式：开台收导航、收台照旧回来（`mve-live` 一摘就恢复）。 */
body.mve-live .topbar { display: none; }

/* 同一个层叠陷阱的第二处：`.wrap{position:relative;z-index:1}` 不只裹着正文，
   页脚里那一层 `.wrap` 用的是同一条规则（app.css:168）—— 两个 z-index:1 的兄弟
   比的是**文档顺序**，页脚在 `<main>` 之后 ⇒ 页脚整块盖在剪辑台底栏上面。
   实测（2026-11-04 桌面闸门 WY7a 命中栈）：时间轴那一格 `mve-seg` 的正上方依次是
   `a` → `p.foot-docs` → `div.wrap`，点「第二层」30 秒点不动。
   开台期间把正文这一层抬到页脚之上（收起页脚也行，但那只是躲开这一处，
   抬高 main 是把「后面还有别的 z-index:1 兄弟」这一类一起解决）。 */
body.mve-live main { z-index: 70; }

.mve-sheet {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column; justify-content: space-between;
  pointer-events: none;                 /* 中间那块留给画面：只有顶栏/把手/底栏吃事件 */
  color: #eef1f4; font-family: var(--font-sans, system-ui, "PingFang SC", sans-serif);
}
.mve-top {
  pointer-events: auto; display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 8px 12px; padding-top: calc(8px + var(--safe-t, env(safe-area-inset-top, 0px)));
  background: #0b0d10;
}
.mve-title { font-size: 13.5px; font-weight: 800; letter-spacing: .06em; }
.mve-quit, .mve-finish {
  border: 0; background: none; color: #cfd6dd; font: inherit; font-size: 13px;
  font-weight: 700; padding: 6px 10px; border-radius: var(--r-sm, 8px);
}
.mve-finish { color: #0b0d10; background: var(--brand, #00bda6); padding: 6px 14px; }

/* 四颗把手：`.mve-handles` 由 JS 摆成**选中那一层的方框**（视口坐标），
   四颗子钮靠 CSS 贴在那框的四角 —— JS 只写 left/top/width/height 四个数，
   不在这里算「第几颗该挪几个像素」（两处算坐标必对不上）。 */
.mve-handles { position: absolute; pointer-events: none; }
.mve-hd {
  position: absolute; pointer-events: auto; width: 28px; height: 28px; padding: 0;
  display: grid; place-items: center; border: 0; border-radius: 50%;
  background: rgba(11, 13, 16, .74); color: #fff;
}
.mve-hd .ic { width: 14px; height: 14px; }
.mve-handles [data-mve-h-del]  { left: 0; top: 0; transform: translate(-42%, -42%); }
.mve-handles [data-mve-h-edit] { right: 0; top: 0; transform: translate(42%, -42%); }
.mve-handles [data-mve-h-copy] { left: 0; bottom: 0; transform: translate(-42%, 42%); }
.mve-handles [data-mve-h-home] { right: 0; bottom: 0; transform: translate(42%, 42%); }

/* 底栏：一句实话 + 当前那格面板 + 时间轴 + 工具条 */
.mve-dock {
  pointer-events: auto; background: #12151a;
  border-radius: 16px 16px 0 0; padding: 6px 10px calc(8px + var(--safe-b, env(safe-area-inset-bottom, 0px)));
}
.mve-dock button[disabled] { opacity: .38; }
.mve-note { margin: 2px 2px 0; font-size: 12px; line-height: 1.6; color: #97a2ae; }
.mve-note.is-bad { color: #ff8a8a; font-weight: 600; }

.mve-panels { display: none; }
body.mve-panel .mve-panels { display: block; }
/* 面板定高 + 内部滚：底栏高度只随「开没开一格」变，不随内容多少变 ——
   JS 量到几个像素，画面就让出几个像素，不会出现「字被底栏吃掉一半」。 */
.mve-pane { max-height: 34vh; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.mve-fl {
  display: block; margin: 8px 0 4px; font-size: 11.5px; font-weight: 700; color: #8b96a3;
}

.mve-input {
  width: 100%; box-sizing: border-box; padding: 9px 10px;
  border: 1px solid rgba(255, 255, 255, .18); border-radius: var(--r-sm, 8px);
  background: rgba(255, 255, 255, .07); color: #eef1f4; font-size: 14px;
}
.mve-add {
  display: flex; width: 100%; align-items: center; justify-content: center; gap: 5px;
  padding: 9px; margin-top: 8px; border: 1px dashed rgba(255, 255, 255, .24);
  border-radius: var(--r-sm, 8px); background: none;
  font-size: 12.5px; font-weight: 700; color: var(--brand, #00bda6);
}

/* 花字预设：每一颗**按自己的画法**渲染（模板把 class 与色都印上了），
   所以「按钮长什么样」= 「点上去画面变什么样」，不需要文案解释。 */
.mve-presets { display: flex; gap: 6px; overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: 2px; }
.mve-pre {
  flex: none; max-width: 46%; padding: 9px 11px; border: 1px solid rgba(255, 255, 255, .16);
  border-radius: var(--r-sm, 8px); background: rgba(255, 255, 255, .05);
  font-size: 12.5px; font-weight: 800; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.mve-pre.is-on { border-color: var(--brand, #00bda6); box-shadow: 0 0 0 2px rgba(0, 189, 166, .32); }
.mve-decos { display: flex; gap: 6px; flex-wrap: wrap; }
.mve-deco {
  padding: 6px 12px; border: 1px solid rgba(255, 255, 255, .16); border-radius: 999px;
  background: rgba(255, 255, 255, .05); color: #dfe5eb; font-size: 12px; font-weight: 700;
}
.mve-deco.is-on { border-color: var(--brand, #00bda6); color: var(--brand, #00bda6); }

.mve-swatches { display: flex; gap: 7px; flex-wrap: wrap; }
.mve-sw {
  width: 26px; height: 26px; padding: 0; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .26);
}
.mve-sw.is-on { border-color: var(--brand, #00bda6); box-shadow: 0 0 0 2px rgba(0, 189, 166, .34); }
/* 白色那颗在深色底上是**看得见**的，但给它一圈边才看得出那是个圆（不是漏了一块） */
.mve-sw.is-light { border-color: rgba(255, 255, 255, .6); }
.mve-fonts { display: flex; gap: 6px; }
.mve-font {
  flex: 1; padding: 7px 4px; border: 1px solid rgba(255, 255, 255, .16);
  border-radius: var(--r-sm, 8px); background: rgba(255, 255, 255, .05);
  font-size: 12.5px; font-weight: 700; color: #dfe5eb;
}
.mve-font.is-on { border-color: var(--brand, #00bda6); color: var(--brand, #00bda6); }
.mve-font-is-art { letter-spacing: .02em; }
.mve-row-scale { display: flex; align-items: center; gap: 8px; }
.mve-row-scale + .mve-row-scale { margin-top: 6px; }   /* 出现/消失两条滑条挨着时留一口气 */
.mve-range { flex: 1; accent-color: var(--brand, #00bda6); }
.mve-read {
  flex: none; min-width: 52px; text-align: right; font-size: 11.5px;
  color: #97a2ae; font-variant-numeric: tabular-nums;
}

/* 出场时间那三颗小钮（起于此处 / 止于此处 / 全程） */
.mve-markrow { display: flex; gap: 6px; }
.mve-mini {
  flex: 1; padding: 8px 4px; border: 1px solid rgba(255, 255, 255, .16);
  border-radius: var(--r-sm, 8px); background: rgba(255, 255, 255, .05);
  color: #dfe5eb; font-size: 12px; font-weight: 700;
}

/* 表情面板（贴纸）：只认评论那一份清单，分组胶囊切 `hidden` */
.mve-emocats { display: flex; gap: 6px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.mve-emocat {
  flex: none; padding: 5px 11px; border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 999px; background: rgba(255, 255, 255, .05);
  color: #dfe5eb; font-size: 12px; font-weight: 700;
}
.mve-emocat.is-on { background: var(--brand, #00bda6); border-color: transparent; color: #0b0d10; }
.mve-emo { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; }
/* 分组只是模板里为了「常用/表情/手势/生活」留着的一层结构，
   不参与排版（display:contents 让里面的钮直接进上面那条 flex），不然每组会各起一行。 */
.mve-emo-g { display: contents; }
.mve-em {
  width: 34px; height: 34px; padding: 0; border: 0; border-radius: var(--r-sm, 8px);
  background: rgba(255, 255, 255, .07); font-size: 19px; line-height: 1;
}
.mve-em:active { background: rgba(0, 189, 166, .22); }

.mve-hint { margin: 8px 0 0; font-size: 11.5px; line-height: 1.6; color: #8b96a3; }

/* 层那一格：画面上的字叠在一起时点不中，就来这里点 —— 与 `.mov` 是同一份数据 */
.mve-chips { display: flex; flex-wrap: wrap; gap: 6px; padding-top: 6px; }
.mve-chip {
  display: inline-flex; align-items: center; gap: 4px; padding: 4px 5px 4px 7px;
  border: 1px solid rgba(255, 255, 255, .16); border-radius: 999px;
  background: rgba(255, 255, 255, .05);
}
.mve-chip.is-on { border-color: var(--brand, #00bda6); box-shadow: 0 0 0 2px rgba(0, 189, 166, .26); }
.mve-chip-main {
  display: inline-flex; align-items: center; gap: 6px; max-width: 200px;
  border: 0; background: none; color: inherit; font: inherit; padding: 0;
}
.mve-kicker {
  flex: none; padding: 2px 7px; border-radius: 999px;
  background: rgba(0, 189, 166, .2); color: var(--brand, #00bda6);
  font-size: 10.5px; font-weight: 800;
}
.mve-text-prev {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12.5px; font-weight: 600; color: #eef1f4;
}
.mve-time {
  flex: none; font-size: 11px; color: #97a2ae; font-variant-numeric: tabular-nums;
}
.mve-chip-del {
  flex: none; width: 24px; height: 24px; display: grid; place-items: center;
  border: 0; border-radius: 50%; background: rgba(255, 255, 255, .1); color: #cfd6dd;
}
.mve-chip-del .ic { width: 13px; height: 13px; }

/* 时间轴：每一层一段 + 一根播放头。`touch-action:none` 是关键 ——
   不给它，手指在轨上横拖会被浏览器当成滚页面，拖动找帧就成了「拖不动」。 */
.mve-tl { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.mve-play {
  flex: none; width: 32px; height: 32px; padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center; background: rgba(255, 255, 255, .1); color: #eef1f4;
}
.mve-play .ic { width: 15px; height: 15px; }
.mve-tlbox {
  position: relative; flex: 1; min-width: 0; height: 34px; overflow: hidden;
  border-radius: 8px; background: rgba(255, 255, 255, .07); touch-action: none;
}
.mve-tltrack { position: absolute; inset: 0; }
.mve-seg {
  position: absolute; top: 5px; bottom: 5px; min-width: 16px; padding: 0 5px;
  border: 0; border-radius: 5px; text-align: left; color: #eef1f4;
  font: inherit; font-size: 10.5px; font-weight: 700; line-height: 24px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 三类层在轨上三种底色（和层本身的颜色无关，只为「一眼看出这段是哪种东西」） */
.mve-seg-text { background: rgba(0, 189, 166, .42); }
.mve-seg-caption { background: rgba(124, 198, 255, .4); }
.mve-seg-sticker { background: rgba(255, 179, 230, .38); }
.mve-seg.is-on { box-shadow: 0 0 0 2px var(--brand, #00bda6); background: var(--brand, #00bda6); color: #06231f; }
.mve-tlhead {
  position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px;
  background: #ff5a5f; pointer-events: none;
}
.mve-tldur {
  flex: none; min-width: 66px; text-align: right; font-size: 11px; color: #8b96a3;
  font-variant-numeric: tabular-nums;
}

/* 工具条：窄屏一定会溢出，所以横滑（这一条自己就是可横滑的，不参与「横向锁死」那类断言） */
.mve-tools {
  display: flex; gap: 6px; margin-top: 8px; overflow-x: auto;
  -webkit-overflow-scrolling: touch; padding-bottom: 2px;
}
.mve-tool {
  flex: none; display: inline-flex; align-items: center; gap: 4px; padding: 7px 12px;
  border: 1px solid rgba(255, 255, 255, .14); border-radius: 999px;
  background: rgba(255, 255, 255, .06); color: #dfe5eb; font-size: 12px; font-weight: 700;
}
.mve-tool .ic { width: 14px; height: 14px; }
.mve-tool.is-on { background: var(--brand, #00bda6); border-color: transparent; color: #06231f; }

/* 配乐那一格：`partials/_bgm_picker.html` 那一整块搬进来后**不动它的配色**。
   bgm.css 那套是按浅色底写的，这里给一块浅色卡片把它包住 ——
   在深色剪辑台里重画一份 bgm 的深色版就是「同一口径两个真身」（铁律 40②）。 */
.mve-bgm-slot {
  margin-top: 8px; padding: 8px; border-radius: 12px;
  background: #f6f7f9; color: #17181c;
}
.bgm-field.is-insheet { margin: 0; }

/* 导出那一块（第二波③）：钮 + 一句实话 + 出来的下载链接。
   它在发布页那一格（不在剪辑台里），版式跟着 `.mve-add` 走，只是实底 —— 点了真会出文件。 */
.mve-exp { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line, rgba(0, 0, 0, .07)); }
.mve-exp-btn {
  display: flex; width: 100%; align-items: center; justify-content: center; gap: 6px;
  padding: 9px; border: 0; border-radius: var(--r-sm, 8px);
  background: var(--brand-soft, rgba(0, 189, 166, .12)); color: var(--brand-deep, #0a8f80);
  font-size: 12.5px; font-weight: 700;
}
.mve-exp-btn[disabled] { opacity: .6; }
.mve-exp-btn .ic { width: 15px; height: 15px; }
.mve-exp-note { margin: 6px 2px 0; font-size: 11.5px; line-height: 1.6; color: var(--ink-3, #6b7280); }
.mve-exp-note.is-bad { color: var(--coral, #e5484d); font-weight: 600; }
.mve-exp-dl {
  display: block; margin-top: 8px; padding: 9px; border-radius: var(--r-sm, 8px);
  background: var(--brand, #00bda6); color: #fff;
  font-size: 12.5px; font-weight: 700; text-align: center; text-decoration: none;
}

/* 选中一层时，预览上那个虚线框（与四颗把手是一套：看得见的框 + 摸得着的角） */
.mov-stage.is-editing .mov { cursor: grab; }
.mov-stage.is-editing .mov.is-drag { cursor: grabbing; }
.mov-stage.is-editing .mov::after {
  content: '';
  position: absolute; inset: -6px;
  border: 1px dashed rgba(255, 255, 255, .75);
  border-radius: 6px;
  opacity: 0;
}
.mov-stage.is-editing .mov.is-on::after { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .mve-sw, .mve-tool, .mve-font, .mve-deco { transition: none; }
}
