/* 语音/视频通话：来电浮层与通话主界面。
 * 视觉对标微信：整屏暗场、大头像、圆形图标按钮 + 下方小字标签。
 * 配色优先取 base.css 的设计变量；通话界面是深色基底场景，
 * 这里少量使用固定深色（#0b0d10 一类），保证在浅色主题下也压得住画面。 */

:root{--call-bg1:#171a20;--call-bg2:#0a0c0f;--call-ico-bg:rgba(255,255,255,.13);
  --call-ico-tx:#fff;--call-ico-on:rgba(255,255,255,.94)}

/* ---------- 来电 / 去电等待（#call-mask） ---------- */
/* 层级高于弹窗(90)与 toast(99) */
.call-mask{position:fixed;inset:0;z-index:120;display:flex;align-items:center;justify-content:center;
  padding:20px;overflow:hidden;animation:fadein .16s ease-out}
/* 背景层与内容层分离：背景跟着头像走柔光，内容不跟着动。
   纯色铺底而非 var(--mask)，浅色主题下才不会突然变白刺眼。 */
.call-mask-bg{position:absolute;inset:0;background:linear-gradient(170deg,var(--call-bg1),var(--call-bg2));
  z-index:-1}
.call-mask-bg::after{content:'';position:absolute;inset:0;
  background:radial-gradient(46% 34% at 50% 34%,rgba(255,255,255,.1),transparent 70%)}
.call-scene{position:relative;width:100%;max-width:340px;display:flex;flex-direction:column;
  align-items:center;text-align:center}
/* 头像 96px：微信来电页的比例。圆形，配合柔光背景不显突兀 */
.call-scene-av{width:96px;height:96px;border-radius:50%;margin-bottom:18px;display:flex;
  align-items:center;justify-content:center;color:#fff;font-size:36px;font-weight:600;
  box-shadow:0 8px 32px rgba(0,0,0,.35)}
.call-scene-name{font-size:22px;font-weight:600;color:#fff;max-width:100%;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
/* 提示语：浅色低对比，不与姓名抢视觉。振铃时由 JS 加 .pulse 做呼吸动画 */
.call-scene-tip{margin-top:8px;font-size:14px;color:rgba(255,255,255,.62);min-height:20px}
.call-scene-tip.pulse{animation:callPulse 1.4s ease-in-out infinite}
@keyframes callPulse{0%,100%{opacity:.55}50%{opacity:1}}

/* 按钮组：底部两枚圆形按钮，间距靠 justify-content:space-between 拉开，
   这样双钮（被叫）与单钮（主叫取消）在同一套 CSS 下都居中好看 */
.call-btns{display:flex;justify-content:center;gap:min(18vw,140px);margin-top:52px}
/* 主叫只有取消一枚，用 margin:auto 让它真正居中而不是偏左 */
.call-out-btns .call-act{margin:0 auto}
.call-act{display:flex;flex-direction:column;align-items:center;gap:9px}
.call-act span{font-size:12.5px;color:rgba(255,255,255,.78)}
.call-round{width:64px;height:64px;border:none;border-radius:50%;display:flex;align-items:center;
  justify-content:center;cursor:pointer;transition:transform .14s ease,filter .14s ease;
  box-shadow:0 6px 20px rgba(0,0,0,.32)}
.call-round .ti svg{width:28px;height:28px}
.call-round:active{transform:scale(.94)}
.call-round-reject{background:#e8514b;color:#fff}
.call-round-accept{background:#2aae67;color:#fff}
/* 接听键放大 1.18 倍：主操作必须一眼可辨 */
.call-round-accept{transform:scale(1.18)}
.call-round-accept:active{transform:scale(1.1)}
.call-round:hover{filter:brightness(1.06)}

/* ---------- 通话中主界面（#call-bar） ---------- */
/* 整屏而非吸顶细条：视频画面需要铺满，语音也需要大头像做背景 */
.call-bar{position:fixed;inset:0;z-index:110;display:flex;flex-direction:column;
  background:linear-gradient(170deg,var(--call-bg1),var(--call-bg2));color:#fff;overflow:hidden}

/* 顶部信息条：浮在画面之上。视频通话时用渐变压暗，保证白字可读 */
.call-top{position:absolute;top:0;left:0;right:0;z-index:6;display:flex;flex-direction:column;
  align-items:center;gap:3px;padding:calc(16px + env(safe-area-inset-top)) 16px 26px;
  background:linear-gradient(180deg,rgba(0,0,0,.52),transparent);pointer-events:none}
.call-bar-name{font-size:15.5px;font-weight:600;max-width:80%;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;text-shadow:0 1px 3px rgba(0,0,0,.4)}
.call-bar-timer{font-size:12.5px;color:rgba(255,255,255,.66);font-variant-numeric:tabular-nums}

/* 画面区：铺满整屏，远端画面 cover 填满。
   两个叠放层都没有 z-index 时靠 DOM 顺序分胜负——video 在 idle 层之后，
   会画在它上面。没有流的 video 仍带着 background:#000，
   于是语音通话整屏发黑、大头像被盖住（真实发生过）。
   因此这里显式管理显隐与层级，不指望"谁盖谁"。 */
.call-stage{position:absolute;inset:0;z-index:1;background:#000}
.call-stage-idle{position:absolute;inset:0;z-index:0;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:14px;
  background:linear-gradient(170deg,var(--call-bg1),var(--call-bg2))}
.call-stage-idle .call-stage-hint{font-size:13px;color:rgba(255,255,255,.5)}
.call-stage-av{width:88px;height:88px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;color:#fff;font-size:33px;font-weight:600;
  box-shadow:0 8px 30px rgba(0,0,0,.34)}
/* 远端画面真的到达后才摘掉大头像。has-video 由 onRemoteTrack 置位，
   必须真的走到那一步——只靠 paintCallBar 判断 kind 是不够的：
   视频通话刚接通、对方还没开摄像头的两三秒里，也该显示大头像而不是黑屏。 */
.call-stage.has-video .call-stage-idle{display:none}
/* 默认隐藏：没有流的 video 不参与显示。display 而非 visibility，
   元素干脆不参与布局，不留下占位。 */
.cv-remote-solo{position:absolute;inset:0;z-index:1;width:100%;height:100%;object-fit:cover;
  display:none;background:#000}
.call-stage.has-video .cv-remote-solo{display:block}

/* 底部控制坞：磨砂悬浮条，微信同款。padding-bottom 吃掉 iPhone 的 home indicator。
 * 视频态一排最多 7 枚按钮（静音/摄像头/翻转/共享/扬声器/小窗/挂断），
 * 固定 54px + 26px 间距在 375px 小屏上要 505px，必被裁掉——按钮尺寸与间距
 * 全部改 clamp() 跟视口宽伸缩，flex-wrap 是最后的兜底（极端窄屏折一行，
 * 也不能有按钮点不到）。 */
.call-dock{position:absolute;left:0;right:0;bottom:0;z-index:7;display:flex;align-items:flex-start;
  justify-content:center;flex-wrap:wrap;row-gap:12px;
  gap:clamp(6px,2.6vw,26px);padding:20px 8px calc(22px + env(safe-area-inset-bottom));
  background:linear-gradient(0deg,rgba(0,0,0,.62),rgba(0,0,0,.34) 62%,transparent)}
.call-dock-act{display:flex;flex-direction:column;align-items:center;gap:clamp(4px,1.8vw,7px);flex:none}
/* 圆形图标按钮 56px，比来电视图的 64 小一号——通话中要能一眼扫完一整排。
 * 小屏上同步缩：320px 宽 7 枚 34px 也放得下（34×7+8×6≈286，含 padding≈302）。 */
.call-ico{width:clamp(34px,10.6vw,54px);height:clamp(34px,10.6vw,54px);border:none;border-radius:50%;display:flex;align-items:center;
  justify-content:center;cursor:pointer;background:var(--call-ico-bg);color:var(--call-ico-tx);
  transition:transform .14s ease,background .18s ease}
.call-ico .ti svg{width:clamp(18px,5.6vw,25px);height:clamp(18px,5.6vw,25px)}
.call-ico:active{transform:scale(.92)}
/* .on = 状态已切换（静音中、摄像头已关、共享中）：实心白底反色，
   远看就能读出「现在是关着的」，不必读文字 */
.call-ico.on{background:var(--call-ico-on);color:#1a1d22}
.call-ico-hangup{background:#e8514b;color:#fff}
.call-ico-hangup:active{transform:scale(.92)}
.call-dock-tx{font-size:clamp(9.5px,3vw,11.5px);color:rgba(255,255,255,.72);white-space:nowrap}

/* 双图标按钮（麦克风/摄像头）：常态只显示第一段，.on 时切到第二段。
   两个 <i> 叠在同一格，用 display 切换——比替换 innerHTML 便宜，
   也不会在切换瞬间丢掉已经解析好的 SVG。 */
.call-ico .ti{position:absolute;display:flex;align-items:center;justify-content:center}
.call-ico .ti-off,.call-ico.on .ti-on{display:none}
.call-ico.on .ti-off{display:flex}

/* 成员宫格。列数由 JS 按人数算好后写进 grid-template-columns，
   这里只给兜底的两列值——人数为 0 或渲染异常时不至于塌成一列。
   群语音时铺在控制坞上方的半透明面板里，不与画面争位置。 */
.call-members{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;max-height:min(40vh,320px);
  overflow-y:auto;position:absolute;left:50%;transform:translateX(-50%);bottom:150px;z-index:5;
  width:min(420px,calc(100vw - 24px));padding:10px;border-radius:16px;
  background:rgba(0,0,0,.42);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
.call-cell{position:relative;display:flex;flex-direction:column;align-items:center;gap:5px;padding:10px 6px;border-radius:12px;background:rgba(255,255,255,.08);cursor:pointer;transition:background .15s ease}
.call-cell:hover{background:rgba(255,255,255,.14)}
.call-cell.self{cursor:default;box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}
/* 正在说话：头像外圈亮起。判定来自远端音轨的实际音量（见 call.js 的 talkMeter），
   不是「已连接」——连接通了不代表此刻有人在说，静态高亮只会变成噪音。 */
.call-cell.speaking .call-cell-av{box-shadow:0 0 0 2px #4ade80,0 0 12px 2px rgba(74,222,128,.45)}
/* 还在振铃、尚未接入：格子保留但压暗，让人一眼分清「已加入」与「待接听」 */
.call-cell.pending{opacity:.55}
.call-cell-av{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;font-size:17px;font-weight:600;transition:box-shadow .12s ease}
.call-cell-name{font-size:12px;color:rgba(255,255,255,.82);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 静音角标压在头像右上角，不占独立行——多人时每格高度要尽量一致，
   否则宫格会因为谁静音了而参差不齐 */
.call-cell-muted{position:absolute;top:5px;right:5px;padding:1px 5px;border-radius:999px;background:#e8514b;color:#fff;font-size:10px;line-height:1.5}
/* 群主标记：与静音角标分居两侧，同一格最多各占一个角，不会互相压盖 */
.call-cell-host{position:absolute;top:5px;left:5px;padding:1px 5px;border-radius:999px;background:rgba(255,255,255,.22);color:#fff;font-size:10px;line-height:1.5}
/* 性能提示：只在人数多且设备弱时出现，空元素不占高度。
   位置在控制坞正上方，遮住 dock 就等于遮住了挂断键，不能放错。 */
.call-warn:empty{display:none}
.call-warn{position:absolute;left:50%;transform:translateX(-50%);bottom:132px;z-index:8;
  max-width:calc(100vw - 40px);font-size:12px;color:#ffd66b;background:rgba(120,80,0,.42);
  border:1px solid rgba(255,214,107,.32);border-radius:8px;padding:5px 10px;line-height:1.4;text-align:center}

/* 拉人面板：浮在控制坞上方，与成员栏同宽。内嵌于通话界面，随通话一起消失。 */
.call-invite{position:absolute;left:50%;transform:translateX(-50%);bottom:150px;z-index:9;
  width:min(420px,calc(100vw - 24px));background:rgba(22,25,31,.94);border-radius:16px;padding:10px;
  box-shadow:0 10px 34px rgba(0,0,0,.45)}
.call-invite-hd{font-size:12.5px;color:rgba(255,255,255,.6);padding:2px 4px 6px}
.call-invite-list{max-height:min(34vh,260px);overflow-y:auto;display:flex;flex-direction:column;gap:2px}
.call-invite-row{display:flex;align-items:center;gap:9px;padding:7px 8px;border-radius:9px;cursor:pointer}
.call-invite-row:hover{background:rgba(255,255,255,.08)}
/* 勾选框自绘：原生 checkbox 在深色底上对比度不可控，且尺寸随系统缩放变化 */
.call-invite-box{width:17px;height:17px;border-radius:5px;border:1.5px solid rgba(255,255,255,.28);flex:none;display:flex;align-items:center;justify-content:center}
.call-invite-row.on .call-invite-box{background:#2aae67;border-color:#2aae67}
/* 名额已满且未勾选：置灰但仍可点击，点击时给出 toast 说明原因 */
.call-invite-row.full{opacity:.45}
.call-invite-row.on .call-invite-box::after{content:'';width:9px;height:5px;border:2px solid #fff;border-top:0;border-right:0;transform:rotate(-45deg) translate(1px,-1px)}
.call-invite-nm{flex:1;min-width:0;font-size:13.5px;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.call-invite-ft{display:flex;gap:8px;justify-content:flex-end;padding:8px 2px 2px}
.call-bar-btn{height:32px;padding:0 14px;border:none;border-radius:999px;background:rgba(255,255,255,.14);
  color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;flex:none}
.call-bar-btn-primary{background:#2aae67;color:#fff}

/* 成员操作菜单：固定定位而非 absolute。
 * 它按格子与视口的位置计算 top/left（openMemberMenu 里用的是 getBoundingClientRect），
 * 若挂在 position:relative 的祖先内，这些视口坐标会被当作局部坐标，菜单整体偏移。 */
.call-menu{position:fixed;z-index:130;min-width:132px;padding:5px;border-radius:12px;background:rgba(22,25,31,.97);border:1px solid rgba(255,255,255,.12);box-shadow:0 8px 26px rgba(0,0,0,.5)}
.call-menu-row{display:flex;align-items:center;width:100%;padding:8px 11px;border:none;border-radius:8px;background:none;color:#fff;font-size:13.5px;text-align:left;cursor:pointer}
.call-menu-row:hover{background:rgba(255,255,255,.1)}
.call-menu-row.danger{color:#ff8a84}
.call-menu-row:disabled{color:rgba(255,255,255,.36);cursor:not-allowed}

/* ---------- 通话记录页 ---------- */
/* 与设置页同型：ci-bar 标题栏 + ci-scroll 滚动区，视觉上是一级页面而不是弹层 */
/* z-index 与 #settings 对齐（88）：记录页是从设置页推进来的下一级，
 * 必须高于设置页（否则返回前它盖在设置页上看起来没生效），
 * 又必须低于 toast(99) 与通话浮层(110/120)，否则提示与来电会被压住。 */
#calllogs{position:fixed;inset:0;z-index:88;display:flex;flex-direction:column;background:var(--bg);animation:ciIn .2s ease-out}
.cl-list{display:flex;flex-direction:column}
.cl-row{display:flex;align-items:center;gap:11px;padding:11px 14px;border-bottom:1px solid var(--line)}
.cl-row:last-child{border-bottom:0}
.cl-row .call-cell-av{width:38px;height:38px;font-size:15px;flex:none}
.cl-main{flex:1;min-width:0}
.cl-t{font-size:14.5px;color:var(--txt);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cl-s{font-size:12px;color:var(--sub);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cl-when{font-size:12px;color:var(--mut);flex:none;font-variant-numeric:tabular-nums}
.cl-empty{padding:52px 14px;text-align:center;color:var(--sub);font-size:13.5px}

/* ---------- 视频通话（call_video.js） ----------
 * 本地预览与远端画面共用一套尺寸规则：摄像头画面 object-fit:cover，
 * 裁掉边缘也看得清人脸；而通话窗口按宫格排布时宁可裁也不能留黑边——
 * 留黑边会让宫格看起来像坏了。
 * 例外是屏幕共享（.cv-share）：屏幕内容是要看全的，任务栏、代码行
 * 裁掉一半就完全没法用，因此 contain 留黑边也不裁。 */
.cv-local,.cv-remote{background:#000;object-fit:cover;display:block}
.cv-remote-solo.cv-share,.cv-remote.cv-share{object-fit:contain;background:#000}
/* 本地预览：右下角浮窗，压在控制坞之上。
   不能像以前那样挂在 .call-bar 的底部靠 absolute 定位——现在 .call-bar 是整屏容器，
   left/bottom 是相对整屏的，工具条挪到中间就会把它一起挪走。 */
.cv-local{position:absolute;right:14px;bottom:150px;width:84px;height:118px;border-radius:12px;
  box-shadow:0 4px 16px rgba(0,0,0,.5);z-index:4}
/* 关摄像头时给个斜纹底：黑屏小窗容易被当成画面卡住，斜纹明确表达"已关" */
.cv-local.cv-off{background:repeating-linear-gradient(45deg,#2a2e36,#2a2e36 6px,#1d2027 6px,#1d2027 12px)}
/* 远端视频在成员格内：铺满该格，头像与名字靠 z-index 压在上面 */
.cv-remote{position:absolute;inset:0;width:100%;height:100%;z-index:0;border-radius:12px}
.call-cell{overflow:hidden}
/* 有远端画面时头像与名字改为压在画面上方，靠半透明底衬保证可读 */
.call-cell .call-cell-av,.call-cell .call-cell-name{position:relative;z-index:1}

/* ---------- 通话特效（call_effects.js） ----------
 * 这些节点是 canvas 与隐藏 video 的工作区，用户看不到，
 * 但必须留在文档里：脱离文档的 canvas 无法 captureStream。 */
.cf-src,.cf-canvas{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;
  left:-9999px;overflow:hidden}
.cf-blur-src{filter:blur(6px)}
/* 截图的落点：先显示再由浏览器下载，给用户一个「已生成」的反馈 */
.cf-shot,.cf-download{position:fixed;left:50%;top:16px;transform:translateX(-50%);z-index:130;
  padding:6px 14px;border-radius:999px;background:var(--card);border:1px solid var(--line);
  box-shadow:var(--sh-md);color:var(--txt);font-size:12.5px;pointer-events:none;
  animation:fadein .2s ease-out}

/* 1:1 专用的远端音频出口。不隐藏的话它会作为通话条的一个 flex 子项，
   既占掉一段横向空间，又可能把底部工具条挤出可视区——纯音频节点没有任何
   可见内容，直接移出布局即可。display:none 的媒体元素仍能正常播放。 */
.call-audio-solo{display:none}
