/* ============================================================
   css/panels/panels-growth-map.css — 「成长 -> 我的语言地图」（第四阶段，前缀 gm- 独占）
   ------------------------------------------------------------
   [第四阶段] 第四版范式 · 火车车窗（甲方拍板锁死）：
     不是"App 里放一扇窗"，而是"她坐在火车里，窗外的世界正从她眼前经过"。
     画面层次：车厢顶 -> 行李架/顶灯 -> 报站屏 -> 大车窗 -> 窗外远/中/近三层 -> 窗帘
              -> 窗台 -> 人（背影）-> 咖啡杯 -> 座椅。
     · 三层风景速度比 **远景 : 中景 : 近景 = 1 : 2 : 4**，只许 transform
     · 场景切换只许 opacity（清晨 / 傍晚 / 夜）
     · 当前站**不许发光**：玫瑰淡底 + 玫瑰字 + 法式金细短下划线
     · 车厢内部比窗外暗一档，窗外自然成为视觉焦点（不靠任何发光）
     · 全屏不许出现分数/进度条

   已全部删除（不再迭代）：窄路、双边道路、节点圆点、当前位置圆、'你在这里'药丸、
     呼吸光环、底部圆点、纸面细痕、园林地形。
   ============================================================ */

/* ===== 画布 =====
   [注意] 宽度 100%、高度不写死：靠 SVG 自己的 viewBox 比例撑开（332:470）。
     踩过的坑：JS 内联过一个 height 盖掉 CSS -> 两套尺寸，整组元素错位一百多像素。 */
.gm-canvas { position: relative; width: 100%; }
/* [注意] 尺寸**锁死**（外部评审拍板）：上一版按屏宽等比撑大，430 屏车厢跑到 378×535、占屏 50%，
   看着像"一张巨型插画贴满屏"。现在封 360 宽，再宽就两侧自然留白。
   [注意] 上一版我写的是 `calc(100% - 28px)`，又减了一刀 —— 而这层外面本来就有 14px 边距
   （实测 360 屏只剩 308 宽），于是车厢反而更小了。边距只能让一次，别再减。 */
.gm-stage { position: relative; width: min(360px, 100%); margin: 0 auto; }
.gm-car { display: block; width: 100%; height: auto; }

/* ===== 场景三套（**只切 opacity**，不切别的）=====
   清晨 = .gm-stage 的默认值（不加类）。傍晚 / 夜只换这套变量，HTML 结构一模一样。 */
.gm-stage {
    --sky-a: #E6D8D1; --sky-b: #F5ECE5;      /* 天空 */
    --far: #C9BBB4; --mid: #A69D96; --near: #756C66;   /* 远 / 中 / 近 */
    --car-in: #4B423D;                        /* 车厢内部（比窗外暗一档） */
}
.gm-stage.is-evening { --sky-a: #CBA7A3; --sky-b: #E8CDBD; --far: #9F8B89; --mid: #756B69; --near: #494442; --car-in: #3C3431; }
.gm-stage.is-night   { --sky-a: #2E2A31; --sky-b: #4B4248; --far: #67606A; --mid: #3F3A40; --near: #29262B; --car-in: #312B29; }

/* ===== 车厢顶 / 行李架 / 顶灯 ===== */
.gm-ceiling { fill: var(--car-in); opacity: 0.92; }
.gm-ceiling-line { fill: none; stroke: rgba(255,250,245,0.10); stroke-width: 1; }
.gm-rack { fill: none; stroke: rgba(196,168,106,0.50); stroke-width: 1; stroke-linecap: round; }
/* 顶灯：一个很小的暖色椭圆，**不发光**（这里曾经加过 0 0 20px 的箱影影，被明令删掉） */
.gm-lamp { fill: rgba(255,244,226,0.70); }

/* ===== 站牌（车厢铭牌，不是黑色 LED 屏）=====
   四个成长站 S1~S4：当前站最大最深，上一站次之，下一站有存在感但明显更轻，更远只作背景。
   **只写站名，绝不写任何内部能力数值**（外部评审明令）。 */
.gm-board-bg { fill: rgba(248,244,239,0.92); stroke: rgba(180,160,140,0.22); stroke-width: 1; }
.gm-sign-en { font-size: 7.5px; fill: #C9C2B8; letter-spacing: 0.08em; }
.gm-sign-nowbg { fill: rgba(201,168,168,0.14); }
.gm-sign-tick { fill: #C4A86A; }
.gm-sign-idx { font-size: 8px; fill: #C9C2B8; letter-spacing: 0.08em; }
.gm-sign-name { font-size: 11px; fill: #BFB8AE; }
.gm-sign-idx.is-now, .gm-sign-name.is-now { fill: #A88080; }
.gm-sign-name.is-now { font-weight: 500; }
.gm-sign-idx.is-past, .gm-sign-name.is-past { fill: #8A8278; }
.gm-sign-idx.is-next { fill: #A8A096; }
.gm-sign-name.is-next { fill: #6F6862; }
.gm-sign-idx.is-far, .gm-sign-name.is-far { fill: #D2CBC2; }
/* 站名可能四个字（如"能读会写"），窗口一格约 60px —— 给一格留得住的最小字号 */
.gm-sign-name { font-size: 10.5px; }
/* 到站那一下的换站：只动 opacity + 一点点位移（外部评审拍板的 420ms 内完成），
   不缩放、不弹、不闪。车厢、人、窗框、窗帘一律不动。 */
@keyframes gm-sign-swap { 0% { opacity: 1; } 45% { opacity: 0.15; } 100% { opacity: 1; } }
.gm-sign.is-swap { animation: gm-sign-swap 0.42s var(--ec-ease) both; }
@media (prefers-reduced-motion: reduce) { .gm-sign.is-swap { animation: none; } }

/* ===== 场景两组风景叠着，只动 opacity（真的交叉淡入，不是换颜色变量）=====
   [注意] 上一版是靠 custom property 直接换颜色 = 硬切；评审指出那不符合"只动 opacity"的约定。
   现在 day / night 是**两组真的风景**，切换时一组退一组进；.gm-stage 的变量只负责车厢与天空基调。 */
.gm-scene { transition: opacity 460ms cubic-bezier(0.22, 0.61, 0.36, 1); }
.gm-scene.is-day { opacity: 1; }
.gm-scene.is-night { opacity: 0; }
.gm-stage.is-night .gm-scene.is-day { opacity: 0; }
.gm-stage.is-night .gm-scene.is-night { opacity: 1; }
.gm-night-sky { fill: var(--sky-a); }
@media (prefers-reduced-motion: reduce) { .gm-scene { transition: none; } }

/* ===== 读取失败：如实说，不伪造任何成长进度 ===== */
.gm-fail { padding: 26px var(--ec-gutter) 0; }
.gm-fail-h { font-family: var(--font-display, var(--font-body)); font-size: 18px; color: var(--ec-ink); }
.gm-fail-p { margin-top: 8px; font-size: 12.5px; line-height: 1.85; color: var(--ec-sub); }

/* ===== 「下一站需要什么」：三态文案（已达标 / 还差 / 还没有数据）=====
   [注意] 绝不显示「0 / 40」这种内部数值，也绝不把"没测过"显示成 0。 */
/* ===== 「下一站需要什么」那一块独立牌子**已删**（外部评审：同一个信息在车厢和车票上说两遍，
   看着像"仪表盘 + 一张插画"）。现在：报站牌只管"我在哪"，下一站差什么只住在车票里。
   那几条三态样式（.gm-needs-*）随之一并删掉，不留死样式。 */

/* ===== 车窗：双线窗框（外 2px 深木色 + 内 .75px 高光）= 真正有厚度的框，不是 CSS 方框 ===== */
.gm-win-frame { fill: none; stroke: #7E7067; stroke-width: 2; }
.gm-win-inner { fill: none; stroke: rgba(255,250,245,0.32); stroke-width: 0.75; }
/* 玻璃反光**只放一条**（左上->右下约 20°），不是一整块白三角 */
.gm-glare { fill: none; stroke: rgba(255,250,245,0.09); stroke-width: 3.5; stroke-linecap: round; }

/* ===== 窗外三层景（速度比 1 : 2 : 4；只动 transform）===== */
.gm-sky-a { stop-color: var(--sky-a); }
.gm-sky-b { stop-color: var(--sky-b); }
/* 远（最慢）：几条柔和的远山脊 */
.gm-far { fill: var(--far); opacity: 0.86; }
/* 中（中速）：树线（弧，不是整圆）+ 缓坡 */
.gm-mid { fill: var(--mid); opacity: 0.82; }
.gm-mid-fill { fill: var(--mid); opacity: 0.62; }
/* 近（最快）：地面带 + 电线杆/细树干（**只做这一种近景**） */
.gm-near-ground { fill: var(--near); opacity: 0.30; }
.gm-near { fill: none; stroke: var(--near); stroke-width: 3; stroke-linecap: round; opacity: 0.55; }
/* 玻璃里的一条极淡地平线：让人读出"远处"与"近处" */
.gm-horizon { fill: none; stroke: rgba(255,250,245,0.16); stroke-width: 1; }

/* 车厢内壁（窗台以下）：比窗外暗一档 —— 窗外自然成为视觉焦点，不靠任何发光。
   [注意] 这块原来和人的背影**一样深**，接在一起像"半个人下面接了一块深布"（甲方原话"腰斩"）。
   现在内壁调成一档更暖更浅的木色，人贴在内壁前面才有前后关系，断面也不再那么刺眼。 */
.gm-panel { fill: color-mix(in srgb, var(--car-in) 62%, #F8F4EF); }
.gm-panel-hi { fill: none; stroke: rgba(255,250,245,0.10); stroke-width: 1; }
/* 座椅：最靠前的一条，只压住人的最下缘 —— 于是"她坐在座位上"，而不是被切断 */
.gm-seat-back { fill: color-mix(in srgb, var(--car-in) 84%, #F8F4EF); }
.gm-seat-hi { fill: none; stroke: rgba(255,250,245,0.12); stroke-width: 1; }

/* 视差：每条层都"比窗户宽"，平移一段就无缝接着走（所以能一直动下去） */
.gm-layer { will-change: transform; }
@keyframes gm-pan-far  { from { transform: translateX(0); }     to { transform: translateX(-143px); } }
@keyframes gm-pan-mid  { from { transform: translateX(0); }     to { transform: translateX(-286px); } }
@keyframes gm-pan-near { from { transform: translateX(0); }     to { transform: translateX(-572px); } }
/* 周期与位移按 1 : 2 : 4（远近不同速，才像真的在开） */
.gm-l-far  { animation: gm-pan-far 12s linear infinite; }
.gm-l-mid  { animation: gm-pan-mid 6s linear infinite; }
.gm-l-near { animation: gm-pan-near 3s linear infinite; }
/* 减少动态效果：风景停住（保留全部静态可读性），热气也停 */
@media (prefers-reduced-motion: reduce) {
    .gm-l-far, .gm-l-mid, .gm-l-near { animation: none; }
    .gm-steam { animation: none; opacity: 0.30; }
}

/* ===== 窗帘（左右各一小片，2~3 个褶皱；只告诉人"这是车厢里的窗"）===== */
.gm-curtain { fill: #E8DDD3; opacity: 0.96; }
.gm-curtain-line { fill: none; stroke: rgba(180,160,140,0.20); stroke-width: 1; }

/* ===== 人（背影；两层 + 一条极薄肩线高光 -> 像真的坐在那里，不是一个剪影 icon）===== */
.gm-fig-outer { fill: #3B3430; opacity: 0.96; }
.gm-fig-inner { fill: rgba(78,67,61,0.78); }
.gm-fig-hi { fill: none; stroke: rgba(255,250,245,0.12); stroke-width: 1.4; stroke-linecap: round; }

/* ===== 窗台 / 咖啡杯 / 座椅 ===== */
.gm-sill { fill: #B8AAA0; }
.gm-sill-hi { fill: none; stroke: rgba(255,250,245,0.40); stroke-width: 1; }.gm-cup-rim { fill: #E8DDD3; stroke: rgba(180,160,140,0.30); stroke-width: 0.8; }
.gm-cup-body { fill: #E8DDD3; }
.gm-cup-handle { fill: none; stroke: #E8DDD3; stroke-width: 1.4; }
.gm-steam { fill: none; stroke: rgba(255,250,245,0.35); stroke-width: 1; stroke-linecap: round; animation: gm-puff 2.8s ease-in-out infinite; }
.gm-steam.is-b { animation-delay: 0.6s; }

/* ===== 车厢下面：车票（不是普通卡片，是一张票）=====
   两联：上联＝成长站要补什么（真实证据驱动）｜下联＝现实目的地的官方要求。
   两条线**不混算**：成长站门槛来自系统内部，官方要求来自真实门槛库。 */
/* 车票：**压着座椅上沿**、票在座位上的那道投影 —— 让它属于车厢，而不是 SVG 下面隔 14px 的一张卡。
   [注意] 上一版是 margin-top:14px 的圆角白卡（评审：给它起名叫 ticket 但它还是普通 Card）。
   现在：上边负外边距压进座椅、更薄、纸感（极淡的横向纹理 + 一条撕票线），并且收敛了内容。 */
.gm-canvas { position: relative; }
.gm-ticket {
    position: relative;
    margin: -18px var(--ec-gutter) 0;
    background: linear-gradient(#FFFDFA, #FBF6F0);
    border: 1px solid rgba(180,160,140,0.26);
    border-radius: 8px;
    padding: 10px 14px 9px;
    box-shadow: 0 6px 18px rgba(60,48,40,0.10), 0 1px 0 rgba(255,255,255,0.7) inset;
}
/* 票根那一小段：左侧一条极淡的票根齿（不用图片，纯 CSS） */
.gm-ticket::before {
    content: ''; position: absolute; left: 0; top: 8px; bottom: 8px; width: 3px;
    background: repeating-linear-gradient(180deg, rgba(180,160,140,0.30) 0 3px, transparent 3px 7px);
    border-radius: 8px 0 0 8px;
}
.gm-tk-top { display: flex; align-items: baseline; justify-content: space-between; }
.gm-tk-en {
    font-family: 'Playfair Display', 'Great Vibes', serif; font-style: italic;
    font-size: 10px; letter-spacing: 0.14em; color: var(--ec-faint);
}
.gm-tk-no { font-size: 9px; letter-spacing: 0.08em; color: #D2CBC2; }
.gm-tk-main { display: flex; align-items: stretch; gap: 8px; margin-top: 8px; }
.gm-tk-col { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.gm-tk-col.is-right { text-align: right; }
.gm-tk-arrow { flex: 0 0 26px; position: relative; align-self: center; }
/* 中间那道很细的金色箭头线（不是大箭头图标） */
.gm-tk-arrow::before {
    content: ''; position: absolute; left: 0; right: 4px; top: 50%;
    height: 1px; background: rgba(196,168,106,0.55);
}
.gm-tk-arrow::after {
    content: ''; position: absolute; right: 0; top: 50%; width: 5px; height: 5px;
    margin-top: -2.5px; border-top: 1px solid rgba(196,168,106,0.75); border-right: 1px solid rgba(196,168,106,0.75);
    transform: rotate(45deg);
}
.gm-tk-k { font-size: 10px; letter-spacing: 0.04em; color: var(--ec-faint); }
.gm-tk-v {
    font-family: var(--font-display, var(--font-body));
    font-size: 14px; line-height: 1.4; color: var(--ec-ink);
}
/* 票中间那道"撕开线" */
.gm-tk-cut { margin: 10px 0 9px; height: 1px; background: repeating-linear-gradient(90deg, rgba(180,160,140,0.30) 0 4px, transparent 4px 9px); }
.gm-tk-half + .gm-tk-half { margin-top: 11px; padding-top: 10px; border-top: 1px dashed rgba(180,160,140,0.20); }
.gm-tk-half-h { font-size: 11.5px; color: var(--ec-sub); letter-spacing: 0.02em; }
.gm-tk-reqs { margin-top: 6px; display: flex; flex-direction: column; gap: 4px; }
.gm-tk-req { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.gm-tk-req-k { font-size: 12px; color: var(--ec-sub); }
.gm-tk-req-v { font-size: 12px; letter-spacing: 0.02em; }
.gm-tk-req-v.is-ok { color: #8FA383; }
.gm-tk-req-v.is-behind { color: #A88080; }
.gm-tk-req-v.is-none { color: var(--ec-muted, #BFB8AE); }
.gm-tk-quiet { margin-top: 6px; font-size: 12px; color: var(--ec-faint); }
.gm-tk-note { margin-top: 5px; font-size: 11.5px; line-height: 1.75; color: var(--ec-sub); }
/* 官方要求与练习估计**并排摆**（主票只留这一组，绝不硬算"还差 X 分"）
   [注意] 上一版主票把总分/单项/中文转述/状态/核验日期全展开 = 一份签证资料。
   现在主票只留：官方要求一行 + 你的练习估计一行 + 来源日期一行 + 两个入口。 */
.gm-tk-cmp { margin-top: 6px; display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.gm-tk-cmp-k { font-size: 11px; letter-spacing: 0.03em; color: var(--ec-faint); }
.gm-tk-cmp-v { font-size: 12.5px; color: #A88080; }
.gm-tk-cmp-v.is-est { color: var(--ec-ink); }
.gm-tk-state { margin-top: 7px; font-size: 11.5px; }
/* 当前线路（章节）：只留一条极小辅助信息，六章不在地图上展开 */
.gm-tk-chap { margin-top: 3px; font-size: 10.5px; letter-spacing: 0.02em; color: var(--ec-muted, #BFB8AE); }

/* ===== 官方要求详情层（全部条件逐条列；来源与核验日期也放这里，主票不塞）===== */
.gm-req-sheet { padding: 2px 0 0; }
.gm-req-route { font-family: var(--font-display, var(--font-body)); font-size: 17px; color: var(--ec-ink); }
.gm-req-aud { margin-top: 5px; font-size: 12px; color: var(--ec-sub); }
.gm-req-list { margin-top: 12px; display: flex; flex-direction: column; gap: 10px; }
.gm-req-row { padding: 10px 12px; background: rgba(255,255,255,0.55); border: 1px solid rgba(180,160,140,0.20); border-radius: 9px; }
.gm-req-row-h { font-size: 11px; letter-spacing: 0.05em; color: var(--ec-faint); }
.gm-req-row-v { margin-top: 4px; font-size: 13px; color: #A88080; }
.gm-req-row-m { margin-top: 3px; font-size: 12px; color: var(--ec-muted, #BFB8AE); }
.gm-req-row-m.is-est { color: var(--ec-sub); }
.gm-req-text { margin-top: 12px; font-size: 12px; line-height: 1.85; color: var(--ec-sub); }
.gm-req-src { margin-top: 10px; font-size: 10.5px; line-height: 1.7; letter-spacing: 0.02em; color: #D2CBC2; }
.gm-req-note { margin-top: 12px; font-size: 11.5px; line-height: 1.8; color: var(--ec-faint); }
.gm-tk-state.is-ok { color: #8FA383; }
.gm-tk-state.is-behind { color: #A88080; }
.gm-tk-state.is-none { color: var(--ec-faint); }
.gm-tk-verify { margin-top: 6px; font-size: 10px; letter-spacing: 0.03em; color: #D2CBC2; }
.gm-tk-pick, .gm-tk-change {
    margin-top: 8px; padding: 0; border: 0; background: none;
    font-size: 12px; color: #A88080; letter-spacing: 0.02em;
    border-bottom: 1px solid rgba(168,128,128,0.32); line-height: 1.9;
}
.gm-tk-foot { margin-top: 11px; padding-top: 9px; border-top: 1px solid rgba(180,160,140,0.16); display: flex; align-items: baseline; gap: 8px; }
.gm-tk-step { font-size: 12px; color: var(--ec-ink); }
/* 「最新一笔」显影：只动 opacity 与 translateY（像纸上刚盖出来的一行字，不缩放、不弹、不闪） */
@keyframes gm-ink-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
.gm-tk-foot.is-fresh .gm-tk-step { animation: gm-ink-in 0.32s var(--ec-ease) both; }

/* ===== 目的地选择抽屉 ===== */
.gm-dest-sheet { padding: 2px 0 0; }
.gm-dest-h {
    font-family: var(--font-display, var(--font-body));
    font-size: 18px; color: var(--ec-ink);
}
.gm-dest-sub { margin-top: 6px; font-size: 12px; line-height: 1.8; color: var(--ec-sub); }
.gm-dest-list { margin-top: 12px; display: flex; flex-direction: column; gap: 9px; }
.gm-dest-row {
    text-align: left; width: 100%; padding: 11px 12px;
    background: rgba(255,255,255,0.55);
    border: 1px solid rgba(180,160,140,0.22); border-radius: 10px;
    display: flex; flex-direction: column; gap: 3px;
}
.gm-dest-row.is-on { border-color: rgba(168,128,128,0.5); background: rgba(201,168,168,0.10); }
.gm-dest-flag { font-size: 10px; letter-spacing: 0.06em; color: var(--ec-faint); }
.gm-dest-name { font-size: 14px; color: var(--ec-ink); }
.gm-dest-score { font-size: 12px; color: #A88080; }
.gm-dest-src { font-size: 10px; letter-spacing: 0.03em; color: #D2CBC2; }

/* ===== 页首（一行小斜体 + 一个很小的声音开关；别再把"地图"二字做成视觉重点）===== */
.gm-head { display: flex; align-items: center; justify-content: space-between; }
.gm-lead-en {
    font-family: 'Playfair Display', 'Great Vibes', serif; font-style: italic;
    font-size: 13px; letter-spacing: 0.06em; color: var(--ec-faint);
}
/* 声音开关：自绘的线性音波（触摸目标 44），静音时只是一条压平的线 */
.gm-sound {
    width: 44px; height: 44px; margin: -12px -10px -12px 0;
    border: 0; background: none; padding: 0;
    display: flex; align-items: center; justify-content: center;
}
.gm-sound svg { width: 22px; height: 22px; }
.gm-sound svg path {
    fill: none; stroke: #C9C2B8; stroke-width: 1.4; stroke-linecap: round;
    transition: stroke 0.24s var(--ec-ease), opacity 0.24s var(--ec-ease);
}
.gm-sound.is-on svg path { stroke: #A88080; }
.gm-sound:active svg path { opacity: 0.6; }

/* 窄屏收紧（只动字号；画面几何一律不动） */
@media (max-width: 369px) {
    .gm-tk-v { font-size: 13px; }
    .gm-dest-name { font-size: 13px; }
}
