:root {
  color-scheme: dark;
  --bg: #0c0d0f;
  --surface: #18191c;
  --surface-2: #1d1e22;
  --border: #2d2e33;
  --text: #e9e9ea;
  --text-mute: #8a8a8e;
  --text-faint: #5a5a5e;
  --accent: #d0392a;
  /* §STATE 带看三色护栏(#0163,镜像 placevr-design canonical,锁定不白标) */
  --success: #1f9d55;
  --success-glow: rgba(31,157,85,0.45);
  --follow-tint: rgba(31,157,85,0.14);
  --warn: #e0a32e;
  --danger: var(--accent);
  --safe-bottom: env(safe-area-inset-bottom, 0);
  --safe-top: env(safe-area-inset-top, 0);
  /* Frosted-glass for floating controls (placevr-viewer#9 — neutral dark so it
     stays legible over any panorama, unlike pure-white). */
  --glass-bg: rgba(0,0,0,0.30);
  --glass-border: 1px solid rgba(255,255,255,0.18);
  --glass-blur: blur(16px) saturate(130%);
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { margin: 0; padding: 0; height: 100%; background: var(--bg); color: var(--text); font-family: -apple-system, "PingFang SC", "Helvetica Neue", "Microsoft YaHei", sans-serif; overflow: hidden; }

/* ─── Overlays ─── */
.overlay { position: fixed; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; background: var(--bg); z-index: 100; gap: 12px; padding: 24px; text-align: center; }
.overlay[hidden] { display: none; }
.spinner { width: 36px; height: 36px; border: 3px solid var(--surface-2); border-top-color: #fff; border-radius: 50%; animation: spin 0.9s linear infinite; }
.overlay-icon { width: 56px; height: 56px; border-radius: 50%; background: var(--accent); color: #fff; font-size: 32px; font-weight: 600; display: flex; align-items: center; justify-content: center; }
.overlay-title { font-size: 16px; font-weight: 600; }
.overlay-text { font-size: 13px; color: var(--text-mute); max-width: 280px; line-height: 1.5; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ─── App: full-screen panorama, controls float on top ─── */
#app { position: fixed; inset: 0; overflow: hidden; }
#app[hidden] { display: none; }

/* Panorama fills the whole screen as the base layer. */
#panorama-pane { position: absolute; inset: 0; background: linear-gradient(135deg, #0c0d0f 0%, #1a1d24 50%, #0c0d0f 100%); }
.pano-layer { position: absolute; inset: 0; opacity: 0; transition: opacity 650ms ease; pointer-events: none; }
.pano-layer.visible { opacity: 1; pointer-events: auto; }
/* 热点点击「电影感前推 + 交叉淡入」:对溶拉长 + ease-in-out(见 viewer.js CINE_FADE_MS)。
   仅热点切换时两层临时挂 .cine;小地图/罗盘/箭头切换不挂 → 保持默认 650ms。 */
.pano-layer.cine { transition: opacity 900ms cubic-bezier(0.45, 0, 0.25, 1); }
/* Meeting guest input lock — above pano layers, below floating controls. */
#input-lock { position: absolute; inset: 0; z-index: 6; background: transparent; }
#input-lock[hidden] { display: none; }

/* Floating top: title bar (gradient so text stays legible over any pano). */
#topbar { position: absolute; top: 0; left: 0; right: 0; z-index: 10; padding: calc(10px + var(--safe-top)) 16px 22px; text-align: center; pointer-events: none; background: linear-gradient(to bottom, rgba(0,0,0,0.55), rgba(0,0,0,0)); }
#topbar .title { font-size: 15px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-shadow: 0 1px 3px rgba(0,0,0,0.8); }
#topbar .meta { font-size: 11px; color: #d8d8da; margin-top: 2px; text-shadow: 0 1px 2px rgba(0,0,0,0.8); }
/* ⋯ tools button (placevr-viewer#7 A), rightmost in the top bar. */
#tools-btn { position: absolute; z-index: 11; top: calc(8px + var(--safe-top)); right: 14px; width: 34px; height: 34px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.2); background: rgba(0,0,0,0.35); color: #fff; font-size: 20px; line-height: 1; pointer-events: auto; cursor: pointer; }

/* Close-page button, left of ⋯ (top-right). */
#close-btn { position: absolute; z-index: 11; top: calc(8px + var(--safe-top)); right: 56px; width: 34px; height: 34px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.2); background: rgba(0,0,0,0.35); color: #fff; font-size: 15px; line-height: 1; pointer-events: auto; cursor: pointer; }

/* ⋯ tools dropdown (placevr-viewer#7 A): fullscreen / share / listing / disclaimer. */
#tools-menu { position: absolute; z-index: 30; top: calc(48px + var(--safe-top)); right: 14px; display: flex; flex-direction: column; min-width: 134px; padding: 6px; gap: 2px; background: rgba(0,0,0,0.42); border: var(--glass-border); border-radius: 12px; box-shadow: 0 8px 30px rgba(0,0,0,0.5); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); }
#tools-menu[hidden] { display: none; }
.tool-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 10px; border: none; border-radius: 8px; background: transparent; color: var(--text); font-size: 13px; text-align: left; cursor: pointer; }
.tool-item[hidden] { display: none; }
.tool-item:active { background: var(--surface-2); }
.tool-item.copied { color: #fff; }
.tool-ico { font-size: 15px; width: 18px; flex: 0 0 18px; text-align: center; }

/* Floating top-right: room info + compass + minimap card. */
#map-card { position: absolute; z-index: 12; top: calc(52px + var(--safe-top)); right: 12px; width: 156px; background: transparent; padding: 8px; }
#map-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.room-info { min-width: 0; }
.room-name { display: block; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-shadow: 0 1px 3px rgba(0,0,0,0.85); }
.room-area { display: block; font-size: 11px; color: #d8d8da; margin-top: 1px; text-shadow: 0 1px 3px rgba(0,0,0,0.85); }

/* Compass: fixed ring, needle rotates to point true north relative to view. */
#compass { position: relative; flex: 0 0 32px; width: 32px; height: 32px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.25); background: rgba(0,0,0,0.3); display: flex; align-items: center; justify-content: center; }
#compass-needle { position: absolute; top: 3px; left: 50%; width: 0; height: 0; border-left: 4px solid transparent; border-right: 4px solid transparent; border-bottom: 11px solid #fff; transform-origin: 50% 13px; transform: translateX(-50%) rotate(0deg); }
#compass-dir { font-size: 10px; font-weight: 700; color: var(--text); }

#map-stage { position: relative; width: 100%; height: 104px; background: transparent; border-radius: 8px; overflow: hidden; cursor: pointer; }
#floor-img { display: block; width: 100%; height: 100%; object-fit: contain; filter: drop-shadow(0 0 2px rgba(255,255,255,0.45)); }
#dot-layer { position: absolute; inset: 0; pointer-events: none; }
/* P1 尺寸标注:结构化房间尺寸标签层(小地图 + ⤢ 大图共用样式)。DOM 文本 → 缩放不糊。 */
#dim-layer, #map-overlay-dims { position: absolute; inset: 0; pointer-events: none; }
.dim-label { position: absolute; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center; line-height: 1.05; white-space: nowrap; text-align: center; }
.dim-label .dim-size { font-weight: 700; color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,0.95), 0 0 2px rgba(0,0,0,0.9); }
.dim-label .dim-name { font-size: 0.82em; font-weight: 600; color: rgba(255,255,255,0.9); text-shadow: 0 1px 3px rgba(0,0,0,0.95); }
.dot { position: absolute; transform: translate(-50%, -50%); width: 16px; height: 16px; border-radius: 50%; background: rgba(255,255,255,0.92); color: #111; font-size: 10px; font-weight: 600; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 1.5px rgba(0,0,0,0.35), 0 2px 6px rgba(0,0,0,0.4); pointer-events: auto; cursor: pointer; transition: transform 120ms ease; }
.dot.active { transform: translate(-50%, -50%) scale(1.3); background: #fff; box-shadow: 0 0 0 3px rgba(0,0,0,0.4), 0 0 12px rgba(255,255,255,0.7); }
/* Invisible ≥28px tap target (placevr-viewer#3 C) — visual dot stays 18px. */
.dot::before { content: ''; position: absolute; inset: -6px; border-radius: 50%; }
/* P6 朝向扇形:每个点的"全景正面"楔形;当前点的随 yaw 实时转(JS 改 rotate)。
   conic from -22deg → 44° 对称楔形指上;rotate(θ) 指向平面图方位。放 dot 下层。 */
.dot-cone {
  position: absolute; left: 50%; top: 50%;
  width: 46px; height: 46px; margin-left: -23px; margin-top: -23px;
  border-radius: 50%; pointer-events: none; z-index: -1;
  background: conic-gradient(from -22deg, rgba(255,255,255,0.55) 0deg 44deg, transparent 44deg 360deg);
  transform: rotate(0deg); transform-origin: 50% 50%;
  transition: transform 90ms linear;
}
.dot.active .dot-cone { background: conic-gradient(from -20deg, rgba(255,255,255,0.82) 0deg 40deg, transparent 40deg 360deg); width: 56px; height: 56px; margin-left: -28px; margin-top: -28px; }
/* "+N" cluster badge for overlapping dots on the small card (tap → big map). */
.dot-cluster { background: rgba(40,40,46,0.92); font-size: 11px; }
.dot-cluster::after { content: '+'; font-size: 8px; margin-left: -1px; }
/* Expand-to-big-map affordance, bottom-right of the minimap. */
#map-expand { position: absolute; right: 3px; bottom: 3px; z-index: 2; width: 22px; height: 22px; padding: 0; border: none; border-radius: 6px; background: rgba(0,0,0,0.45); color: #fff; font-size: 14px; line-height: 22px; cursor: pointer; }

/* ── Full-screen floor-plan overlay (placevr-viewer#3 A) ── */
#map-overlay { position: fixed; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center; }
#map-overlay[hidden] { display: none; }
#map-overlay-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.78); backdrop-filter: blur(2px); }
#map-overlay-panel { position: relative; width: min(94vw, 900px); height: min(86vh, 720px); padding: 14px; }
#map-overlay-close { position: absolute; top: -2px; right: -2px; z-index: 2; width: 40px; height: 40px; border: none; border-radius: 50%; background: rgba(0,0,0,0.6); color: #fff; font-size: 20px; cursor: pointer; }
/* #8: static north indicator on the big plan (building-wide north, fixed angle). */
#map-overlay-compass { position: absolute; top: 8px; left: 8px; z-index: 3; width: 40px; height: 40px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.3); background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; }
#map-overlay-compass[hidden] { display: none; }
#map-overlay-compass span { font-size: 11px; font-weight: 700; color: var(--text); }
#map-overlay-needle { position: absolute; top: 4px; left: 50%; width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 13px solid #fff; transform-origin: 50% 16px; transform: translateX(-50%) rotate(0deg); }
#map-overlay-stage { position: relative; width: 100%; height: 100%; }
#map-overlay-img { display: block; width: 100%; height: 100%; object-fit: contain; filter: drop-shadow(0 0 3px rgba(255,255,255,0.5)); }
#map-overlay-dots { position: absolute; inset: 0; pointer-events: none; }
#map-overlay-dots .dot { width: 26px; height: 26px; font-size: 13px; }
#map-overlay-dots .dot::before { inset: -8px; }
.dot-label { position: absolute; left: 50%; top: calc(100% + 3px); transform: translateX(-50%); white-space: nowrap; font-size: 12px; font-weight: 600; color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,0.9); pointer-events: none; }

/* Fallback chip list when there's no floor plan. */
#point-list { display: flex; flex-wrap: wrap; gap: 6px; padding: 2px; }
/* #0206:作者写的 display 会压过 [hidden] 的浏览器默认样式 → 必须显式兜底,
   否则 viewer.js 的 `pointList.hidden = true`(有平面图时)形同虚设。 */
#point-list[hidden] { display: none; }
#point-list button { padding: 6px 12px; border-radius: 16px; background: var(--surface-2); color: var(--text); border: 1px solid var(--border); font-size: 12px; }
#point-list button.active { background: var(--accent); border-color: #fff; }

/* Bottom-right FAB column (placevr-viewer#9): 导览 + 致电/微信 as uniform 56px
   circles, right-aligned and evenly spaced (replaces the old standalone nav-btn
   + the action buttons that lived inside the agent card). */
#fab-col { display: none; }
/* No backdrop blur — a flat 30% tint lets the panorama show straight through the
   buttons (frost made even low-alpha fills look milky / block the VR). #9. */
/* Bare icons — no fill, border or shadow (per Leo). Just glyph + label. */
#nav-btn, .fab { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; width: 56px; height: 56px; border-radius: 50%; border: none; background: transparent; color: var(--text); cursor: pointer; text-decoration: none; }
#nav-btn.running { color: #fff; }
.fab[hidden] { display: none; }
/* 致电 tinted red so it still reads as the call CTA without any chrome. */
#action-tel { color: #fff; }
#nav-icon, .fab-icon { font-size: 17px; line-height: 1; }
#nav-label, .fab-label { font-size: 10px; }

/* ─── Agent card (floating bottom-left, identity only — #9) ─── */
/* right:88 leaves the bottom-right FAB column clear so long names don't slide
   under the circles. */
#agent-card { position: absolute; z-index: 11; left: 12px; right: 88px; bottom: calc(12px + var(--safe-bottom)); background: transparent; padding: 10px 14px; }
#agent-card[hidden] { display: none; }
.agent-row { display: flex; align-items: center; gap: 12px; }
.agent-avatar { width: 44px; height: 44px; border-radius: 50%; background: var(--surface-2); flex: 0 0 44px; background-size: cover; background-position: center; display: flex; align-items: center; justify-content: center; color: var(--text-mute); font-size: 16px; font-weight: 600; }
.agent-info { flex: 1; min-width: 0; }
.agent-name { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-shadow: 0 1px 3px rgba(0,0,0,0.85); }
.agent-role { font-size: 11px; color: #d8d8da; margin-top: 2px; text-shadow: 0 1px 3px rgba(0,0,0,0.85); }
.brand { font-size: 10px; color: var(--text-faint); text-align: center; margin-top: 6px; }
.brand[hidden] { display: none; }
.brand a { color: var(--text-mute); text-decoration: none; }

/* ─── WeChat modal ─── */
.modal { position: fixed; inset: 0; background: rgba(0,0,0,0.6); display: flex; align-items: center; justify-content: center; z-index: 200; padding: 24px; }
.modal[hidden] { display: none; }
.modal-card { background: var(--surface); border-radius: 14px; padding: 22px 20px 16px; max-width: 320px; width: 100%; text-align: center; }
.modal-title { font-size: 13px; color: var(--text-mute); margin-bottom: 8px; }
.modal-wechat { font-size: 18px; font-weight: 600; font-family: -apple-system, "Menlo", monospace; user-select: all; padding: 10px 8px; background: var(--surface-2); border-radius: 8px; word-break: break-all; }
.modal-hint { font-size: 12px; color: var(--text-mute); margin-top: 10px; }
.modal-text { font-size: 13px; color: var(--text-mute); line-height: 1.7; text-align: left; }
.card-img { max-width: 100%; max-height: 80vh; border-radius: 14px; box-shadow: 0 8px 30px rgba(0,0,0,0.6); }
.modal-input { width: 100%; margin-top: 10px; padding: 11px 12px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; color: var(--text); font-size: 15px; }
.modal-input::placeholder { color: var(--text-faint); }
#meeting-error { color: rgba(255,255,255,0.82); margin-top: 8px; }
#meeting-error[hidden] { display: none; }
.modal-close { margin-top: 14px; width: 100%; padding: 11px; background: var(--accent); color: #fff; border: none; border-radius: 10px; font-size: 14px; font-weight: 600; cursor: pointer; }

/* ─── Pannellum tweaks ─── */
.pnlm-about-msg, .pnlm-load-box { display: none !important; }
.pnlm-zoom-controls, .pnlm-orientation-button, .pnlm-fullscreen-toggle-button { background-color: rgba(0,0,0,0.4) !important; }
/* Nudge Pannellum's own controls clear of our floating agent card. */
.pnlm-zoom-controls { bottom: auto !important; top: calc(12px + var(--safe-top)) !important; left: 12px !important; }

/* Multi-floor selector (placevr-viewer#6 → #9): a compact vertical segmented
   control inside the (glass) minimap card, high floor on top. Transparent itself
   to avoid glass-on-glass; segments sit on the card. Hidden for ≤1 floor. */
.floor-selector{display:flex;flex-direction:column;gap:2px;width:fit-content;margin:8px 0 0 auto;
  padding:0;background:transparent;border:none}
.floor-selector[hidden]{display:none}
.floor-btn{height:24px;min-width:36px;padding:0 12px;border:0;border-radius:9px;
  background:transparent;color:#fff;font-size:12px;font-weight:600;cursor:pointer}
.floor-btn.active{background:rgba(255,255,255,.92);color:#111}

/* ADR-0008 访客呼叫 FAB(打电话模型)+ toast + 邀请弹窗 ────────────────── */
/* 底部居中常驻;既显在线状态又是连接动作。z-index 高于右下 fab-col(12)。 */
#call-fab { position: absolute; z-index: 14; left: 0; right: 0; bottom: calc(20px + var(--safe-bottom)); display: flex; flex-direction: column; align-items: center; gap: 6px; pointer-events: none; }
/* #0206:同上 —— 没有这行,index.html 的初始 `hidden` 和「showing.js 未激活」的场景
   (老 ?meeting= 直链访客)都会照样露出一个无监听的「呼叫经纪人讲解」死按钮。
   (host 视图早先是靠 showing.js hideVisitorFabsForHost 注 !important 绕过的,那正是本坑的旁证)*/
#call-fab[hidden] { display: none; }
#call-btn { pointer-events: auto; display: inline-flex; align-items: center; gap: 8px; padding: 13px 22px; border: var(--glass-border); border-radius: 28px; background: rgba(20,20,22,0.55); color: var(--text); font-size: 15px; font-weight: 600; line-height: 1; cursor: pointer; box-shadow: 0 6px 24px rgba(0,0,0,0.45); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); transition: background 0.2s, transform 0.1s; }
#call-btn:active { transform: scale(0.97); }
#call-btn #call-icon { font-size: 17px; }
/* 在线 = 可呼叫(绿) */
#call-btn.online { background: var(--success); border-color: var(--success); color: #fff; }
/* 离线 = 留资(灰胶囊,与基样式一致,显式定义让 showing.js 加 class 安全) */
#call-btn.offline { background: rgba(20,20,22,0.55); color: var(--text); }
/* 接通中 = 等待(静音灰,禁用) */
#call-btn.pending { background: rgba(40,40,44,0.7); color: var(--text-mute); cursor: default; }
/* 带看中 = 结束(红) */
#call-btn.live { background: var(--accent); border-color: #fff; color: #fff; }
/* 上线脉冲:轻微吸引注意,不刺眼 */
#call-btn.pulse { animation: callPulse 2s ease-in-out infinite; }
@keyframes callPulse { 0%,100% { box-shadow: 0 6px 24px rgba(0,0,0,0.45), 0 0 0 0 rgba(255,255,255,0.4); } 50% { box-shadow: 0 6px 24px rgba(0,0,0,0.45), 0 0 0 10px rgba(255,255,255,0); } }
#call-cancel { pointer-events: auto; border: none; background: transparent; color: var(--text-mute); font-size: 12px; cursor: pointer; padding: 2px 8px; }

#call-toast { position: absolute; z-index: 15; left: 50%; transform: translateX(-50%); bottom: calc(86px + var(--safe-bottom)); max-width: 80vw; padding: 9px 16px; border: var(--glass-border); border-radius: 18px; background: rgba(0,0,0,0.62); color: var(--text); font-size: 13px; line-height: 1.4; text-align: center; backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); }

/* #0163 影院式:带看进行中收起浏览 chrome,全景为主、跟随条接管状态。
   为安全保留顶栏(back/close 始终可用,不做 tap-to-reveal)。
   .meeting-participants 由 meeting.js 注入样式定位在 top:8px,与跟随条抢位 → 带看中隐藏
   (**这是 #0163 的原始动机,别放出来**)。

   🔴 #0225(Leo 直接裁决,推翻 #0163 的一部分):**带看时小地图和楼层始终显示**。
   ⇒ `#map-card` 整卡不再隐藏(#0224 只放出了卡里的 #floor-selector,现在整卡都回来:
   小地图/房名/罗盘/点位列表)。带看中小地图是导航+定位感,不是可有可无的 chrome。
   ⇒ #0224 那两条 pointer-events 兜底(卡 none / 楼层条 auto)**一并删掉** ——
   整卡要显示就必须整卡可点,留着 none 会把小地图点死(点不开大平面图)。
   保留隐藏的只剩 Leo 没点名的三样:#fab-col / #agent-card / .meeting-participants。
   单层 tour 仍由 renderFloorSelector 的 bar.hidden + `.floor-selector[hidden]` 隐藏楼层条。 */
body.showing-live #fab-col,
body.showing-live #agent-card,
body.showing-live .meeting-participants { display: none !important; }

/* 邀请弹窗:复用 .modal/.modal-card;补两按钮一行 */
#invite-popup .invite-actions { display: flex; gap: 10px; margin-top: 14px; }
#invite-popup .invite-actions button { flex: 1; }
.modal-later { padding: 11px 0; border: 1px solid var(--border); border-radius: 12px; background: var(--surface-2); color: var(--text-mute); font-size: 15px; cursor: pointer; }

/* ADR-0008 片4 带看可见提示(进房失败 / 无麦降级)── 顶部居中短暂横幅 */
#trtc-notice { position: fixed; z-index: 1000; left: 50%; transform: translateX(-50%); top: calc(12px + var(--safe-top)); max-width: 86vw; padding: 10px 16px; border: var(--glass-border); border-radius: 18px; background: rgba(0,0,0,0.80); color: var(--text); font-size: 13px; line-height: 1.45; text-align: center; box-shadow: 0 6px 24px rgba(0,0,0,0.5); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); }

/* #10 修复:非阻塞「申请操控」授权弹层(替代 window.confirm,iOS 不卡死)*/
#ctrl-req { position: fixed; z-index: 1002; left: 50%; transform: translateX(-50%); top: calc(60px + var(--safe-top)); min-width: 240px; max-width: 86vw; padding: 14px 16px; border: var(--glass-border); border-radius: 16px; background: rgba(12,13,15,0.90); box-shadow: 0 8px 30px rgba(0,0,0,0.55); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); text-align: center; }
.ctrl-req-msg { font-size: 14px; color: var(--text); margin-bottom: 12px; }
.ctrl-req-row { display: flex; gap: 10px; }
.ctrl-req-row button { flex: 1; padding: 10px 0; border: none; border-radius: 12px; font-size: 14px; font-weight: 600; cursor: pointer; }
.ctrl-req-yes { background: #fff; color: #111; }
.ctrl-req-no { background: var(--surface-2); color: var(--text-mute); }

/* #0028 ADR-0011 step① 路线3:漫游热点 = WebGL 地面层(viewer.js #0028 段)。
   DOM 热点(.roam-hotspot)已删(天生漂)。下面仅留 WebGL 环的名字标签样式。 */
.roam-label {
  position: absolute; top: 46px; left: 50%; transform: translateX(-50%); white-space: nowrap;
  background: rgba(0,0,0,0.62); color: #fff; font-size: 11px; font-weight: 600;
  padding: 2px 8px; border-radius: 9px; pointer-events: none;
}

/* ─── H5 listing-view style refresh (2026-06-23, screenshot target) ─── */
#topbar {
  height: calc(64px + var(--safe-top));
  padding: var(--safe-top) 14px 0;
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr) 112px;
  align-items: center;
  background: #fff;
  color: #050505;
  pointer-events: auto;
  text-align: center;
  box-shadow: 0 1px 0 rgba(0,0,0,0.08);
}
#topbar .title {
  font-size: 18px;
  font-weight: 800;
  color: #050505;
  text-shadow: none;
}
#topbar .meta { display: none; }
#back-btn {
  width: 42px;
  height: 42px;
  border: 0;
  background: transparent;
  color: #050505;
  font-size: 40px;
  line-height: 1;
  cursor: pointer;
}
#top-actions {
  justify-self: end;
  height: 42px;
  display: flex;
  align-items: center;
  padding: 0 12px;
  gap: 12px;
  border: 1px solid rgba(0,0,0,0.08);
  border-radius: 24px;
  background: #fff;
  box-shadow: 0 1px 8px rgba(0,0,0,0.06);
}
#tools-btn,
#close-btn {
  position: static;
  width: auto;
  height: auto;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: #050505;
  font-size: 20px;
  pointer-events: auto;
}
#close-btn {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 4px solid #111;
  font-size: 0;
}
#tools-menu {
  top: calc(60px + var(--safe-top));
  right: 16px;
  background: rgba(255,255,255,0.94);
  border: 1px solid rgba(0,0,0,0.10);
  color: #111;
}
.tool-item { color: #111; }

#scene-title {
  position: absolute;
  z-index: 11;
  left: 20px;
  top: calc(86px + var(--safe-top));
  max-width: calc(100vw - 40px);
  color: #fff;
  font-size: 22px;
  font-weight: 850;
  letter-spacing: .2px;
  text-shadow: 0 2px 8px rgba(0,0,0,0.35);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#map-card {
  left: 20px;
  right: auto;
  top: calc(148px + var(--safe-top));
  width: 150px;
  padding: 12px;
  border-radius: 4px;
  background: rgba(0,0,0,0.22);
}
#map-head { margin-bottom: 8px; }
#map-head #compass { display: none; }
.room-name {
  font-size: 15px;
  font-weight: 800;
  color: #fff;
}
.room-area {
  font-size: 13px;
  color: rgba(255,255,255,0.92);
}
#map-stage {
  height: 116px;
  border-radius: 0;
}
#floor-img {
  filter: brightness(2.2) grayscale(1) drop-shadow(0 0 1px rgba(255,255,255,0.9));
  opacity: 0.92;
}
.dot {
  width: 10px;
  height: 10px;
  font-size: 0;
  background: #fff;
  box-shadow: 0 0 0 2px rgba(0,0,0,0.4);
}
.dot.active {
  transform: translate(-50%, -50%) scale(1.25);
  box-shadow: 0 0 0 3px rgba(0,0,0,0.45), 0 0 14px rgba(255,255,255,0.9);
}
.dot-cone {
  width: 30px;
  height: 30px;
  margin-left: -15px;
  margin-top: -15px;
  opacity: 0.72;
  background: conic-gradient(from -18deg, rgba(255,255,255,0.5) 0deg 36deg, transparent 36deg 360deg);
}
#map-expand { display: none; }

.floor-selector {
  position: absolute;
  z-index: 12;
  left: 20px;
  top: calc(346px + var(--safe-top));
  margin: 0;
  padding: 18px 18px;
  gap: 22px;
  border-radius: 30px;
  background: rgba(0,0,0,0.18);
}
.floor-btn {
  min-width: 40px;
  height: 22px;
  padding: 0;
  border-radius: 0;
  background: transparent;
  color: rgba(255,255,255,0.60);
  font-size: 18px;
  font-weight: 800;
}
.floor-btn.active {
  background: transparent;
  color: #fff;
  border-bottom: 2px solid #fff;
}

#share-float,
#measure-float {
  position: absolute;
  z-index: 18;
  right: 17px;
  border: 0;
  color: #fff;
  background: rgba(255,255,255,0.22);
  cursor: pointer;
}
#share-float {
  top: calc(96px + var(--safe-top));
  width: 40px;
  height: 40px;
  border-radius: 50%;
  font-size: 22px;
}
#measure-float {
  top: calc(184px + var(--safe-top));
  width: 40px;
  height: 56px;
  border-radius: 12px;
  font-size: 30px;
}
#measure-float.active {
  background: rgba(255,255,255,0.88);
  color: #333;
}
#measure-overlay {
  position: absolute;
  z-index: 9;
  right: 10px;
  top: calc(64px + var(--safe-top));
  width: 38vw;
  max-width: 260px;
  height: 52vh;
  pointer-events: none;
}
#measure-overlay[hidden] { display: none; }
.measure-line {
  position: absolute;
  background: rgba(255,255,255,0.85);
  transform-origin: top left;
}
.measure-main {
  width: 2px;
  height: 82%;
  right: 44%;
  top: 0;
  transform: rotate(7deg);
}
.measure-foot {
  width: 66%;
  height: 2px;
  right: 0;
  bottom: 10%;
}
.measure-side {
  width: 2px;
  height: 22%;
  right: 66%;
  bottom: 10%;
  transform: rotate(-26deg);
}
.measure-label {
  position: absolute;
  color: #fff;
  font-size: 14px;
  font-weight: 800;
  text-shadow: 0 1px 3px rgba(0,0,0,0.45);
}
.measure-label-long {
  right: 40%;
  top: 30%;
  transform: rotate(-83deg);
}
.measure-label-short {
  right: 8%;
  bottom: 8%;
}
.measure-label-side {
  right: 62%;
  bottom: 18%;
  transform: rotate(-66deg);
}

#listing-sheet {
  position: absolute;
  z-index: 15;
  left: 12px;
  right: 12px;
  bottom: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: calc(82vh - var(--safe-top));
  overflow-y: auto;
  padding: 0 0 calc(16px + var(--safe-bottom));
  transform: translateY(calc(100% - 206px - var(--safe-bottom)));
  transition: transform 220ms ease;
  -webkit-overflow-scrolling: touch;
}
#listing-sheet.expanded {
  transform: translateY(0);
}
#room-strip {
  position: relative;
  z-index: auto;
  left: auto;
  right: auto;
  bottom: auto;
  display: flex;
  gap: 28px;
  overflow-x: auto;
  padding: 0 4px 2px;
  scrollbar-width: none;
}
#room-strip::-webkit-scrollbar { display: none; }
.room-tab {
  flex: 0 0 auto;
  border: 0;
  background: transparent;
  color: rgba(255,255,255,0.88);
  font-size: 18px;
  font-weight: 800;
  text-shadow: 0 2px 6px rgba(0,0,0,0.45);
  cursor: pointer;
}
.room-tab.active { color: #fff; }

#agent-card {
  position: relative;
  left: auto;
  right: auto;
  bottom: auto;
  min-height: 72px;
  padding: 12px 14px;
  border-radius: 5px;
  background: rgba(0,0,0,0.42);
}
.agent-row { gap: 12px; }
.agent-avatar {
  width: 54px;
  height: 54px;
  flex-basis: 54px;
  border: 2px solid rgba(255,255,255,0.75);
}
.agent-name {
  font-size: 20px;
  font-weight: 850;
}
.agent-role {
  font-size: 13px;
  color: rgba(255,255,255,0.78);
}
.brand {
  position: absolute;
  left: 14px;
  bottom: 4px;
  margin: 0;
  color: rgba(255,255,255,0.58);
  text-align: left;
}
.agent-action {
  flex: 0 0 44px;
  width: 44px;
  border: 0;
  background: transparent;
  color: #fff;
  text-decoration: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  font-size: 12px;
  cursor: pointer;
}
.agent-action[hidden] { display: none; }
.agent-action-icon {
  font-size: 24px;
  line-height: 1;
}

/* #0163:呼叫键 = 绿胶囊「请经纪人带看」。⚠️沿用 production 的「名片行右侧」承重定位
   (原第二段是布局承重,非单纯红覆盖 —— 删光会错位、露出名片自带电话键);仅改
   红→绿、直角→胶囊、去掉 ::after「VR带看」hack(文案由 showing.js renderFab 按状态设)。 */
#call-fab { position: absolute; right: 12px; top: 48px; left: auto; bottom: auto; width: auto; max-width: 60%; z-index: 16; align-items: flex-end; pointer-events: none; }
#call-btn { width: auto; height: 44px; padding: 0 16px; justify-content: center; border: 0; border-radius: 22px; background: rgba(20,20,22,0.6); box-shadow: 0 4px 14px rgba(0,0,0,0.3); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); font-size: 14px; font-weight: 600; white-space: nowrap; }
#call-btn.online { background: var(--success); border-color: var(--success); color: #fff; }
#call-btn.offline { background: rgba(40,42,48,0.92); color: var(--text); }
#call-btn.pending { background: rgba(100,100,105,0.9); color: #fff; }
#call-btn.live { background: rgba(0,0,0,0.42); border-color: rgba(255,255,255,0.5); color: #fff; -webkit-backdrop-filter: var(--mp-blur); backdrop-filter: var(--mp-blur); }
#call-icon { display: none; }
#call-cancel { color: #fff; background: rgba(0,0,0,0.4); border-radius: 12px; margin-top: 4px; padding: 4px 10px; }
#call-toast { bottom: calc(184px + var(--safe-bottom)); }

#price-card {
  position: relative;
  z-index: auto;
  left: auto;
  right: auto;
  bottom: auto;
  max-height: none;
  overflow: visible;
  padding: 10px 18px calc(16px + var(--safe-bottom));
  border-radius: 5px 5px 0 0;
  background: rgba(0,0,0,0.48);
}
.more-row {
  display: block;
  width: 100%;
  border: 0;
  background: transparent;
  text-align: center;
  color: rgba(255,255,255,0.90);
  font-size: 15px;
  font-weight: 750;
  margin-bottom: 8px;
  cursor: pointer;
}
.price-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}
.price-value {
  color: #fff;
  font-size: 28px;
  line-height: 1.05;
  font-weight: 900;
}
.price-label {
  margin-top: 5px;
  color: rgba(255,255,255,0.52);
  font-size: 14px;
  font-weight: 800;
}
#listing-detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 22px;
  margin-top: 22px;
  color: rgba(255,255,255,0.90);
}
#listing-detail-grid div {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  gap: 10px;
  align-items: baseline;
}
/* #0206 ①(7a53293 从上线起就没生效的根因):上面这条 display:grid 压过了 [hidden] 的
   浏览器默认样式 → viewer.js renderPriceCard 的 `row.hidden = !has` 白设,空字段行照显,
   露出 index.html 的默认占位「—」(Leo 真机 12 项里 7 项)。 */
#listing-detail-grid div[hidden] { display: none; }
#listing-detail-grid span {
  color: rgba(255,255,255,0.42);
  font-size: 15px;
  font-weight: 800;
}
#listing-detail-grid strong {
  color: #fff;
  font-size: 17px;
  font-weight: 850;
}
.viewer-version {
  margin-top: 4px;
  color: rgba(255,255,255,0.42);
  font: 10px ui-monospace, SFMono-Regular, Menlo, monospace;
}

#fab-col {
  display: none;
  top: calc(154px + var(--safe-top));
  bottom: auto;
  right: 13px;
}
#nav-btn {
  width: 44px;
  height: 44px;
  color: #fff;
}
.fab { display: none; }

@media (max-width: 390px) {
  #topbar { grid-template-columns: 44px minmax(0, 1fr) 100px; }
  #topbar .title { font-size: 16px; }
  #scene-title { font-size: 20px; left: 16px; }
  #map-card { left: 16px; width: 142px; }
  #room-strip { gap: 22px; }
  .room-tab { font-size: 17px; }
  .price-value { font-size: 25px; }
  #listing-detail-grid { gap: 12px 14px; }
  #listing-detail-grid strong { font-size: 16px; }
}

/* ============================================================================
 * #0163 Matterport 黑白灰高端皮肤(覆盖层,放最后 → 生效)。
 * 界面纯黑白灰 · 半透明磨砂浮控 · 衬线标题/价格 + 字距标签 · 细线 · 留白。
 * 仅保留一个克制的「在线」白点(#follow-bar)。VR 照片保持彩色(内容,不去饱和)。
 * 缩略图 reel 用 p.preview(全景首帧),由 viewer.js renderRoomStrip 注入 background-image。
 * ========================================================================== */
:root {
  --mp-glass: rgba(255,255,255,0.13);
  --mp-line: rgba(255,255,255,0.32);
  --mp-blur: blur(13px) saturate(120%);
  --mp-mute: rgba(255,255,255,0.78);
}
/* 磨砂浮控统一皮肤 */
#back-btn, #tools-btn, #close-btn, #share-float, #measure-float {
  background: var(--mp-glass) !important; border: 0.5px solid var(--mp-line) !important;
  -webkit-backdrop-filter: var(--mp-blur); backdrop-filter: var(--mp-blur);
  color: #fff !important; box-shadow: none !important;
}
/* 顶栏:衬线空间名 */
#topbar .title { font-family: Georgia, "Songti SC", "STSong", "Noto Serif SC", serif; font-weight: 400; letter-spacing: 0.3px; text-shadow: 0 1px 6px rgba(0,0,0,0.5); }
/* 底部 sheet:克制暗底 + 轻字重 + 衬线价格 + 字距标签 */
#agent-card { background: rgba(0,0,0,0.34); border-radius: 4px; }
.agent-name { font-weight: 500; letter-spacing: 0.3px; }
.agent-role { color: var(--mp-mute); font-weight: 400; letter-spacing: 0.5px; }
.agent-avatar { border: 1px solid rgba(255,255,255,0.6); }
#price-card { background: rgba(0,0,0,0.4); }
.more-row { font-weight: 400; letter-spacing: 1px; color: var(--mp-mute); }
.price-value { font-family: Georgia, "Songti SC", "STSong", "Noto Serif SC", serif; font-weight: 400; letter-spacing: 0.3px; }
.price-label { font-weight: 400; letter-spacing: 1.5px; text-transform: uppercase; color: rgba(255,255,255,0.5); font-size: 11px; }
/* 高光缩略图条(room-strip → reel):缩略图=p.preview(JS 注入 background-image) */
#room-strip { gap: 8px; padding: 2px 4px 4px; }
.room-tab {
  position: relative; flex: 0 0 auto; width: 64px; height: 46px; border-radius: 4px;
  overflow: hidden; padding: 0; background: var(--surface-2); background-size: cover;
  background-position: center; border: 1.5px solid transparent; box-shadow: none; font-size: 0; text-shadow: none;
}
.room-tab::after {
  content: attr(data-name); position: absolute; left: 5px; right: 4px; bottom: 3px; font-size: 9px;
  font-weight: 400; letter-spacing: 0.4px; color: #fff; text-align: left;
  text-shadow: 0 1px 3px rgba(0,0,0,0.85); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.room-tab.active { border-color: #fff; }
/* CTA:在线=白实底高级直角;离线/接通=磨砂 */
#call-btn { border-radius: 4px; letter-spacing: 0.5px; font-weight: 500; box-shadow: 0 4px 16px rgba(0,0,0,0.28); }
#call-btn.online { background: #fff !important; border-color: #fff !important; color: #111 !important; }
#call-btn.offline { background: var(--mp-glass) !important; border: 0.5px solid var(--mp-line) !important; -webkit-backdrop-filter: var(--mp-blur); backdrop-filter: var(--mp-blur); color: #fff !important; }
#call-btn.pending { background: var(--mp-glass) !important; color: var(--mp-mute) !important; }

/* ============================================================================
 * #0163 pass3 精修(对齐 LoopNet × Matterport 实参考):衬线放大 · 大写字距标签 ·
 * 细环 loading · 极简 · 灭所有残留彩色(红 spinner/error/modal + 彩色 emoji 灰度)。
 * ========================================================================== */
/* 1) 加载/错误浮层 → 黑白细线(细环 spinner + 大写字距标签) */
.spinner { width: 32px; height: 32px; border: 2px solid rgba(255,255,255,0.16); border-top-color: #fff; }
.overlay-text { letter-spacing: 2.5px; text-transform: uppercase; font-size: 11px; color: rgba(255,255,255,0.72); }
.overlay-icon { background: transparent; border: 1.5px solid rgba(255,255,255,0.55); color: #fff; font-weight: 400; }
.overlay-title { font-family: Georgia, "Songti SC", "STSong", serif; font-weight: 400; letter-spacing: 0.3px; }
/* 2) 顶栏标题放大 + 场景房名衬线优雅 */
#topbar .title { font-size: 20px; }
#scene-title { font-family: Georgia, "Songti SC", "STSong", serif; font-weight: 400; font-size: 26px; letter-spacing: 0.3px; text-shadow: 0 2px 10px rgba(0,0,0,0.45); }
/* 3) 名片:角色大写字距 + 灰度化彩色 emoji(☎💬📞 → 灰) */
.agent-role { text-transform: uppercase; letter-spacing: 1.5px; font-size: 10px; }
.agent-action { color: #fff; }
.agent-action-icon, #call-icon, .fab-icon { filter: grayscale(1) brightness(1.35); }
/* 4) 弹窗 → 黑白极简,主按钮白实底 */
.modal-card { background: #141416; border: 0.5px solid rgba(255,255,255,0.12); border-radius: 6px; }
.modal-title { letter-spacing: 0.5px; filter: grayscale(1); }
.modal-close { background: #fff; color: #111; border-radius: 4px; font-weight: 500; letter-spacing: 0.5px; }
.modal-later { border-radius: 4px; letter-spacing: 0.5px; }
/* 5) reel 标签字距 + 价格细节标签字距 + 藏调试版本号 */
.room-tab::after { letter-spacing: 1px; }
#listing-detail-grid span { letter-spacing: 0.5px; }
.viewer-version { display: none; }

/* ============================================================================
 * #0163 pass3.2 简化(Leo 真机反馈):去半透明面板底 · 去缩略图小图 · 修楼层选择器
 * 与展开明细重叠 · 减负要简洁(贴 Matterport 极简:文字浮屏无框)。
 * ========================================================================== */
/* 1) 去半透明面板底 → 文字直接浮全景(加投影保可读,不要框) */
#map-card, #agent-card, #price-card { background: transparent !important; }
.agent-name, .agent-role, .price-value, .price-label, .more-row, .room-name, .room-area,
#listing-detail-grid span, #listing-detail-grid strong, #scene-title {
  text-shadow: 0 1px 6px rgba(0,0,0,0.9), 0 0 2px rgba(0,0,0,0.6) !important;
}
/* 2) 小图不要:房间条 → 干净文字(无缩略图 / 无框 / 无底) */
.room-tab { background: transparent !important; background-image: none !important; width: auto !important;
  height: auto !important; border: 0 !important; box-shadow: none !important; font-size: 0 !important; padding: 4px 3px !important; }
.room-tab::after { content: attr(data-name) !important; position: static !important; left: auto; right: auto; bottom: auto;
  font-size: 13px !important; letter-spacing: 1px; color: rgba(255,255,255,0.8); text-shadow: 0 1px 5px rgba(0,0,0,0.9); }
.room-tab.active { border: 0 !important; }
.room-tab.active::after { color: #fff; }
#room-strip { gap: 18px; padding: 4px 4px 6px; }
/* 3) 修重叠:展开明细时淡出左侧小地图 + 楼层选择器(不再压住价格/明细文字) */
body:has(#listing-sheet.expanded) #map-card,
body:has(#listing-sheet.expanded) .floor-selector { opacity: 0; pointer-events: none; transition: opacity 0.2s; }

/* ============================================================================
 * #0163 pass3.3(Leo 真机 ②④⑤⑥):删陀螺仪/罗盘按钮 · 楼层收回小地图下方(流式,
 * 不浮·不挡底部·无半透明底)· 浮动分享/尺寸键收进 ⋯ 菜单(菜单里已有,去重)。
 * ========================================================================== */
/* ⑤ 删 pannellum 移动端"陀螺仪/罗盘"按钮(左上点了跟手机晃的) */
.pnlm-orientation-button, .pnlm-compass, .pnlm-orientation-button:hover { display: none !important; }
/* ②⑥ 楼层选择器:从浮动绝对定位 → 流在小地图下方,去半透明底 */
.floor-selector { position: static !important; left: auto !important; top: auto !important;
  background: transparent !important; padding: 8px 0 0 !important; border-radius: 0 !important;
  margin: 6px 0 0 !important; }
/* ④ 收浮动分享/尺寸按钮(菜单 ⋯ 里已有 → 去重减负) */
#share-float, #measure-float { display: none !important; }

/* ============================================================================
 * #0163 pass3.4(Leo):删顶部灰底栏(占太多屏)→ 功能浮进 VR;顶部不占整行,
 * 右上角只两个浮动键:✕(关闭)+ ⋯(菜单,默认折叠、点开显常用功能)。
 * ========================================================================== */
/* 删顶栏灰底 + 冗余标题 + 返回键(房名仍由左上 #scene-title 显;关闭/菜单浮右上) */
#topbar { background: transparent !important; padding: calc(8px + var(--safe-top)) 12px 0 !important; pointer-events: none; }
#topbar .title, #topbar .meta { display: none !important; }
#back-btn { display: none !important; }
/* 右上两个浮动键已是磨砂(#tools-btn ⋯ / #close-btn ✕);确保浮在最上、可点 */
#tools-btn, #close-btn { pointer-events: auto !important; }

/* ============================================================================
 * #0163 pass4(UX 重排·极简默认,Leo 拍板):折叠态只露 价格 + 呼叫CTA + 上滑把手;
 * 房间导航 / 经纪人 / 房源明细 全收进上滑展开。默认态砍到最简。
 * ========================================================================== */
/* 折叠态藏:房间条 / 经纪人 / 明细网格 / 单价(只留总价)*/
#listing-sheet:not(.expanded) #room-strip,
#listing-sheet:not(.expanded) #agent-card,
#listing-sheet:not(.expanded) #listing-detail-grid,
#listing-sheet:not(.expanded) .price-grid > div:nth-child(2) { display: none !important; }
/* 折叠态露出高度收小到只够「上滑把手 + 总价行」 */
#listing-sheet:not(.expanded) { transform: translateY(calc(100% - 100px - var(--safe-bottom))) !important; }
#listing-sheet:not(.expanded) .price-grid { grid-template-columns: auto !important; gap: 0 !important; }
#listing-sheet:not(.expanded) .more-row { text-align: left; }
/* CTA 移到底部行右侧(与总价并排,不再浮在名片行)*/
#call-fab { right: 14px !important; bottom: 18px !important; top: auto !important; max-width: 56% !important; }

/* ============================================================================
 * #0163 pass5(Leo 真机):底部重排 —— 上滑把手居中在上,价格(左)+ CTA(右)同一行底对齐。
 * ========================================================================== */
/* 折叠态:上滑把手居中、细 */
#listing-sheet:not(.expanded) .more-row { text-align: center !important; font-size: 11px !important; letter-spacing: 1.5px !important; padding: 0 0 8px 0 !important; margin: 0 0 4px 0 !important; }
/* 价格卡内边距收紧,价格行底对齐 */
#listing-sheet:not(.expanded) #price-card { padding: 4px 16px calc(16px + var(--safe-bottom)) 16px !important; }
#listing-sheet:not(.expanded) .price-grid { margin: 0 !important; }
#listing-sheet:not(.expanded) .price-value { line-height: 1 !important; }
/* CTA 与总价同一底线对齐 */
#call-fab { right: 16px !important; bottom: calc(20px + var(--safe-bottom)) !important; top: auto !important; }

/* ============================================================================
 * #0163 pass6(Leo 真机):① 「总价」标签 → 交易类型(出售/出租),与价格同一行底对齐;
 * ② 楼层选择器左对齐(原 align-items:stretch + 居中文本看着像居中)。
 * ========================================================================== */
/* ① 价格 + 类型(出售/出租)同一行、底线对齐(替代上下堆叠)*/
#listing-sheet:not(.expanded) .price-grid > div:first-child { display: flex !important; align-items: baseline !important; gap: 9px !important; }
#price-total-label { font-size: 12px !important; letter-spacing: 1px !important; text-transform: none !important; color: rgba(255,255,255,0.65) !important; }
/* ② 楼层按钮左对齐 */
.floor-selector { align-items: flex-start !important; }
.floor-btn { text-align: left !important; }

/* ============================================================================
 * #0163 pass3.5(审计修复 Leo 真机):灭旧白栏残留 + 隐藏 pannellum 默认控件。
 * 白药丸 = #top-actions 旧白底(L270 background:#fff) + #topbar grid(L241)把它
 * 塞进左列(标题/返回隐藏后自动落第一格);此处全压掉,✕/⋯ 复位成右上磨砂深色
 * 圆键;pannellum 自带缩放/全屏控件整盒隐藏(与我们自己的浮键重复)。
 * ========================================================================== */
/* 顶栏:去 grid、不占位、不挡点 */
#topbar { display: block !important; background: transparent !important; height: auto !important; padding: 0 !important; box-shadow: none !important; pointer-events: none !important; }
/* 杀白药丸:#top-actions 纯透明壳、静态、不再 grid 末端对齐 */
#top-actions { position: static !important; justify-self: auto !important; background: transparent !important; border: 0 !important; border-radius: 0 !important; box-shadow: none !important; padding: 0 !important; }
/* ✕ / ⋯ → 磨砂深色圆键,绝对定位浮右上(close 在 right:56,tools 在 right:14)*/
#close-btn, #tools-btn {
  position: absolute !important; z-index: 12 !important;
  top: calc(8px + var(--safe-top)) !important;
  width: 36px !important; height: 36px !important;
  display: inline-flex !important; align-items: center !important; justify-content: center !important;
  border-radius: 50% !important;
  background: rgba(0,0,0,0.42) !important;
  border: 1px solid rgba(255,255,255,0.45) !important;
  -webkit-backdrop-filter: blur(14px) saturate(120%) !important;
  backdrop-filter: blur(14px) saturate(120%) !important;
  color: #fff !important; box-shadow: none !important; line-height: 1 !important;
  cursor: pointer !important; pointer-events: auto !important;
}
#close-btn { right: 56px !important; font-size: 15px !important; }
#tools-btn { right: 14px !important; font-size: 20px !important; }
/* 下拉菜单恢复深色磨砂(撤销旧白底 L301-308)*/
#tools-menu { background: rgba(0,0,0,0.55) !important; border: 1px solid rgba(255,255,255,0.18) !important; color: #fff !important; }
#tools-menu .tool-item, .tool-item { color: #fff !important; }
/* pannellum 默认缩放/全屏控件整盒隐藏 */
.pnlm-controls-container, .pnlm-zoom-controls, .pnlm-fullscreen-toggle-button, .pnlm-orientation-button, .pnlm-compass { display: none !important; }

/* ============================================================================
 * #0163 pass7(Leo 真机):折叠底部加克制容器底 scrim + CTA 提成清晰按钮。
 * scrim 挂不被 transform 的全屏 #app::after(fixed 边到边),z=1 介于全景 canvas
 * 与漫游热点(z2/3)之间 → 托起价格/CTA、不挡房间导航、不挡主持/会议控件(z≥50)、
 * pointer-events:none 不吃上滑手势。仅折叠态显示(:has),不碰展开态/不碰漫游热点。
 * ========================================================================== */
body:has(#listing-sheet:not(.expanded)) #app::after {
  content: ''; position: fixed; left: 0; right: 0; bottom: 0;
  height: calc(165px + var(--safe-bottom));
  background: linear-gradient(to top, rgba(0,0,0,0.74) 0%, rgba(0,0,0,0.5) 36%, rgba(0,0,0,0) 100%);
  pointer-events: none; z-index: 1;
}
/* CTA「预约带看」→ 白实底清晰按钮(替掉 13% 几乎隐形的 offline 磨砂;在深 scrim 上高对比)*/
#listing-sheet:not(.expanded) #call-btn.offline {
  background: rgba(255,255,255,0.94) !important;
  border: 0 !important;
  color: #111 !important;
  box-shadow: 0 4px 16px rgba(0,0,0,0.4) !important;
}
#listing-sheet:not(.expanded) #call-btn { font-weight: 600 !important; }
/* 价格/把手坐在 scrim 基底上,投影克制即可(避免双重黑边显脏)*/
#listing-sheet:not(.expanded) .price-value,
#listing-sheet:not(.expanded) #price-total-label,
#listing-sheet:not(.expanded) .more-row { text-shadow: 0 1px 4px rgba(0,0,0,0.5) !important; }

/* ============================================================================
 * #0205 缩略图房间条(shareConfig.showThumbStrip=true 时,viewer 给 <body> 加
 * .thumb-strip)。⚠️ 只做「开启时覆盖」—— 上面 #0163 pass3.2 那段(纯文字条)是
 * **关闭=缺省**时的正确样式,是 Leo 真机拍板的,绝不删。pass3.2 用了整串
 * !important,所以这里必须 选择器权重更高(body.x .room-tab) + 同样 !important。
 * 缩略图本身来自 JS 写的 --room-thumb(见 renderRoomStrip):inline background-image
 * 压不过 pass3.2 的 !important,自定义属性可以。
 * ========================================================================== */
body.thumb-strip #room-strip { gap: 8px; padding: 2px 4px 4px; }
body.thumb-strip .room-tab {
  width: 64px !important; height: 46px !important; padding: 0 !important;
  background-color: var(--surface-2) !important;
  background-image: var(--room-thumb, none) !important;
  /* 🔴 #0221:这两条**必须** !important —— pass3.2(:797)那条是 `background:` **简写**
     带 !important,简写会把 background-size/position 一并重置成 initial(auto / 0% 0%)
     且带 !important;这里不带 !important 就永远输 ⇒ 64×46 的格子里显示 320×160 缩图的
     左上角原始像素 = 全景图天花板(Leo 真机「一片糊的米色」)。#0205 只解了 background-image
     被压的问题,漏了同一个简写也压掉 size/position。 */
  background-size: cover !important; background-position: center !important;
  border: 1.5px solid transparent !important;
}
body.thumb-strip .room-tab::after {
  position: absolute !important; left: 5px; right: 4px; bottom: 3px;
  font-size: 9px !important; letter-spacing: 0.4px; color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,0.85);
}
body.thumb-strip .room-tab.active { border-color: #fff !important; }

/* ============================================================================
 * #0206 ②(Leo 真机「上拉后文字太多挡屏、划动变差」):导航 ≠ 查阅。开关打开时
 * viewer.js 把 #room-strip 从 #listing-sheet 里搬到 #app 下(见 render()),这里给它
 * 常驻底部的定位 —— 不用上拉就能跳点位。⚠️ 只匹配「搬出来后」的 `#app > #room-strip`,
 * 关闭(缺省)时条子仍在 sheet 里,这些规则一条都不命中 ⇒ 逐像素零回归。
 * 让位关系:sheet 折叠态可见高度 = 100px + safe-bottom(pass4)→ 条子 bottom 取
 * 112px + safe-bottom,压在「上滑查看更多」把手之上 12px;「预约带看」CTA 在
 * bottom:20px+safe(高 44 → 顶边 64+safe)之下,互不遮挡;home indicator 在 safe 区内。
 * ========================================================================== */
/* #0219:hideListingInfo=true 时条子同样被搬到 #app(见 render() 的 dock),复用同一段
   定位 —— 否则藏了 #price-card 就没了展开入口,折叠态 :837 又把条子 display:none,
   点位导航会整个够不着。两个类共用一段样式,避免定位规则分叉。 */
body.thumb-strip #app > #room-strip,
body.hide-listing #app > #room-strip {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(112px + var(--safe-bottom));
  z-index: 16;
  padding: 0 12px;
  gap: 8px;
}
/* 信息面板展开 = 在「查阅」不在「逛」→ 常驻条收起,不与面板抢地盘(明确选「收起」,
   不叠不打架;收起面板即回来)。 */
body.thumb-strip:has(#listing-sheet.expanded) #app > #room-strip,
body.hide-listing:has(#listing-sheet.expanded) #app > #room-strip { display: none; }

/* ============================================================================
 * #0221 ② 房间条横滚可感知(Leo 真机:11 个 tab 内容宽 808px vs 屏宽 390px,一屏只
 * 看得到 5 个,不知道右边还有)。Leo 选 A 方案:保持**一行横滚** + 加滚动提示
 * (不换行 —— 条子常驻压在全景上,多一行 = 永久少一块看房画面)。
 * 实现要点:
 *   · 遮罩挂**滚动容器自身**(mask 相对元素框,不随内容滚);`::after` 伪元素会跟着
 *     内容一起滚走,除非再包一层外壳 —— 不值得多一层 DOM。
 *   · 不写死双边渐变:滑到底还淡右边 / 没滑过就淡左边都是错观感 ⇒ 两个类
 *     `can-scroll-left` / `can-scroll-right` 由 viewer.js 按真实 scrollLeft 切。
 *   · 🔴 遮罩绝不吃点击:mask 只改 alpha,**完全不参与命中测试**,被淡化的 tab 照样
 *     点得动(这里一个字都没碰 pointer-events)。
 *   · 内容不溢出(3~5 个点位)⇒ 两个类都不加 ⇒ 一条规则都不命中 = 逐像素零回归。
 * 缩略图条与纯文字条(缺省)共用这段 —— 两种模式都是同一个 `#room-strip` 滚动容器。
 * ========================================================================== */
#room-strip.can-scroll-right:not(.can-scroll-left) {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent 100%);
          mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent 100%);
}
#room-strip.can-scroll-left:not(.can-scroll-right) {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 32px);
          mask-image: linear-gradient(to right, transparent 0, #000 32px);
}
#room-strip.can-scroll-left.can-scroll-right {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 32px, #000 calc(100% - 32px), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, #000 32px, #000 calc(100% - 32px), transparent 100%);
}

/* 角落版本标记:真机一眼确认部署版本。极小、半透明、不挡点击、避开刘海安全区。 */
#ver-tag {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 4px);
  left: calc(env(safe-area-inset-left, 0px) + 6px);
  z-index: 2000;
  font: 500 9px/1 -apple-system, system-ui, monospace;
  letter-spacing: 0.5px;
  color: rgba(255, 255, 255, 0.35);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  pointer-events: none;
  user-select: none;
}

/* ─── 娃娃屋 3D 视图(ADR-0021 route A, v1)─────────────────────────── */
#dollhouse-overlay { position: fixed; inset: 0; z-index: 105; background: #1a1d22; }
#dollhouse-overlay[hidden] { display: none; }
#dollhouse-canvas { display: block; width: 100%; height: 100%; touch-action: none; }
#dollhouse-close {
  position: absolute; z-index: 2; top: calc(10px + var(--safe-top)); left: 14px;
  height: 34px; padding: 0 14px 0 10px; border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.22); background: rgba(0,0,0,0.45); color: #fff;
  font-size: 14px; line-height: 34px; cursor: pointer;
}
#dollhouse-hint {
  position: absolute; z-index: 2; left: 50%; transform: translateX(-50%);
  bottom: calc(18px + var(--safe-bottom)); padding: 6px 14px; border-radius: 14px;
  background: rgba(0,0,0,0.45); color: rgba(255,255,255,0.85); font-size: 12px;
  pointer-events: none; white-space: nowrap;
}
#dollhouse-loading { z-index: 3; background: #1a1d22; }
#dollhouse-loading[hidden] { display: none; }
