/* ==========================================================================
   AI伴途 · 导览页 V3 · 浅色主题        文件：guide3.css
   --------------------------------------------------------------------------
   依据设计稿 docs/design/v3-light/ 1:1 落地：
     L-S1 待命 / L-S2 跟随安静 / L-S3 讲解中 / L-S4 暂停 / L-S5 结束确认（司机模式）
     P-乘客主界面 / P-切向乘客确认卡（乘客模式）
   设计基准 375×812；本工程 1rem = 100vw/7.5（375px 宽时 1rem = 50px）。
   所有几何与色值均取自导出 SVG 的实测值（圆角 / 坐标 / 十六进制色），非估算。
   本文件在 app.css 之后加载 —— 旧的 .navpill / .livepanel / .lp- 系列 / .boot / .idle
   等整块样式因 HTML 里已无对应类名而自然失效，不构成残留。

   引擎约定（pages.js 绑定，不得改名）：
   · ID：g-* / lp-* 全集
   · 结构类：.map-tools（手势放行）、.mp-item/.mp-dot/.mp-name（足迹标注）、
     .notice-text（g-n-bg 内文查询）
   · 状态类：is-live is-open is-flip is-pop is-holding free has-map mp-on
     notice-auto is-gone btn-disabled on
   ========================================================================== */

/* ==========================================================================
   1. 令牌与根容器
   ========================================================================== */
/* 色板同时挂到 :root —— 切成乘客模式的确认卡（#modal 内）位于 .g3-root 之外，
   变量若只定义在 .g3-root 上，那里的 linear-gradient(var(--g3-purple-*)) 会因
   变量未定义而整条声明失效（按钮变成空白）。挂在 :root 后任意节点都能取到。 */
:root {
  /* —— 浅色主题色板（SVG 实测） —— */
  --g3-bg:        #F5F8F6;   /* 页面底色 */
  --g3-bg-pass:   #F1F5F3;   /* 乘客模式页面底色 */
  --g3-line:      #DDE4E0;   /* 卡片描边 */
  --g3-ink:       #12201C;   /* 主文字 */
  --g3-ink-2:     #3D514B;   /* 次要文字 */
  --g3-ink-3:     #5A6B65;   /* 说明文字 */
  --g3-ink-4:     #8A9A94;   /* 弱化文字 */
  --g3-green:     #0E6B57;
  --g3-green-d:   #0A4F41;
  --g3-green-soft:#E6EFEC;   /* 绿色浅底（状态胶囊 / 激活胶囊） */
  --g3-green-line:#ACD3C8;   /* 绿色描边 */
  --g3-g1:        #13A483;   /* 主按钮渐变起 */
  --g3-g2:        #094F41;   /* 主按钮渐变止 */
  --g3-green-g1:  #13A483;   /* 同上，与 purple-g1/g2 命名对齐 */
  --g3-green-g2:  #094F41;
  --g3-orange:    #E08A2E;
  --g3-orange-d:  #B4610F;
  --g3-orange-soft:#FDF0E1;  /* 橙色浅底（正在讲解胶囊） */
  --g3-orange-soft2:#FDF3E1; /* 橙色浅底（已暂停胶囊） */
  --g3-purple:    #6A5ADF;
  --g3-purple-d:  #4B3FB0;
  --g3-purple-g1: #7969EF;
  --g3-purple-g2: #5A4AD7;
  --g3-shadow:    0 0.12rem 0.26rem rgba(27, 59, 49, .10);
  --g3-shadow-sm: 0 0.06rem 0.18rem rgba(27, 59, 49, .08);
  --g3-r:         0.40rem;   /* 卡片圆角（设计稿实测 20px） */
  --g3-r-lg:      0.44rem;   /* 大卡圆角（设计稿实测 22px） */
}

/* 旧注释：色板原定义于此 —— 现改挂 :root 以覆盖 #modal 内的确认卡。
   卡片圆角（设计稿实测 20~22px → 0.40~0.44rem） */
.g3-root {
  /* 底部卡片底边距：底栏间距 + 底栏高 + 安全区 + 0.16rem 视觉间隙
     （设计稿：卡片底 736 / 底栏顶 744 / 底栏底 800 / 屏底 812） */
  --g3-bottom:    calc(var(--tabbar-gap) + var(--tabbar-h) + env(safe-area-inset-bottom) + 0.16rem);

  /* 当前模式强调色：默认司机模式 = 绿 */
  --g3-accent:      var(--g3-green);
  --g3-accent-d:    var(--g3-green-d);
  --g3-accent-soft: var(--g3-green-soft);
  --g3-accent-line: var(--g3-green-line);
  --g3-accent-g1:   var(--g3-g1);
  --g3-accent-g2:   var(--g3-g2);

  position: relative;
  height: 100vh; height: 100dvh;
  overflow: hidden;
  background-color: var(--g3-bg);
  color: var(--g3-ink);
  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", "Microsoft YaHei", sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* —— 乘客模式：强调色整体切紫（P-乘客主界面） —— */
.g3-root.g3-passenger {
  --g3-bg:          var(--g3-bg-pass);
  --g3-accent:      var(--g3-purple);
  --g3-accent-d:    var(--g3-purple-d);
  --g3-accent-soft: rgba(106, 90, 224, .14);
  --g3-accent-line: rgba(106, 90, 224, .34);
  --g3-accent-g1:   var(--g3-purple-g1);
  --g3-accent-g2:   var(--g3-purple-g2);
}

/* ==========================================================================
   2. 地图层
   ========================================================================== */
.g3-map {
  position: absolute; left: 0; right: 0; top: 0; bottom: 0;
  overflow: hidden;
  background-color: #E7EDEA;
  /* 地图要自己吃掉拖动 / 捏合手势，否则浏览器会拿去滚页面 */
  touch-action: none;
}
/* ⚠️⚠️⚠️ z-index 必须有值 —— 这条是「所有按钮都点不动」的唯一原因，绝对不要删。
   腾讯地图 GL 会在容器内部插入一个 `z-index:1000` 的全屏 UI 层（内含 logo 与
   交互层，pointer-events:auto）。本节点若为 z-index:auto 就**不构成层叠上下文**，
   那一层会「逃逸」到整个 App 之上：elementFromPoint 全屏任意点都命中它，
   表现为右侧工具列 / 开始陪伴 / 底栏 / 司机乘客分段**全部点不动**，
   而控制台零报错、CSS 与 JS 都看不出任何异常（真机触摸尤其明显）。
   给了 z-index 后它被锁在容器内部，本文件 z3~z9 的兄弟节点自然都在它之上。
   ⚠️ 旧版 app.css 的 `.map-canvas` 正是靠 `z-index:0` 做到这一点的，重写时漏了。 */
.g3-canvas { position: absolute; inset: 0; z-index: 1; overflow: hidden; }
/* 静态图兜底（矢量图不可用时才显示）：
   · pointer-events 必须 none —— 它 positioned 且 DOM 在 canvas 之后，
     否则会盖住矢量画布并吞掉全部 touch/pointer 事件（「地图看得见拖不动」老坑）；
   · z-index 必须低于 .g3-canvas —— 否则矢量图好了以后它仍压在真地图上，
     观感就是「一张模糊的图片」，正是新装机首次进入时的那个问题。 */
.g3-mapimg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: none;
  z-index: 0; pointer-events: none;
  /* 去噪（V3.1）：腾讯静态图接口**不能**关掉底图自带的 POI 文字，
     maptype 只有 roadmap / satellite / hybrid 三种，没有样式参数 ——
     一屏下来几十个商户、医院、大厦名糊在一起，正是「密密麻麻很丑」的来源。
     既然去不掉，就整张压成「纸底」：去饱和 + 提亮 + 降对比 + 半透明，
     只留路网骨架做空间参照，文字噪声退到几乎读不出来。
     ⚠️ 只能整体压，不能只压文字 —— 但静态底图的路网本就是白线，
        压狠了会跟浅色背景糊在一起，所以对比度不要低于 .5。 */
  filter: saturate(.3) brightness(1.08) contrast(.58);
  opacity: .52;
}
.g3-map.has-map .g3-mapimg { display: block; }
/* touch-action 不继承，必须显式给到画布及其内部节点 */
.g3-canvas, .g3-canvas * { touch-action: none; }

/* 顶部 / 底部渐隐：把真实底图的杂乱边缘压掉，让白卡「落」在干净的底上
   （设计稿：顶部 180px 由 #DFE9E4 渐隐；底部 312px 渐白） */
/* ⚠️ z-index 必须 ≥2：地图画布是 z-index:1，没有显式值就会被压到画布下面看不见 */
.g3-map-veil { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.g3-map-veil::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 3.4rem;
  background: linear-gradient(180deg, rgba(223, 233, 228, .95) 0%, rgba(241, 246, 244, 0) 100%);
}
.g3-map-veil::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 4.6rem;
  background: linear-gradient(0deg, rgba(245, 248, 246, .92) 0%, rgba(245, 248, 246, 0) 100%);
}
.g3-attrib {
  position: absolute; left: 0.24rem; bottom: 0.12rem; z-index: 3;
  font-size: 0.18rem; color: rgba(18, 32, 28, .34); pointer-events: none;
}
/* —— 隐藏腾讯地图自带的 logo 控件 ——
   GL SDK 默认在左下角塞一个「彩色图标 + 腾讯地图字标 + ©2026 Tencent - GS(...)」
   的控件（在 #g-tmap 内部，随 SDK 版本可能换类名，故三条选择器一起兜）。
   本产品的署名由 .g3-attrib 那一行极简小字承担（设计稿左下角就是这行）。 */
#g-tmap .logo-text,
#g-tmap a[href*="map.qq.com"],
#g-tmap img[src*="logo_def"] { display: none !important; }

/* ==========================================================================
   3. 定位标记：圆形头像 + 顶部朝向小三角（高德样式）
   -------------------------------------------------------------------------
   用户指定「改回以前那种」，即 V2 的 .map-heading / .mh-* 那一套 ——
   它的完整样式仍在 app.css 里（第 793 行起），本文件只补 V3 的层序，
   **不要**在这里重写一套，否则两处样式各改一半必然漂移。

   ⚠️ 外框尺寸必须是 0.8rem —— 引擎 _positionCompass 用 `0.8 × 根字号`
      算圆心 (left, top)，容器尺寸一变标记就整体偏心。
   ⚠️ pointer-events 必须 none（app.css 已在 .map-heading 上声明），
      否则地图中心区域拖不动（老坑）。
   ⚠️ z 序：V3 的地图层是 canvas(z1) / veil(z2) / attrib(z3)，
      app.css 里 .map-heading 是 z3，会被底部渐隐盖住 → 这里提到 z4。
   ========================================================================== */
.g3-root .map-heading { z-index: 4; }

/* ==========================================================================
   4. 地图上的点位气泡（正在讲解 / 已讲解）
   ========================================================================== */
.g3-poi {
  position: absolute; left: 0; top: 0;
  width: 0; height: 0; z-index: 6;
  pointer-events: none;
}
/* 默认气泡在锚点之上；落点圆点贴住锚点 */
.g3-poi-in {
  position: absolute; left: 0; bottom: 0;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center;
}
.g3-poi.is-flip .g3-poi-in {
  bottom: auto; top: 0;
  flex-direction: column-reverse;
}
.g3-poi-card {
  pointer-events: auto;
  max-width: 3.4rem;
  padding: 0.22rem 0.26rem;
  background-color: #FFFFFF;
  border: 1px solid var(--g3-line);
  border-radius: 0.32rem;
  box-shadow: var(--g3-shadow);
  margin-bottom: 0.18rem;
}
.g3-poi.is-flip .g3-poi-card { margin: 0.18rem 0 0; order: 1; }
.g3-poi-live {
  display: flex; align-items: center; gap: 0.1rem;
  font-size: 0.22rem; font-weight: 600; color: var(--g3-green);
}
.g3-poi-live i {
  width: 0.12rem; height: 0.12rem; border-radius: 50%;
  background-color: currentColor; flex: none;
}
.g3-poi-live.is-done { color: var(--g3-ink-4); }
/* 「已讲解」点开后的卡：与底部讲解卡同款五段（复用 .g3-n* 那一套类）。
   ⚠️ 宽度必须给到 6.86rem（= 设计稿那张卡的 343px）—— 原先沿用气泡的
   `max-width: 3.4rem`，五段内容在 170px 里全被折成两行（「已讲解 · 人文历史」
   「查看详情」都断行），与设计稿完全不是一个东西。
   窄屏由 max-width 兜住；引擎侧的水平钳制半径见 _renderPlayedTag。 */
#g-playedtag .g3-poi-card {
  width: 6.86rem;
  max-width: calc(100vw - 0.64rem);
  padding: 0.32rem 0.32rem 0.28rem;
  border: none;
  border-radius: var(--g3-r-lg);
}
#g-playedtag .g3-nfoot { justify-content: space-between; }
#g-playedtag .g3-poi-cta { flex: 1; }
.g3-poi-name {
  margin-top: 0.06rem;
  font-size: 0.36rem; font-weight: 700; line-height: 1.25; color: var(--g3-ink);
}
.g3-poi-row { display: flex; align-items: center; gap: 0.16rem; margin-top: 0.18rem; }
.g3-poi-photo {
  display: flex; align-items: center; gap: 0.06rem;
  height: 0.56rem; padding: 0 0.2rem;
  border: 1px solid var(--g3-line); border-radius: 999px;
  font-size: 0.24rem; font-weight: 600; color: var(--g3-ink-2);
}
.g3-poi-cta {
  display: flex; align-items: center; justify-content: center;
  height: 0.56rem; padding: 0 0.24rem;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--g3-accent-g1), var(--g3-accent-g2));
  color: #FFFFFF; font-size: 0.24rem; font-weight: 600;
}
.g3-poi-stem { width: 1px; height: 0.14rem; background-color: var(--g3-line); }
.g3-poi.is-flip .g3-poi-stem { order: 2; }
.g3-poi.is-flip .g3-poi-dot { order: 3; }
/* 讲解落点标记：橙色同心圆（设计稿 L-S3 实测 —— 外圈 r16 / 内圈 r8，同心）。
   原先是 0.2rem 的单颗绿点，既不是同心也没有光环，与稿子差得较远。 */
.g3-poi-dot { position: relative; width: 0.32rem; height: 0.32rem; flex: none; }
.g3-poi-dot::before {   /* 外圈光环（r16 → 直径 0.64rem） */
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 0.64rem; height: 0.64rem; margin: -0.32rem 0 0 -0.32rem;
  border-radius: 50%; background-color: rgba(224, 138, 46, .22);
}
.g3-poi-dot i {
  position: absolute; inset: 0; border-radius: 50%;
  background-color: var(--g3-orange); opacity: 0;
}
.g3-poi-dot::after {
  content: ''; position: absolute; inset: 0;
  border-radius: 50%; background-color: var(--g3-orange);
}
.g3-poi-dot-done::before { background-color: rgba(138, 154, 148, .18); }
.g3-poi-dot-done::after { background-color: var(--g3-ink-4); }
/* 讲解落点：脉冲扩散（三段错峰） */
.g3-poi.is-pop .g3-poi-dot i { animation: g3Pulse 2.1s ease-out infinite; }
.g3-poi.is-pop .g3-poi-dot i:nth-child(2) { animation-delay: .7s; }
.g3-poi.is-pop .g3-poi-dot i:nth-child(3) { animation-delay: 1.4s; }
@keyframes g3Pulse {
  0%   { transform: scale(.9); opacity: .5; }
  100% { transform: scale(2); opacity: 0; }
}
.g3-poi.is-pop .g3-poi-card { animation: g3Pop .26s cubic-bezier(.22, .9, .26, 1.18); }
@keyframes g3Pop {
  0%   { transform: translateY(0.14rem) scale(.94); opacity: 0; }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}

/* ==========================================================================
   5. 右侧悬浮工具列（定位 / 方向 / 音量 / 图层）
   -------------------------------------------------------------------------
   ⚠️ 外层保留引擎约定类名 .map-tools（_bindMapGestures 靠 closest 放行手势）。
   ========================================================================== */
.map-tools {
  position: absolute; right: 0.32rem;
  /* 设计稿实测：4 个钮 y = 300 / 352 / 404 / 456（步进 52 = 40 高 + 12 间距），
     整列中心在 398 而非屏幕正中 406，故用 2.12rem（= 106px = 196/2 + 8）。
     ⚠️ 必须把 app.css 里那句 `transform: translateY(-50%)` 顶掉 ——
     否则再上移半个列高，整列会比设计稿高约 100px（真机上工具钮快贴到顶部分段控件）。 */
  top: calc(50% - 2.12rem);
  transform: none;
  z-index: 8;
  display: flex; flex-direction: column; gap: 0.24rem;
}
.g3-tool {
  width: 0.8rem; height: 0.8rem;
  display: flex; align-items: center; justify-content: center;
  background-color: #FFFFFF;
  border-radius: 0.24rem;
  box-shadow: var(--g3-shadow);
  color: var(--g3-ink-2);
  cursor: pointer;
}
.g3-tool svg { width: 0.4rem; height: 0.4rem; display: block; }
.g3-tool.on { color: var(--g3-orange); }
/* 关闭态：整钮褪成浅底浅图标（设计稿里图层钮的常态就是白底灰图标，
   所以「开启」不加色，「关闭」才用褪色区分） */
.g3-tool.g3-tool-dim { background-color: #F1F5F3; color: var(--g3-ink-4); box-shadow: none; }
.g3-tool.is-off { display: none; }
.g3-tool:active { transform: scale(.94); }

/* ==========================================================================
   6. 当天已讲解的点位标注
   ========================================================================== */
.g3-played { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.mp-item {
  position: absolute; transform: translate(-50%, -50%);
  display: flex; align-items: center; gap: 0.08rem;
  max-width: 2.4rem;
  height: 0.44rem; padding: 0 0.16rem;
  background-color: rgba(255, 255, 255, .96);
  border: 1px solid var(--g3-line);
  border-radius: 999px;
  box-shadow: var(--g3-shadow-sm);
  pointer-events: auto;
  font-size: 0.22rem; color: var(--g3-ink-2);
}
.mp-dot { width: 0.14rem; height: 0.14rem; border-radius: 50%; flex: none; }
.mp-name { font-weight: 600; }
.mp-item.mp-on {
  background-color: var(--g3-green);
  border-color: var(--g3-green);
  color: #FFFFFF;
}

/* —— 视野内的优质点位（本地 POI 库 S / A 档）——
   与「当天已讲解」分两层：那层是本趟讲过的足迹（z 3），这层是**值得一看**的点位（z 2），
   压在足迹下面 —— 两个标注叠在一起时，用户刚听过的那条必须盖在最上面。
   只画当前地图视野内的，拖动 / 缩放停下来才加载新的，不会密密麻麻铺满全城。
   ⚠️ 整层 pointer-events: none —— 标注只用来看，**绝不能吃地图的触摸事件**
      （吃掉的后果是「地图看得见却拖不动」，这是踩过的坑）。 */
.g3-viewpois { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
/* 2026-10-14（需求 8）：**只画类型图标，不画名称**。
   原先是「小圆点 + 名称」的白色药丸 —— 一屏 60 条铺开就是一片白字（用户截图反馈
   「点位显示名称显得杂乱」）。现在收成一颗圆形图标钮：**底色 = 类别色、图形 = 类型**，
   两个通道同时区分（红绿色盲也分得开），不识字也能看出「这是桥 / 这是博物馆」。
   ⚠️ 名称没有删掉，只是不再铺在地图上 —— 点击弹出的气泡、以及详情卡片里都在。
   ⚠️ 尺寸必须克制：一屏最多 60 颗，做成大图钉会重新变成用户抱怨的那种「花」。
      圆钮 0.5rem（25px@375），热区靠 ::after 外扩到约 39px —— **视觉小、点得中**。 */
.vp-item {
  position: absolute; transform: translate(-50%, -50%);
  width: 0.5rem; height: 0.5rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  /* 底色由 JS 内联写 category 色；这里给兜底，缺了就还是品牌绿 */
  background-color: var(--vp-c, var(--g3-green));
  /* 白描边是「压在地图上的标记」的通用语言：深色底图上也留得下一圈边 */
  border: 1px solid rgba(255, 255, 255, .96);
  box-shadow: 0 1px 4px rgba(20, 40, 34, .28);
  pointer-events: auto;   /* 允许点击，但自身很小，不会大面积阻挡地图拖动 */
}
.vp-ico { width: 0.3rem; height: 0.3rem; display: block; }
/* 热区外扩：视觉仍是 0.5rem，手指点得中（≈39px，接近 44px 的可点建议值）。 */
.vp-item::after {
  content: ''; position: absolute; inset: -0.14rem; border-radius: 50%;
}
/* S 档（最高价值）只大一点点、白边厚一点点 —— 档位差异做重了，
   整屏又是用户抱怨的那种「花」。z-index 保证与 S 档重叠时它在上。 */
.vp-item.is-key { width: 0.56rem; height: 0.56rem; border-width: 1.5px; z-index: 1; }
.vp-item.is-key .vp-ico { width: 0.34rem; height: 0.34rem; }

/* 点击优质点位后弹出的详情气泡：与 #g-poitag / #g-playedtag **同一套白卡语言**，
   只是不带直播态（.is-live）。
   ⚠️ 2026-10-13 改版：原先是紫色渐变卡（#8A6DFF → #6B4EE6）+ 半透明白按钮。
      用户反馈「紫色跟整体 ui 不搭配」—— 站得住脚：全站的强调色只有品牌绿（主）
      和讲解橙（正在讲解），紫色只在**乘客模式**临时顶替 accent，而这张卡把它
      写死成常驻色，等于在地图上插了一块异色。
      现在卡片回到白底 + 细描边，强调只落在「查看详情」的品牌绿渐变上，
      三张气泡从此完全同族 —— 一眼能看出「这是同一个东西的三个态」。 */
.g3-vpoi .g3-poi-card { background-color: #FFFFFF; }
/* 落点标记用**品牌绿**：橙色在本项目专指「正在讲解」，这张卡恰恰不是；
   已讲解的落点是灰的（.g3-poi-dot-done）—— 绿正好补上「值得看但没在讲」这一档。
   ⚠️ 三处都要覆盖（::before 光环 / ::after 实心点 / i 脉冲圈），漏一处就会
      露出一圈橙 —— 而「漏一处」在这里只表现为一个很小的橙点，截图很难发现。 */
.g3-vpoi .g3-poi-dot::before { background-color: rgba(14, 107, 87, .18); }
.g3-vpoi .g3-poi-dot::after { background-color: var(--g3-green); }
.g3-vpoi .g3-poi-dot > i { background-color: var(--g3-green); }

/* 「查看详情」按钮：**直接复用 .g3-poi-cta**（与 #g-playedtag 同一个绿渐变胶囊）。
   ⚠️ 别再单独维护一个 .g3-vp-more —— 两套样式迟早长歪，
      这正是上一版紫卡的由来：为了配紫色卡，才另写了一个半透明按钮。
   `.g3-vpfoot` 现在只负责「与上行拉开距离」这一件事。 */
.g3-vpfoot { display: flex; margin-top: 0.16rem; }
#g-vpoitag .g3-poi-cta { flex: 1; }

/* ==========================================================================
   7. 顶部：地名小字 + [指北针 · 速度 · 海拔] + 状态胶囊
   --------------------------------------------------------------------------
   ⚠️ 2026-10-13 改版（用户拍板，推翻上一版「地名 · 速度 · 海拔」合体单胶囊）：
      · 速度 / 海拔 各自独立成一个胶囊，读数放大到 0.36rem，做成仪表读数；
      · 地名降级为胶囊**上方**一行小字（不再是胶囊里的一段）；
      · 新增指北针小圆标（0.68rem 正圆），贴在速度胶囊左侧，
        针随地图旋转角转动（见 pages.js 的 _renderNorth）。
   为什么换掉合体胶囊：两个读数被压在 0.3rem 字号里、还要跟地名平分宽度，
   开车扫一眼根本分不出哪个是哪个 —— 数值得先是「读数」，其次才是「一行信息」。

   ⚠️ 但**别把速度/海拔改回上下堆叠** —— 那是更早被否掉的一版（两块内容各占一行，
      真机上像三块碎饼干）。这里要的是「同一行并排的两个读数」，版式完全不同。

   ⚠️ 顶栏因此高出一行（地名 0.3rem + 0.06rem 间距 = 0.36rem）⇒ 四处 top 必须同加：
        .g3-chip            1.02rem → 1.30rem
        .g3-notice          1.66rem → 1.94rem
        .g3-passenger .g3-notice   1.02rem → 1.30rem
        .g3-passenger .g3-pstack   1.92rem → 2.20rem
      漏任何一处，真机上状态胶囊 / GPS 提示条就会压在数值胶囊上。
      小程序端同理：`miniprogram/pages/guide/guide.js` 的 navMetrics() 里
      chipTop / noticeTop 也要一起加。
   ========================================================================== */
.g3-topbar {
  position: absolute; left: 0; right: 0; top: 0; z-index: 20;
  display: flex; align-items: flex-start;
  padding: calc(env(safe-area-inset-top) + 0.2rem) 0.32rem 0;
}
.g3-placewrap {
  display: flex; flex-direction: column; align-items: flex-start;
  min-width: 0;
}
/* 地名小字：**不是胶囊**。深色字 + 四向白色柔光 —— 压在地图路名 / POI 标注上
   仍然读得出来，又不会因为再加一块白底而变回「第三块碎饼干」。 */
.g3-placename {
  display: block; min-width: 0;
  /* 3.8rem ≈ 190px：反查地名正常就 8~10 字（「珠海 · 香洲区」约 92px），
     留 2 倍余量足够；再长就省略号 —— 它是标签不是读数，让它长过下面
     两个胶囊行（约 209px）的结果是「一行小字比仪表还宽」，看着就歪。
     ⚠️ 没有这条 max-width 时，`getBoundingClientRect` 会随文字一直变宽，
        真机上表现为整条顶栏被顶出屏幕右侧（而 .ellipsis 一句都没生效）。 */
  max-width: 3.8rem; margin: 0 0 0.06rem 0.06rem;
  font-size: 0.22rem; font-weight: 700; line-height: 0.3rem;
  color: var(--g3-ink);
  text-shadow: 0 1px 0 rgba(255, 255, 255, .95), 0 -1px 0 rgba(255, 255, 255, .95),
               1px 0 0 rgba(255, 255, 255, .95), -1px 0 0 rgba(255, 255, 255, .95),
               0 0 6px rgba(255, 255, 255, .9);
}
/* 三个小件同一行：指北针 · 速度胶囊 · 海拔胶囊 */
.g3-gauges { display: flex; align-items: center; gap: 0.12rem; }

/* 指北针：白底正圆 + 双色菱形针。
   针尖（北）用品牌绿、针尾用灰 —— 不引入新色相；红北针在这里会与「讲解橙」抢眼，
   而这块标只解决「北在哪」，不该成为屏幕上第二个高饱和点。 */
.g3-north {
  width: 0.68rem; height: 0.68rem; flex: none;
  display: flex; align-items: center; justify-content: center;
  background-color: #FFFFFF; border-radius: 50%;
  box-shadow: var(--g3-shadow-sm);
}
.g3-north-needle { display: block; width: 0.36rem; height: 0.36rem; will-change: transform; }
.g3-north-needle svg { display: block; width: 100%; height: 100%; }
.g3-nn-n { fill: var(--g3-green); }
.g3-nn-s { fill: var(--g3-ink-4); }
.g3-passenger .g3-nn-n { fill: var(--g3-purple); }

/* 读数胶囊：白底 + 大数字 + 小单位。
   ⚠️ 单位必须是**同一行内的 <em>**（不能是并列的 flex 兄弟）：
      两者字号不同，用 flex 兄弟会各按自己的行高排、基线错开约 2px；
      行内元素则天然共基线，不用手写 offset 去凑。
   ⚠️ tabular-nums 挂在 .g3-gv 上：数字跳动时字形等宽，胶囊宽度才不抖。 */
.g3-gauge {
  display: flex; align-items: center;
  height: 0.68rem; padding: 0 0.2rem;
  background-color: #FFFFFF; border-radius: 999px;
  box-shadow: var(--g3-shadow-sm);
}
.g3-gv {
  font-size: 0.36rem; font-weight: 700; line-height: 1;
  color: var(--g3-ink); font-variant-numeric: tabular-nums;
}
.g3-gv-spd { color: var(--g3-green); }
.g3-passenger .g3-gv-spd,
.g3-passenger .g3-gv-alt { color: var(--g3-purple); }
.g3-gu {
  font-size: 0.2rem; font-weight: 600; font-style: normal;
  color: var(--g3-ink-4); margin-left: 0.06rem;
  font-variant-numeric: normal;
}
/* 读数胶囊的**中文标签**（目前只有海拔用）。
   为什么必须有：速度靠「km/h」自证是什么，而海拔的单位「m」太通用 ——
   用户看到「3 m」认不出那是海拔（2026-10-13 用户原话：「看不出来 3m 指的是海拔」）。
   ⚠️ 单独一个类，**不复用 .g3-gu**：下面那条 `.g3-gv.is-null .g3-gu{display:none}`
      会把标签一起收掉，无值时用户看到的又只剩一个光秃秃的「—」。
   颜色比单位深一档（--g3-ink-3 vs --g3-ink-4）：标签回答「这是什么」，
   比回答「多少」的单位更重要；字号仍远小于读数（0.36rem），不抢主次。 */
.g3-gl {
  font-size: 0.22rem; font-weight: 700; font-style: normal;
  color: var(--g3-ink-3); margin-right: 0.06rem;
  font-variant-numeric: normal;
}
/* 海拔无值（null ⇒ 显示「—」）时，单位一起收掉 ——
   留着就是一个孤零零的「— m」，比只显示「—」更像坏了。 */
.g3-gv.is-null .g3-gu { display: none; }
/* ⚠️ 不给旧类名（.g3-locpill / .g3-speed / .g3-alt …）补 `display:none` 空壳 ——
   它们现已从 DOM 里彻底移除，补一条全局隐藏规则只会埋雷：
   哪天别处（自检面板 / 详情页）再用同名类，就会**静默不显示**。 */

/* 分段控件：白底胶囊 + 深色激活片（设计稿 92×32，激活片 42×26） */
.g3-mode {
  margin-left: auto; flex: none;
  display: flex; align-items: center;
  height: 0.64rem; padding: 0.06rem;
  background-color: #FFFFFF; border-radius: 999px;
  box-shadow: var(--g3-shadow-sm);
}
.g3-seg {
  height: 0.52rem; padding: 0 0.2rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px;
  font-size: 0.26rem; font-weight: 600; color: var(--g3-ink-4);
  cursor: pointer; white-space: nowrap;
}
.g3-seg.is-on { background-color: var(--g3-green); color: #FFFFFF; }
.g3-passenger .g3-seg.is-on { background-color: var(--g3-purple); }

/* 状态胶囊（待命 / 跟随中 / 正在讲解 / 已暂停 / 结束确认）
   ⚠️ top 里的 1.30rem = 顶栏高（0.2rem 上内距 + 地名 0.3rem + 0.06rem 间距 + 胶囊 0.68rem
      = 1.24rem）+ 0.06rem 间隙。顶栏改版后它是 1.02 → 1.30rem，见 §7 顶栏的说明。 */
.g3-chip {
  position: absolute; left: 0.32rem;
  top: calc(env(safe-area-inset-top) + 1.30rem);
  z-index: 19;
  display: inline-flex; align-items: center; gap: 0.1rem;
  height: 0.52rem; padding: 0 0.22rem;
  border-radius: 999px;
  font-size: 0.24rem; font-weight: 600;
  background-color: var(--g3-green-soft);
  border: 1px solid var(--g3-green-line);
  color: var(--g3-green-d);
  cursor: pointer;
}
.g3-chip i {
  width: 0.12rem; height: 0.12rem; border-radius: 50%;
  background-color: currentColor; flex: none;
}
.g3-chip.is-warn {
  background-color: var(--g3-orange-soft);
  border-color: rgba(224, 138, 46, .42);
  color: var(--g3-orange-d);
}
.g3-chip.g3-chip-pause {
  background-color: var(--g3-orange-soft2);
  border-color: rgba(224, 138, 46, .42);
  color: var(--g3-orange-d);
}

/* ==========================================================================
   8. 底部卡片区
   ========================================================================== */
.g3-bottom {
  position: absolute; left: 0.32rem; right: 0.32rem;
  bottom: var(--g3-bottom);
  z-index: 15;
}
.g3-bottom > * { pointer-events: auto; }

/* —— 待命卡（L-S1：343×150 / r20 / 标题 20 粗 + 说明 14 + 通栏绿按钮） —— */
.g3-idle {
  position: absolute; left: 0.32rem; right: 0.32rem;
  bottom: var(--g3-bottom);
  z-index: 16;
}
.g3-idle-card {
  padding: 0.36rem 0.36rem 0.3rem;
  background-color: #FFFFFF;
  border-radius: var(--g3-r);
  box-shadow: var(--g3-shadow);
}
.g3-idle-title { font-size: 0.4rem; font-weight: 700; line-height: 1.3; color: var(--g3-ink); }
.g3-idle-desc { margin-top: 0.16rem; font-size: 0.28rem; line-height: 1.5; color: var(--g3-ink-3); }
.g3-idle-actions { margin-top: 0.28rem; }
.g3-start {
  height: 0.92rem; border-radius: 0.28rem;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(90deg, var(--g3-accent-g1), var(--g3-accent-g2));
  color: #FFFFFF; font-size: 0.32rem; font-weight: 700;
  cursor: pointer; user-select: none;
}
.g3-start:active { opacity: .9; }
.g3-root .btn-disabled { opacity: .45; }
.g3-idle-block {
  margin-top: 0.2rem; font-size: 0.24rem; line-height: 1.45;
  color: var(--g3-orange-d); background-color: var(--g3-orange-soft);
  border-radius: 0.2rem; padding: 0.16rem 0.2rem;
}
.g3-idle-check {
  margin-top: 0.24rem; text-align: center;
  font-size: 0.24rem; color: var(--g3-ink-4);
  display: flex; align-items: center; justify-content: center; gap: 0.08rem;
}
.g3-idle-check .ico { width: 0.28rem; height: 0.28rem; }

/* 准备中提示（细白条） */
.g3-prep {
  display: flex; align-items: center; justify-content: center; gap: 0.1rem;
  height: 0.56rem; margin-bottom: 0.16rem;
  background-color: rgba(255, 255, 255, .96);
  border-radius: 0.36rem; box-shadow: var(--g3-shadow-sm);
  font-size: 0.26rem; color: var(--g3-ink-2);
}
.g3-prep-dot {
  width: 0.16rem; height: 0.16rem; border-radius: 50%;
  border: 2px solid var(--g3-accent-line); border-top-color: var(--g3-accent);
  animation: g3Spin .8s linear infinite;
}
@keyframes g3Spin { to { transform: rotate(360deg); } }

/* —— 小途提示条（L-S2：343×64 / r20） ——
   依据 docs/design/SPEC-组件-小途提示条.md。
   ⚠️ 换算口径：本项目 `html` 字号 = 100vw/7.5，375 宽下 1rem = 50px，
      即 **rem = 设计稿 px ÷ 50**（设计稿为 375 基准）。切勿按 ÷100 写，
      否则整块只有设计尺寸的一半（实测提示条会渲染成 32px 高）。
   两态共用同一 DOM，只切 .is-speaking：
     安静态 → 头像 +「小途」+「前方有值得讲的，我会开口」+ 右侧「安静」
     说话态 → 头像右下橙 badge（带白边）+「正在讲 · 点位名」橙字 + 7 根绿色声纹
   ⚠️ 声纹**必须错开 animation-delay**，7 根一起缩放会看成整列上下跳，
      不像声纹（SPEC §3 明确点名）。 */
.g3-xiaotu-bar {
  display: flex; align-items: center;
  height: 1.28rem;            /* 64px（SPEC §1：343×64） */
  padding: 0 0.24rem;
  background-color: #FFFFFF;
  border-radius: 0.4rem;      /* 20px */
  box-shadow: var(--g3-shadow);
  font-size: 0.28rem; color: var(--g3-ink);
}
/* 头像：40×40 正圆，卡通 mascot 铺满；图加载失败时露兜底浅绿底。
   ⚠️ 必须同时给 width/height，并 align-self:center —— 父容器是 flex，
     只给 flex-basis 会被拉伸成椭圆（实测图里头像变成竖长椭圆就是这个原因）。 */
.g3-xt-avatar {
  position: relative; flex: 0 0 0.8rem;
  width: 0.8rem; height: 0.8rem;
  min-width: 0.8rem; min-height: 0.8rem;
  align-self: center;
  border-radius: 999px;
  background-color: #E6F0ED;
}
.g3-xt-avatar-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; border-radius: 999px;
  object-fit: cover; display: block;
}
/* 说话态右下角橙 badge —— 白边让它从头像上「跳」出来
   ⚠️⚠️ 必须 z-index:1：头像 img 是 position:absolute，按 CSS 层叠规则
       定位元素恒在 static 元素之上 —— 不给 z-index 时 badge 会被 img 整块盖住
       （实测：截图里只有头像绿，完全看不到橙点）。 */
.g3-xt-avatar-badge { display: none; }
.g3-xiaotu-bar.is-speaking .g3-xt-avatar-badge {
  display: block; position: absolute; right: -0.04rem; bottom: -0.04rem; z-index: 1;
  width: 0.24rem; height: 0.24rem; border-radius: 999px;
  background-color: var(--g3-orange);
  border: 2px solid #FFFFFF; box-sizing: content-box;
}
/* 文案区 */
.g3-xt-text {
  margin-left: 0.16rem; flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; justify-content: center;
}
.g3-xt-name { font-size: 0.24rem; font-weight: 700; line-height: 1.3; color: var(--g3-ink); }
.g3-xt-hint {
  font-size: 0.26rem; line-height: 1.4; color: var(--g3-ink-2);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
/* 两态互斥：安静态显示 hint，说话态显示 is-speaking */
.g3-xt-hint.is-speaking { display: none; }
.g3-xiaotu-bar.is-speaking .g3-xt-hint { display: none; }
.g3-xiaotu-bar.is-speaking .g3-xt-hint.is-speaking {
  display: block; font-weight: 500; color: var(--g3-orange-d);
}
/* 声纹：7 根，宽 3px、步进 7px（实测图1：x=248/255/262/269/276/283/290），
   容器 51px，高度 8/20/28/16/24/12/18，底边对齐、从底部缩放。
   ⚠️ 7 根**必须错开 animation-delay** —— 一起缩放会看成整列上下跳，不像声纹。 */
.g3-xt-voice { display: none; }
.g3-xiaotu-bar.is-speaking .g3-xt-voice {
  display: block; position: relative; flex: 0 0 auto;
  width: 1.02rem; height: 0.56rem; margin-left: 0.16rem;   /* 51×28 */
}
.g3-xt-voice i {
  position: absolute; bottom: 0; left: 0;
  width: 0.06rem; border-radius: 0.03rem;                  /* 宽 3px */
  background-color: var(--g3-green);
  transform-origin: bottom center;
  animation: g3XtWave 1.2s ease-in-out infinite;
}
.g3-xt-voice i:nth-child(1) { left: 0rem;    height: 0.16rem; opacity: .75; animation-delay:   0ms; }  /*  8px */
.g3-xt-voice i:nth-child(2) { left: 0.14rem; height: 0.4rem;  opacity: .85; animation-delay: 120ms; }  /* 20px */
.g3-xt-voice i:nth-child(3) { left: 0.28rem; height: 0.56rem; opacity: 1;   animation-delay: 240ms; }  /* 28px */
.g3-xt-voice i:nth-child(4) { left: 0.42rem; height: 0.32rem; opacity: .8;  animation-delay: 360ms; }  /* 16px */
.g3-xt-voice i:nth-child(5) { left: 0.56rem; height: 0.48rem; opacity: .9;  animation-delay: 480ms; }  /* 24px */
.g3-xt-voice i:nth-child(6) { left: 0.70rem; height: 0.24rem; opacity: .75; animation-delay: 600ms; }  /* 12px */
.g3-xt-voice i:nth-child(7) { left: 0.84rem; height: 0.36rem; opacity: .85; animation-delay: 720ms; }  /* 18px */
@keyframes g3XtWave {
  0%, 100% { transform: scaleY(.5); }
  50%      { transform: scaleY(1); }
}
/* 右侧状态字：安静 / 讲解中 */
.g3-xt-action {
  flex: 0 0 auto; margin-left: 0.16rem;
  font-size: 0.24rem; font-weight: 500; color: var(--g3-ink-4);
}
.g3-xiaotu-bar.is-speaking .g3-xt-action { color: var(--g3-orange-d); }

/* —— 讲解卡（L-S3：343×183 / r22） —— */
.g3-ncard {
  padding: 0.32rem 0.32rem 0.28rem;
  background-color: #FFFFFF;
  border-radius: var(--g3-r-lg);
  box-shadow: var(--g3-shadow);
}
.g3-nhead { display: flex; align-items: center; }
.g3-ncat {
  display: flex; align-items: center; gap: 0.1rem;
  font-size: 0.26rem; font-weight: 600; color: var(--g3-orange);
}
.g3-ncat i { width: 0.12rem; height: 0.12rem; border-radius: 50%; background-color: currentColor; }
/* 已讲解态：整行转灰（点开地图标注用的那张卡） */
.g3-ncat.is-done { color: var(--g3-ink-4); }
.g3-ndist { margin-left: auto; font-size: 0.26rem; color: var(--g3-ink-4); }
.g3-nrow { display: flex; align-items: center; margin-top: 0.1rem; }
.g3-ntitle {
  flex: 1; min-width: 0;
  font-size: 0.52rem; font-weight: 700; line-height: 1.25; color: var(--g3-ink);
}
/* 均衡器：播报中的动效提示（设计稿橙色四柱） */
.g3-eq { display: flex; align-items: flex-end; gap: 0.05rem; height: 0.34rem; flex: none; margin-left: 0.2rem; }
.g3-eq i {
  width: 0.06rem; border-radius: 999px; background-color: var(--g3-orange);
  animation: g3Eq .9s ease-in-out infinite;
}
.g3-eq i:nth-child(1) { height: 40%; animation-delay: 0s; }
.g3-eq i:nth-child(2) { height: 100%; animation-delay: .15s; }
.g3-eq i:nth-child(3) { height: 62%; animation-delay: .3s; }
.g3-eq i:nth-child(4) { height: 84%; animation-delay: .45s; }
.g3-eq.is-paused i { animation-play-state: paused; }
@keyframes g3Eq { 0%, 100% { transform: scaleY(.45); } 50% { transform: scaleY(1); } }
.g3-ndesc {
  margin-top: 0.14rem;
  font-size: 0.28rem; line-height: 1.5; color: var(--g3-ink-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.g3-nline { height: 1px; background-color: var(--g3-line); margin: 0.26rem 0 0.24rem; }
.g3-nfoot { display: flex; align-items: center; gap: 0.24rem; }
.g3-play {
  width: 1.04rem; height: 1.04rem; flex: none;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--g3-accent-g1), var(--g3-accent-g2));
  color: #FFFFFF; cursor: pointer; user-select: none;
}
.g3-play svg { width: 0.4rem; height: 0.4rem; display: block; }
.g3-play:active { transform: scale(.95); }
.g3-nmid { flex: 1; min-width: 0; }
.g3-bar { height: 0.08rem; border-radius: 999px; background-color: #E4EAE7; overflow: hidden; }
.g3-bar > i { display: block; height: 100%; width: 0; border-radius: 999px; background-color: var(--g3-accent); }
.g3-ntime { margin-top: 0.12rem; font-size: 0.26rem; color: var(--g3-ink-4); }
.g3-ntime b { color: var(--g3-ink-3); font-weight: 600; }
.g3-nav-btn {
  width: 0.72rem; height: 0.72rem; flex: none;
  display: flex; align-items: center; justify-content: center;
  background-color: #FFFFFF; border: 1px solid var(--g3-line);
  border-radius: 0.24rem; color: var(--g3-ink);
  cursor: pointer;
}
.g3-nav-btn svg { width: 0.34rem; height: 0.34rem; display: block; }
.g3-nav-btn.is-off { display: none; }

/* —— 暂停卡（L-S4：橙按钮） —— */
.g3-pcard {
  padding: 0.36rem 0.36rem 0.3rem;
  background-color: #FFFFFF;
  border-radius: var(--g3-r);
  box-shadow: var(--g3-shadow);
}
.g3-pcard-title { font-size: 0.4rem; font-weight: 700; color: var(--g3-ink); }
.g3-pcard-desc { margin-top: 0.14rem; font-size: 0.28rem; line-height: 1.5; color: var(--g3-ink-3); }
.g3-resume {
  margin-top: 0.28rem;
  height: 0.92rem; border-radius: 0.28rem;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(90deg, #E9A64A, #D08A22);
  color: #FFFFFF; font-size: 0.32rem; font-weight: 700;
  cursor: pointer; user-select: none;
}
.g3-resume:active { opacity: .9; }

/* ==========================================================================
   9. 乘客模式专属：照片 Hero + 逐句高亮 + 播放控制 + 迷你地图
   -------------------------------------------------------------------------
   乘客模式下地图容器被「搬」到底部迷你地图槽位（见 9.4）。
   引擎 _metrics() 读的正是 #g-map 的 clientWidth/Height，
   容器一换位置，标记与点位标注的算术自动跟着走，无需改引擎。
   ========================================================================== */
.g3-hero {
  position: relative;
  height: 3.86rem;
  border-radius: var(--g3-r);
  overflow: hidden;
  background-color: #D9E4E8;
  box-shadow: var(--g3-shadow-sm);
}
.g3-hero img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.g3-hero-fallback {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, #FFEBCB 0%, #FFE2BE 34%, #F5D9BE 60%, #E6D3C4 78%, #F1F5F3 100%);
}
.g3-hero-veil {
  position: absolute; left: 0; right: 0; bottom: 0; height: 1.6rem;
  background: linear-gradient(0deg, rgba(255, 255, 255, .92) 0%, rgba(255, 255, 255, 0) 100%);
}
.g3-hero-badge {
  position: absolute; left: 0.24rem; top: 0.24rem;
  height: 0.44rem; padding: 0 0.18rem;
  display: inline-flex; align-items: center;
  border-radius: 999px; background-color: rgba(18, 31, 28, .62);
  color: #FFFFFF; font-size: 0.22rem; font-weight: 500;
}
.g3-hero-cap { position: absolute; left: 0.28rem; right: 0.28rem; bottom: 0.22rem; }
.g3-hero-name { font-size: 0.5rem; font-weight: 700; color: var(--g3-ink); line-height: 1.2; }
.g3-hero-sub { margin-top: 0.06rem; font-size: 0.26rem; color: var(--g3-ink-2); }

/* 9.2 逐句高亮 */
.g3-subs {
  margin-top: 0.24rem;
  padding: 0.32rem;
  background-color: #FFFFFF;
  border-radius: var(--g3-r);
  box-shadow: var(--g3-shadow-sm);
  font-size: 0.36rem; line-height: 1.85; color: var(--g3-ink);
}
.g3-subs .sub-line { border-radius: 0.16rem; padding: 0.02rem 0.12rem; margin: 0 -0.12rem; }
.g3-subs .sub-line-done { color: #A8B4AF; }
.g3-subs .sub-line-active {
  background-color: rgba(106, 90, 224, .14);
  color: var(--g3-green);
  font-weight: 600;
}

/* 9.3 播放控制（紫） */
.g3-playbar {
  margin-top: 0.24rem;
  padding: 0.28rem 0.32rem 0.24rem;
  background-color: #FFFFFF;
  border-radius: var(--g3-r);
  box-shadow: var(--g3-shadow-sm);
}
.g3-pb-top { display: flex; align-items: center; gap: 0.24rem; }
.g3-pb-btn {
  width: 1.04rem; height: 1.04rem; flex: none; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--g3-purple-g1), var(--g3-purple-g2));
  color: #FFFFFF; cursor: pointer;
}
.g3-pb-btn svg { width: 0.4rem; height: 0.4rem; display: block; }
.g3-pb-track { flex: 1; min-width: 0; }
.g3-pb-time { margin-top: 0.12rem; font-size: 0.26rem; color: var(--g3-ink-4); }
.g3-pb-time b { color: var(--g3-ink-3); font-weight: 600; }
.g3-pb-rows { display: flex; align-items: center; justify-content: space-between; margin-top: 0.24rem; }
.g3-pb-mini {
  height: 0.68rem; padding: 0 0.28rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px; background-color: #F1F5F3;
  font-size: 0.28rem; font-weight: 600; color: var(--g3-ink);
  cursor: pointer;
}
.g3-pb-rate {
  height: 0.6rem; min-width: 0.9rem; padding: 0 0.2rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background-color: rgba(106, 90, 223, .12);
  border: 1px solid rgba(106, 90, 223, .38);
  font-size: 0.28rem; font-weight: 700; color: var(--g3-purple);
  cursor: pointer;
}
.g3-pb-mini:active, .g3-pb-rate:active { opacity: .8; }
.g3-pb-mini.is-off { opacity: .4; }
/* 背景流「跳过这一集」（P7）：整行独立按钮，只在播行政区划分集时出现。
   与上/下一条同视觉语言，但用强调色区分「这是否决当前内容」而不是「换一条」。 */
.g3-pb-skip {
  margin-top: 0.18rem; height: 0.6rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background-color: var(--g3-accent-soft, rgba(106, 90, 223, .10));
  font-size: 0.26rem; font-weight: 600; color: var(--g3-accent);
  cursor: pointer;
}
.g3-pb-skip:active { opacity: .8; }

/* 9.3b 等待卡（乘客模式 · 行程中还没开始讲解）——
   设计稿只画了「正在讲解」一帧，没有空态。切到乘客后若什么都不显示，
   这一屏从 GPS 提示条到迷你地图之间整块是空的（用户反馈的「顶部空白」）。
   沿用同一套白卡语言 + 一个缓慢呼吸的圆环，视觉上属于这套稿子。 */
.g3-waitcard {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 3.86rem;
  padding: 0.6rem 0.4rem;
  text-align: center;
  background-color: #FFFFFF;
  border-radius: var(--g3-r);
  box-shadow: var(--g3-shadow-sm);
}
.g3-wait-ring {
  position: relative; width: 0.96rem; height: 0.96rem;
  margin-bottom: 0.32rem;
  border-radius: 50%;
  border: 0.05rem solid rgba(106, 90, 223, .28);
}
.g3-wait-ring i {
  position: absolute; inset: 0.2rem;
  border-radius: 50%;
  background-color: rgba(106, 90, 223, .16);
  animation: g3Wait 2.4s ease-in-out infinite;
}
@keyframes g3Wait {
  0%, 100% { transform: scale(.82); opacity: .6; }
  50%      { transform: scale(1.12); opacity: 1; }
}
.g3-wait-title { font-size: 0.36rem; font-weight: 700; color: var(--g3-ink); }
.g3-wait-desc { margin-top: 0.14rem; font-size: 0.28rem; line-height: 1.5; color: var(--g3-ink-3); }
/* 等待卡的「查看详情」：只在当天已讲解时露出（停在最后讲过的点位上） */
.g3-wait-more {
  margin-top: 0.28rem;
  display: flex; align-items: center; justify-content: center;
  height: 0.68rem; padding: 0 0.32rem;
  border-radius: 999px;
  background-color: var(--g3-accent-soft);
  color: var(--g3-accent);
  font-size: 0.26rem; font-weight: 700;
}

/* 9.4 迷你地图槽位：把 #g-map 搬进来当卡片用 */
.g3-root.g3-passenger .g3-map {
  position: absolute; left: 0.32rem; right: 0.32rem;
  top: auto; bottom: var(--g3-bottom);
  height: 2.24rem;
  border-radius: 0.36rem;
  overflow: hidden;
  box-shadow: var(--g3-shadow-sm);
  z-index: 8;
}
.g3-root.g3-passenger .g3-map-veil { display: none; }
.g3-root.g3-passenger .g3-attrib { bottom: 0.06rem; }
.g3-root.g3-passenger .map-tools { display: none; }
/* 「上滑查看完整路线」提示（设计稿左下角） */
.g3-mini-hint {
  position: absolute; left: 0.28rem; bottom: 0.2rem; z-index: 9;
  display: none;
  align-items: center; gap: 0.08rem;
  font-size: 0.26rem; font-weight: 600; color: var(--g3-ink);
  pointer-events: none;
}
.g3-root.g3-passenger .g3-mini-hint { display: flex; }
/* 乘客模式没有状态胶囊（P 帧），整体隐藏 */
.g3-root.g3-passenger .g3-chip { display: none !important; }
/* 地图搬到下方后，上方卡片区整体上移让位 */
/* 乘客模式：司机那三态卡（跟随条 / 讲解卡 / 暂停卡）整块不出现 ——
   设计稿 P 帧底部只有迷你地图 + 底栏，没有跟随条。
   这块区域的内容全部由 .g3-pstack 承担：有讲解走 Hero+字幕+播放控制，
   没讲解走等待卡（见 _renderPassengerStack）。 */
.g3-root.g3-passenger .g3-bottom { display: none; }
/* 待命卡只在「行程未开始」时出现，这时它要避开下方的迷你地图槽位 */
.g3-root.g3-passenger .g3-idle {
  bottom: calc(var(--g3-bottom) + 2.24rem + 0.24rem);
}

/* ==========================================================================
   10. 全屏长按结束层（L-S5：浅色磨砂 + 细灰轨道环 + 绿色进度 + 中心方形停止）
   ========================================================================== */
.g3-boot {
  position: fixed; inset: 0; z-index: 1400;
  display: flex; align-items: center; justify-content: center;
}
.g3-boot-mask {
  position: absolute; inset: 0;
  background-color: rgba(245, 248, 246, .88);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.g3-boot-core { position: relative; display: flex; flex-direction: column; align-items: center; }
.g3-boot-ringwrap { position: relative; width: 4.06rem; height: 4.06rem; }
.g3-boot-ringwrap svg { width: 100%; height: 100%; display: block; transform: rotate(-90deg); }
/* stroke-width 是 viewBox 用户单位：viewBox 120、落地面 4.06rem(203px)，
   缩放 1.692 → 用户单位 2.96 恰好画成 5px（与设计稿实测一致）。 */
.g3-boot-ring-bg { fill: none; stroke: #D5DFDA; stroke-width: 2.96; }
.g3-boot-ring-fg {
  fill: none; stroke: var(--g3-green); stroke-width: 2.96; stroke-linecap: round;
}
.g3-boot-in {
  position: absolute; left: 50%; top: 50%;
  width: 1.44rem; height: 1.44rem; margin: -0.72rem 0 0 -0.72rem;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--g3-green-g1), var(--g3-green-g2));
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 0.1rem 0.3rem rgba(9, 79, 65, .28);
}
.g3-boot-in::after {
  content: ''; width: 0.34rem; height: 0.34rem; border-radius: 0.06rem;
  background-color: #FFFFFF;
}
/* 环内数字保留在 DOM（引擎会写值）但设计稿不展示数字，只留中心方块 */
.g3-boot-num { display: none; }
.g3-boot-cap {
  margin-top: 0.5rem;
  font-size: 0.34rem; font-weight: 700; color: var(--g3-ink);
}
.g3-boot-sub { margin-top: 0.14rem; font-size: 0.28rem; color: var(--g3-ink-4); }

/* ==========================================================================
   11. 环境提示条
   ========================================================================== */
.g3-notice {
  position: absolute; left: 0.32rem; right: 0.32rem; z-index: 18;
  /* ⚠️ 1.94rem = 状态胶囊底（1.30rem + 0.52rem = 1.82rem）+ 0.12rem 间隙。
     顶栏改版后由 1.66 → 1.94rem（+0.28rem）。漏改这里，GPS 提示条会压住数值胶囊。 */
  top: calc(env(safe-area-inset-top) + 1.94rem);
  display: flex; align-items: center; gap: 0.1rem;
  padding: 0.18rem 0.24rem;
  background-color: rgba(255, 255, 255, .98);
  border: 1px solid var(--g3-line);
  border-radius: 0.24rem;
  box-shadow: var(--g3-shadow-sm);
  font-size: 0.24rem; line-height: 1.45; color: var(--g3-ink-2);
  overflow: hidden;
  max-height: 2.2rem;
}
.g3-notice .ico-warn { color: var(--g3-orange); width: 0.3rem; height: 0.3rem; flex: none; }
.g3-notice-dim { border-color: rgba(14, 107, 87, .22); background-color: rgba(240, 247, 244, .98); }
/* 自动淡出：收起高度 + 透明（沿用引擎的 notice-auto / is-gone 约定类） */
.g3-notice.notice-auto { transition: max-height .4s ease, opacity .4s ease, padding .4s ease, border-width .4s ease; }
.g3-notice.is-gone { max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; border-width: 0; }

/* ==========================================================================
   12. 播报控制面板（底部弹层：暂停 / 进度 / 音量 / 自检 / 语音设置）
   ========================================================================== */
.g3-scrim { position: fixed; inset: 0; z-index: 1150; background-color: rgba(18, 32, 28, .22); }
.g3-panel {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 1151;
  padding: 0.2rem 0.32rem calc(0.36rem + env(safe-area-inset-bottom));
  background-color: #FFFFFF;
  border-radius: 0.48rem 0.48rem 0 0;
  box-shadow: 0 -0.16rem 0.5rem rgba(18, 32, 28, .16);
}
.g3-panel-grip {
  width: 0.72rem; height: 0.08rem; border-radius: 999px;
  background-color: var(--g3-line); margin: 0 auto 0.24rem;
}
.g3-panel-row { display: flex; align-items: center; gap: 0.24rem; }
.g3-pbtn {
  width: 0.92rem; height: 0.92rem; flex: none; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background-color: var(--g3-green-soft); color: var(--g3-green);
  cursor: pointer; position: relative;
}
.g3-pbtn svg { width: 0.36rem; height: 0.36rem; }
.g3-pmid { flex: 1; min-width: 0; }
.g3-ptitle { font-size: 0.3rem; font-weight: 700; color: var(--g3-ink); }
.g3-ptime { margin-top: 0.08rem; font-size: 0.24rem; color: var(--g3-ink-4); }
.g3-pstop { background: linear-gradient(135deg, var(--g3-green-g1), var(--g3-green-g2)); color: #FFFFFF; }
.g3-pstop.is-holding { box-shadow: 0 0 0 0.06rem rgba(14, 107, 87, .22); }
.g3-ring { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
.g3-ring-bg { fill: none; stroke: rgba(255, 255, 255, .34); stroke-width: 2.4; }
.g3-ring-fg { fill: none; stroke: #FFFFFF; stroke-width: 2.4; stroke-linecap: round; }
.g3-stop-ico { position: relative; display: flex; }
.g3-phint { margin-top: 0.18rem; font-size: 0.24rem; color: var(--g3-ink-4); }
.g3-pvol { display: flex; align-items: center; gap: 0.16rem; margin-top: 0.24rem; }
.g3-pvol-ico { width: 0.34rem; height: 0.34rem; flex: none; color: var(--g3-ink-3); }
.g3-range { flex: 1; -webkit-appearance: none; appearance: none; height: 0.1rem; border-radius: 999px; background-color: #E4EAE7; }
.g3-range::-webkit-slider-thumb { -webkit-appearance: none; width: 0.36rem; height: 0.36rem; border-radius: 50%; background-color: var(--g3-green); box-shadow: 0 0.04rem 0.12rem rgba(9, 79, 65, .3); }
.g3-pvolnum { width: 0.9rem; text-align: right; font-size: 0.24rem; color: var(--g3-ink-3); flex: none; }
.g3-pfoot { display: flex; align-items: center; gap: 0.3rem; margin-top: 0.26rem; }
.g3-plink { font-size: 0.26rem; color: var(--g3-ink-3); cursor: pointer; }
.g3-plink-go { margin-left: auto; color: var(--g3-accent); font-weight: 700; }

/* ==========================================================================
   13. 音量自检面板（底部弹层）
   -------------------------------------------------------------------------
   ⚠️ 这片弹层必须始终有「能被关掉」的出口。曾经它既没有遮罩、也没有关闭钮，
   唯一出口是再点一次右侧工具列的喇叭钮，而那个绑定写成了强制打开 ——
   结果是弹起来就再也收不回（真机反馈）。现在有三个出口：
     ① 再点一次喇叭钮（真切换，见 toggleVolPanel）
     ② 点本面板以外的任何地方（#g-volscrim 遮罩）
     ③ 行程结束 / 停讲解时由 updateCtrl 统一收起
   z 序：遮罩 1151 / 面板 1152，压在播报面板（1150/1151）之上；
   两片弹层互斥，不会同时出现（见 toggleLivePanel / toggleVolPanel）。
   ========================================================================== */
#g-volscrim { z-index: 1151; }
.g3-vol {
  /* 顶边留 0.2rem 与播报面板（.g3-panel）一致，两片弹层的抓手才在同一高度 */
  padding: 0.2rem 0.32rem calc(0.36rem + env(safe-area-inset-bottom));
  background-color: #FFFFFF;
  border-radius: 0.48rem 0.48rem 0 0;
  box-shadow: 0 -0.16rem 0.5rem rgba(18, 32, 28, .16);
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 1152;
}
/* 抓手居中 + 关闭钮靠右。整行 0.56rem 高，是为了让 ✕ 这个圆钮不与下面
   第一行（播报音量滑块，滑块把手在 100% 时正好顶到右边）撞在一起。 */
.g3-vol-head {
  position: relative; height: 0.56rem; margin-bottom: 0.08rem;
  display: flex; align-items: center; justify-content: center;
}
.g3-vol-grip { width: 0.72rem; height: 0.08rem; border-radius: 999px; background-color: var(--g3-line); }
.g3-vol-x {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  width: 0.56rem; height: 0.56rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background-color: #F1F5F3;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
/* 图标用 app.css 的 .ico-close 精灵，这里只把它收到圆钮里合适的大小 */
.g3-vol-x .ico { width: 0.28rem; height: 0.28rem; }
.g3-vol-x:active { transform: translateY(-50%) scale(.92); }
.g3-vol-row { display: flex; align-items: center; gap: 0.2rem; }
.g3-vol-label { font-size: 0.28rem; font-weight: 600; color: var(--g3-ink); flex: none; }
.g3-vol input[type=range] { flex: 1; -webkit-appearance: none; appearance: none; height: 0.1rem; border-radius: 999px; background-color: #E4EAE7; }
.g3-vol input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 0.36rem; height: 0.36rem; border-radius: 50%; background-color: var(--g3-green); }
.g3-vol-diag { margin-top: 0.24rem; border-top: 1px solid var(--g3-line); padding-top: 0.2rem; }
.vd-line { display: flex; align-items: center; justify-content: space-between; font-size: 0.24rem; color: var(--g3-ink-3); padding: 0.06rem 0; }
.vd-v { color: var(--g3-ink); font-weight: 600; }
.vd-v.ok { color: var(--g3-green); }
.vd-v.bad { color: var(--g3-orange-d); }
.vd-concl { margin-top: 0.12rem; font-size: 0.24rem; line-height: 1.5; color: var(--g3-ink-2); }
.g3-vol-acts { margin-top: 0.24rem; flex-direction: column; align-items: stretch; gap: 0.12rem; }
.g3-vol-test {
  height: 0.84rem; border-radius: 0.24rem;
  display: flex; align-items: center; justify-content: center;
  background-color: var(--g3-green-soft); color: var(--g3-green);
  font-size: 0.28rem; font-weight: 700; cursor: pointer;
}
.g3-vol-hint { font-size: 0.22rem; color: var(--g3-ink-4); text-align: center; }
.g3-vol-more {
  margin-top: 0.24rem; padding-top: 0.24rem;
  border-top: 1px solid var(--g3-line);
  display: flex; align-items: center; justify-content: space-between;
  font-size: 0.28rem; color: var(--g3-ink); cursor: pointer;
}
.g3-vol-more .ico { width: 0.3rem; height: 0.3rem; }

/* ==========================================================================
   14. 全局底栏 V3 化（3 格 / 白胶囊 / 浅色激活片）
   -------------------------------------------------------------------------
   app.css 的 .global-tabbar 仍在；这里用 #id 提升优先级整体改版。
   ========================================================================== */
#global-tabbar {
  padding: 0.12rem;
  border-radius: 1.12rem;
  background-color: rgba(255, 255, 255, .98);
  box-shadow: 0 0.12rem 0.3rem rgba(27, 59, 49, .12);
}
#global-tabbar .tab-item {
  /* 圆角 0.4rem（= 20px，设计稿激活片实测值），与底栏胶囊的弧度配套 */
  height: 0.88rem; border-radius: 0.4rem;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.02rem; padding: 0;
  font-size: 0.22rem; font-weight: 600; color: #8A9A94;
}
#global-tabbar .tab-item .ico { width: 0.4rem; height: 0.4rem; margin: 0; }
#global-tabbar .tab-active { background-color: var(--g3-green-soft); color: var(--g3-green); }
#global-tabbar .tab-active .ico {
  filter: invert(30%) sepia(62%) saturate(1195%) hue-rotate(126deg) brightness(93%) contrast(92%);
}
/* 乘客模式：激活片与图标转紫 */
#app.g3-mode-passenger #global-tabbar .tab-active {
  background-color: rgba(106, 90, 223, .12);
  color: var(--g3-purple);
}
#app.g3-mode-passenger #global-tabbar .tab-active .ico {
  filter: invert(38%) sepia(72%) saturate(2600%) hue-rotate(228deg) brightness(96%) contrast(96%);
}

/* ==========================================================================
   15. 导航应用选择弹层（V3：白底 + 彩色图标方格）
   ========================================================================== */
.modal.navsheet {
  padding: 0.2rem 0.32rem calc(0.36rem + env(safe-area-inset-bottom));
  background-color: #FFFFFF;
  border-radius: 0.48rem 0.48rem 0 0;
}
.g3-ns-grip { width: 0.72rem; height: 0.08rem; border-radius: 999px; background-color: var(--g3-line); margin: 0 auto 0.24rem; }
.g3-ns-head { text-align: center; margin-bottom: 0.28rem; }
.g3-ns-t { font-size: 0.34rem; font-weight: 700; color: var(--g3-ink); }
.g3-ns-s { margin-top: 0.08rem; font-size: 0.26rem; color: var(--g3-ink-4); }
.g3-nrow {
  display: flex; align-items: center; gap: 0.24rem;
  padding: 0.22rem 0.24rem;
  border-radius: 0.28rem;
  cursor: pointer;
}
.g3-nrow:active { background-color: #F5F8F6; }
.g3-nico {
  width: 0.88rem; height: 0.88rem; flex: none;
  border-radius: 0.26rem;
  display: flex; align-items: center; justify-content: center;
  color: #FFFFFF; font-size: 0.34rem; font-weight: 700;
}
.g3-nbody { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.g3-nname { font-size: 0.3rem; font-weight: 600; color: var(--g3-ink); }
.g3-ndesc2 { margin-top: 0.04rem; font-size: 0.24rem; color: var(--g3-ink-4); }
.g3-narrow { color: var(--g3-ink-4); width: 0.3rem; height: 0.3rem; flex: none; }
.g3-ns-cancel {
  margin-top: 0.24rem; height: 0.88rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 0.28rem; background-color: #F1F5F3;
  font-size: 0.3rem; font-weight: 600; color: var(--g3-ink-2);
  cursor: pointer;
}

/* ==========================================================================
   16. 切向乘客模式确认卡（P-切向乘客确认卡）
   ========================================================================== */
.g3-confirm {
  padding: 0.5rem 0.44rem 0.4rem;
  background-color: #FFFFFF;
  border: 1px solid rgba(106, 90, 223, .28);
  border-radius: 0.44rem;
  box-shadow: 0 0.2rem 0.6rem rgba(18, 32, 28, .18);
}
.g3-cf-ico { color: var(--g3-orange); width: 0.5rem; height: 0.5rem; display: block; }
.g3-cf-t { margin-top: 0.24rem; font-size: 0.4rem; font-weight: 700; color: var(--g3-ink); }
.g3-cf-d { margin-top: 0.16rem; font-size: 0.28rem; line-height: 1.55; color: var(--g3-ink-3); }
.g3-cf-check {
  margin-top: 0.28rem; display: flex; align-items: center; gap: 0.16rem;
  font-size: 0.28rem; font-weight: 600; color: var(--g3-ink);
  cursor: pointer; user-select: none;
}
.g3-cf-box {
  width: 0.4rem; height: 0.4rem; flex: none;
  border-radius: 0.12rem;
  border: 1.5px solid var(--g3-line);
  display: flex; align-items: center; justify-content: center;
  color: var(--g3-purple);
}
.g3-cf-check.is-on .g3-cf-box {
  background-color: rgba(106, 90, 223, .16);
  border-color: var(--g3-purple);
}
.g3-cf-box svg { width: 0.26rem; height: 0.26rem; display: none; }
.g3-cf-check.is-on .g3-cf-box svg { display: block; }
.g3-cf-btns { display: flex; gap: 0.24rem; margin-top: 0.36rem; }
.g3-cf-btn {
  flex: 1; height: 0.88rem; border-radius: 0.28rem;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.3rem; font-weight: 700; cursor: pointer;
}
.g3-cf-cancel { background-color: #F1F5F3; color: var(--g3-ink-2); }
.g3-cf-ok {
  background: linear-gradient(90deg, var(--g3-purple-g1), var(--g3-purple-g2));
  color: #FFFFFF;
}
/* 未勾选「我不是驾驶员」时：确认键退成灰底灰字。
   不用单纯降 opacity —— 紫渐变 + 白字降透明度后会糊成一片白，看不出是个按钮。 */
.g3-cf-ok.is-off { background: #F1F5F3; color: var(--g3-ink-4); box-shadow: none; }

/* ==========================================================================
   17. 补充件：气泡细节 / 乘客叠层容器 / 居中确认卡
   ========================================================================== */
.g3-poi-top { display: flex; align-items: baseline; gap: 0.12rem; }
.g3-poi-dist { font-size: 0.26rem; color: var(--g3-ink-4); flex: none; }
/* 正在讲解的气泡：橙描边 + 橙标题（设计稿 L-S3 地图气泡的写法） */
.g3-poi-card.is-live { border-color: rgba(224, 138, 46, .42); }
.g3-poi-card.is-live .g3-poi-name { color: var(--g3-orange-d); }

/* 乘客模式叠层：位于顶部信息条之下、迷你地图之上，内容超长可滚 */
/* 乘客讲解叠层：Hero 固定、字幕区吃掉剩余高度并在内部滚动、播放控制常驻底部。
   整体不滚动 —— 播放条是控制件，滑出视口就没法用了（设计稿 P 也是三段固定排布）。 */
.g3-pstack {
  position: absolute; left: 0.32rem; right: 0.32rem;
  top: calc(env(safe-area-inset-top) + 1.36rem);
  bottom: calc(var(--g3-bottom) + 2.24rem + 0.24rem);
  z-index: 14;
  display: flex; flex-direction: column;
  overflow: hidden;
}
/* 乘客模式的起点对齐设计稿 P 帧的 Hero 顶边（y=96 → 1.92rem）。
   顺带把 GPS 提示条提到状态胶囊原本的槽位（乘客模式不显示状态胶囊），
   否则提示条会压在 Hero 上沿。
   ⚠️ 2026-10-13 顶栏改版（多出地名一行 +0.36rem）⇒ 两处同步下移 0.28rem：
      1.92 → 2.20rem / 1.02 → 1.30rem。与司机模式用的同一份「顶栏高」口径，
      别只改上面不改这里（乘客模式下的错位只在切角色后才看得到）。 */
.g3-root.g3-passenger .g3-pstack { top: calc(env(safe-area-inset-top) + 2.20rem); }
.g3-root.g3-passenger .g3-notice { top: calc(env(safe-area-inset-top) + 1.30rem); }
.g3-pstack > .g3-hero { flex: none; }
/* 字幕卡：短文案贴身，长文案内部滚动（min-height:0 才能让 flex 子项真正收缩） */
.g3-pstack > .g3-subs { flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.g3-pstack > .g3-playbar { flex: none; }
/* 等待卡吃掉整块高度并居中，避免「上方一大片空白」 */
.g3-pstack > .g3-waitcard { flex: 1 1 auto; min-height: 0; }

.g3-mini-arrow {
  width: 0.26rem; height: 0.26rem; flex: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2312201C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h15M13 6l6 6-6 6'/%3E%3C/svg%3E") center/contain no-repeat;
}

/* 切向乘客确认卡：居中显示，本体自带白底与描边，外层不参与着色 */
.modal.g3-confirm-wrap {
  align-self: center;
  background: transparent;
  padding: 0 0.32rem;
  border-radius: 0;
}

/* ==========================================================================
   X. 两个快捷按钮 + 两个半屏弹层（派工单 19 §1 / 派工单 20 任务二）
   --------------------------------------------------------------------------
   依据 `docs/design/SPEC-导览页-快捷按钮与点位图标.md` §1 / §3.1 / §3.2 / §3.3 / §3.4。
   换算基准：375 宽设备 `1rem = 50px`（设计稿 px ÷ 50），❌切勿 ÷100。

   ⚠️ 与既有两片底部弹层（`.g3-panel` / `.g3-vol`）的关系：
      「一个字不动」。新弹层另起 `.g3-qpanel`，内距 24 与既有 `.g3-panel` 的 16 不同
      **是有意的**（与讲解卡内距 24 一致）；别为了「统一」回头去改 `.g3-panel`。
   ⚠️ 新类名全部避开既有点位气泡的 `poi` 前缀（`.g3-poi` 及其 12 个子类是引擎依赖选择器）。
   ========================================================================== */

:root {
  --g3-quick-h: 0.64rem;        /* 32px 胶囊高 */
  --g3-quick-w: 1.92rem;        /* 96px 胶囊宽（下限：再收 12px「所在市」就贴右内距） */
  --g3-quick-r: 999px;
}

/* —— 容器：只负责定位，不含视觉 ——
   与 `.map-tools` 同一条右对齐竖线（右边缘 x=359），工具列上方相邻，分组间距 28px
   （胶囊组底边 272 → 工具列顶边 300）。左边缘因宽度不同不齐（263 vs 319）**是有意的**。 */
.g3-quicks {
  position: absolute; right: 0.32rem;
  top: 4rem;                                       /* y=200 */
  z-index: 8;
  display: flex; flex-direction: column;
  gap: 0.16rem;                                    /* 8px：两胶囊间距 = 步进 40 − 32 */
}
.g3-quick {
  width: var(--g3-quick-w); height: var(--g3-quick-h);
  border-radius: var(--g3-quick-r);
  display: flex; align-items: center;
  padding: 0 0.24rem;                              /* 左右各 12 */
  box-sizing: border-box;
  background: #FFFFFF;
  box-shadow: 0 0.02rem 0.08rem rgba(27, 59, 49, .10);
  color: var(--g3-green);
  font-size: 0.24rem; font-weight: 600;             /* 12px SemiBold */
  /* 铁律：值文案永不换行（最长「所在市」= 36px，可用区 54px，放得下且余 18px） */
  white-space: nowrap;
  cursor: pointer; user-select: none;
  transition: background-color .12s, transform .12s, box-shadow .12s;
}
.g3-quick svg { width: 0.28rem; height: 0.28rem; flex: none; display: block; }
.g3-quick span { margin-left: 0.08rem; }            /* 图标与文字间距 4px */
.g3-quick:active,
.g3-quick.is-down {
  background: var(--g3-green-soft);
  box-shadow: none;
  color: var(--g3-green-d);
  transform: scale(.96);
}
/* 无值态：从未设置过（**不是**「选了 0 个」—— 所以文案是「未设置」，永远不出现「0 项」） */
.g3-quick.is-unset {
  background: #F1F5F3;
  box-shadow: var(--g3-shadow-sm);
  color: var(--g3-ink-4);
}

/* —— 半屏弹层外壳 —— */
.g3-qscrim {
  position: fixed; inset: 0; z-index: 1150;
  background-color: rgba(18, 32, 28, .22);          /* = 既有 .g3-scrim，不引入新值 */
}
.g3-qpanel {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 1151;
  padding: 0.48rem 0.48rem calc(0.44rem + env(safe-area-inset-bottom));
  background-color: #FFFFFF;
  border-radius: 0.48rem 0.48rem 0 0;               /* 24px，沿用既有 .g3-panel 的顶角 */
  box-shadow: 0 -0.16rem 0.5rem rgba(18, 32, 28, .16);
}
.g3-qpanel-grip {
  width: 0.8rem; height: 0.08rem; border-radius: 999px;
  background-color: var(--g3-line);
  margin: 0 auto 0.32rem;                           /* 抓手居中 y=12，标题 y=28 */
}
.g3-qpanel-title { font-size: 0.36rem; font-weight: 700; color: var(--g3-ink); }   /* 18px Bold */
.g3-qpanel-sub   { margin-top: 0.1rem; font-size: 0.24rem; color: var(--g3-ink-4); }
/* 脚注：12px。⚠️ 其中「不影响轨迹记录」「至少要保留 1 项」两句是**防误解**的，
   必须原样保留（详见 SPEC §3.3 / §3.4），改文案等于把这条护栏拆了。 */
.g3-qnote {
  margin-top: 0.36rem;
  font-size: 0.24rem; line-height: 1.5; color: var(--g3-ink-3);
}

/* —— 听取范围：四档单选列表 ——
   ⚠️ 前两档是「距离」、后两档是「行政区」——**不是同一把尺子**，所以只能四行单选，
      不能做成滑块（滑块会暗示「同一个连续维度」）。 */
.g3-qrow {
  display: flex; align-items: center;
  height: 1.2rem;                                   /* 60px */
  padding: 0 0.32rem;                               /* 左右各 16 */
  margin-top: 0.16rem;                              /* 步进 68 = 60 + 8 */
  border-radius: 0.32rem;                           /* 16px */
  background: #FFFFFF;
  cursor: pointer;
}
.g3-qrow-main { min-width: 0; }
.g3-qrow-name { font-size: 0.3rem; font-weight: 600; color: var(--g3-ink); }          /* 15px SemiBold */
.g3-qrow-desc { margin-top: 0.04rem; font-size: 0.24rem; color: var(--g3-ink-4); }    /* 12px */
.g3-qradio {
  width: 0.44rem; height: 0.44rem; border-radius: 50%;
  border: 1px solid var(--g3-line);
  background: #FFFFFF; flex: none; margin-left: auto;
  display: flex; align-items: center; justify-content: center;
}
.g3-qradio i { display: none; width: 0.2rem; height: 0.2rem; }                        /* 10×10 勾 */
.g3-qrow.is-on { background: var(--g3-green-soft); }                                  /* #E6EFEC */
.g3-qrow.is-on .g3-qrow-name { color: var(--g3-green-d); }                            /* #0A4F41 */
.g3-qrow.is-on .g3-qrow-desc { color: var(--g3-ink-2); }                              /* #3D514B */
.g3-qrow.is-on .g3-qradio { background: var(--g3-green); border-color: var(--g3-green); }
.g3-qrow.is-on .g3-qradio i { display: block; }

/* —— 兴趣偏好：六类勾选 —— */
.g3-qcat {
  height: 0.96rem;                                  /* 48px */
  margin-top: 0.12rem;                              /* 步进 54 = 48 + 6 */
  border-radius: 0.28rem;                           /* 14px */
  display: flex; align-items: center;
  padding: 0 0.28rem;                               /* 左右各 14 */
  background: var(--g3-green-soft);                 /* 选中态 #E6EFEC */
  cursor: pointer;
}
.g3-qcat-ico { width: 0.4rem; height: 0.4rem; flex: none; color: var(--g3-green); display: block; }
.g3-qcat-name { margin-left: 0.2rem; font-size: 0.28rem; font-weight: 600; color: var(--g3-green-d); }
.g3-qcat-box {
  margin-left: auto; width: 0.4rem; height: 0.4rem; /* 20px */
  border-radius: 0.12rem;                           /* 6px */
  background: var(--g3-green); color: #FFFFFF;
  flex: none;
  display: flex; align-items: center; justify-content: center;
}
.g3-qcat-box i { width: 0.24rem; height: 0.24rem; display: block; }                   /* 12×12 勾 */
.g3-qcat.is-off { background: #FFFFFF; box-shadow: var(--g3-shadow-sm); }
.g3-qcat.is-off .g3-qcat-name { color: var(--g3-ink); }
.g3-qcat.is-off .g3-qcat-ico { color: var(--g3-ink-4); }
.g3-qcat.is-off .g3-qcat-box { background: transparent; border: 1px solid var(--g3-line); }
.g3-qcat.is-off .g3-qcat-box i { display: none; }

