/* ══════════════════════════════════════════════════════════════════════════
   my-growth.css —— 「🌱 我的成长」整页的样式（/my-growth.html 专用）✓

   ★★ 为什么单独一个文件 ✗✗
     · components.css / themes.css 里【有别的改动正在进行】✗（主题色 + 领巾 ✓）
       ⇒ 本轮【一个字都不改它们】✗ 免得冲突 ✓
     · 本文件自包含 ✓ 不依赖组件库 ✓（页面本身也不引入 components.css ✓）
       理由：这是一个【独立整页】✗ 不是首页的一部分 ✓
             引入 73KB 的组件库只为了几个按钮不划算 ✓
     · 配色【照抄】components.css / themes.css 的真实 token ✓ 不自己发明 ✓：
         --mg-primary #12b3a0（青绿主色）· --mg-primary-dark #0f8f74
         --mg-gold #e8b33c · --mg-navy #123A72 · --mg-page #eef4f8

   ★★ RTL（ar / fa）✗✗ —— 全部用【逻辑属性】
       margin-inline / padding-inline / inset-inline-* / text-align:start|end
       ★ 绝不用 row-reverse ✗（仓库里为此踩过坑 ✓ flex/grid 会跟着 dir 自动翻转 ✓）

   ★★ 动画 ✗✗ —— 一律【尊重】prefers-reduced-motion ✓ 不做豁免 ✗
       （components.css 里那条 `*{animation:none!important}` 带 !important ✓
         本页在 reduce 下【本来就应该静止】✓ 所以不去跟它对抗 ✓）
   ══════════════════════════════════════════════════════════════════════════ */

:root{
  --mg-primary:#12b3a0;
  /* ★★ 对比度（全站巡检 25 条）：本页有 4 处要 4.5:1 的地方压在这个色上 ✗
     实测 #0f8f74 = 4.04:1（白字徽章）/ 3.71:1（浅底文字）✗
     ⇒ 按 design-tokens.css 里"若要让青绿小字完全达标 AA ⇒ 把本值改成 #0e8570（4.56:1）"
       的既定建议取 #0e8570 ✓ 只改这一个 token ✗ 字号与版式一律不动 ✓ */
  --mg-primary-dark:#0e8570;
  --mg-gold:#e8b33c;
  --mg-gold-dark:#b8860b;
  --mg-navy:#123A72;
  --mg-page:#eef4f8;
  --mg-card:#ffffff;
  --mg-soft:#f4f9fd;
  --mg-ink:#1f2d3d;
  /* ★ 对比度：11.5px 小字在白底/浅底上是辅助文字 ✗ 巡检里 #mgSub / #mgPerksSub
     都是 4.29:1 ✗ 差 0.21 ✗ ⇒ 加深一档到 #556577（本页浅底上 5.3~6.8:1 ✓）
     ★ 只改本页的局部变量 ✗ 不动全局 --muted（那是第 3 步色值收敛的事 ✓）*/
  --mg-muted:#556577;
  --mg-line:#dfe8f0;
  --mg-radius:22px;
  --mg-shadow:0 10px 30px rgba(18,58,114,.08);
  /* ★ 第 35 轮：本页 /fredoka.css 已经加载 ✓ 但 --mg-display 里【没有 'Fredoka'】✗
     ⇒ 实测 0 个 woff2 被下载 ✗ 整页标题一直是系统字体 ✓
     修法：把 'Fredoka' 插在 ui-rounded 之后、中文字体之前 ✓
     （理由与 themes.css 的 --font-display 完全一致 ✓：
       Fredoka 只有拉丁字形 ✗ 汉字自动往后退到 Yuanti SC / YouYuan / 苹方 ✓
       ⇒ 汉字观感不变 ✓ 拉丁字母终于用上自带的圆体 ✓✓）
     ★ 只改这一行 ✗ 本文件其它内容一律不动 ✓ */
  /* ★★★ 第 2 步：本页的字体栈【退役】✗ 改为指向设计令牌 ✓
     · 原来是【第三套】字体栈：--mg-display 里没有 themes.css 的 --font-display
       那么长的中文回退链 ✗ 于是成长页标题与首页标题不是同一套 ✓
     · 现在只做别名 ✗ 本文件里 11 处 var(--mg-display) / 1 处 var(--mg-body)
       【一处都不用改】✗ 全站自动收敛 ✓
     · ★ 本页没引 themes.css ✗ 所以 --font-display 未定义 ✓
       由 design-tokens.css 的兜底栈接管 ✓ 该栈与被替换掉的旧值【逐项一致】✓
       ⇒ 拉丁字母照旧走自托管 Fredoka ✗ 汉字照旧走 Noto Sans SC ✓ 零位移 ✓ */
  --mg-display:var(--ce-font-display);
  --mg-body:var(--ce-font-body);
}

*{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  font-family:var(--mg-body);
  background:var(--mg-page);
  color:var(--mg-ink);
  line-height:1.6;
  min-height:100vh;
}
img{max-width:100%;height:auto}
a{color:var(--mg-primary-dark)}
button{font:inherit;color:inherit;cursor:pointer;border:0;background:none}
bdi{unicode-bidi:isolate}

/* ★ 数字与拉丁串的通用包裹 ✓（RTL 下不反转 ✓ 与 growth-cards 同一手法 ✓）*/
.mg-num{unicode-bidi:isolate}

/* ── 跳过导航（无障碍 ✓）── */
.mg-skip{
  position:absolute;inset-block-start:-60px;inset-inline-start:12px;z-index:80;
  background:var(--mg-navy);color:#fff;padding:10px 16px;border-radius:0 0 12px 12px;
  font-weight:var(--ce-fw-head);text-decoration:none;
}
.mg-skip:focus{inset-block-start:0}

/* ══════════════════════════════════════════════════════════════════
   ① 页头（index.html 那套的【简化版】✓）
   ══════════════════════════════════════════════════════════════════ */
.mg-top{
  background:linear-gradient(135deg,var(--mg-navy),var(--mg-primary-dark));
  color:#fff;position:sticky;inset-block-start:0;z-index:40;
  box-shadow:0 4px 20px rgba(18,58,114,.18);
}
.mg-topin{
  max-width:1120px;margin-inline:auto;padding:10px 16px;
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
}
.mg-logo{
  width:44px;height:44px;object-fit:contain;border-radius:14px;
  background:#fff;padding:3px;box-shadow:0 3px 0 rgba(0,0,0,.15);flex:0 0 auto;
}
.mg-brand h1{font-family:var(--mg-display);font-size:25px;font-weight:var(--ce-fw-head);letter-spacing:.2px}
.mg-brand p{font-size:15.5px;opacity:.88}
.mg-topactions{margin-inline-start:auto;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
/* ★★ 以下三条 .mg-sel 规则【本轮起已无消费者】✗（原来是那个 <select id="mgLang"> 的样式 ✓）
   保留不删 ✗ 两条理由：
     ① 本仓惯例：能救活/可复用的规则留档 ✗ 不删（见 components.css 里同样留档的旧规则 ✓）
     ② .mg-sel 是个通用"页头胶囊下拉"样式 ✗ 将来若要再放一个 select（如排序 / 筛选 ✓）
        直接可用 ✓ 删了就得重写一遍 ✓
   ★ 但【它现在确实一个元素都不匹配】✗ 别误以为语言下拉还在用它 ✗✗
     语言下拉现在是 .lang-wrap + #mgLangBtn + .lang-menu（见下面那一大段 ✓）*/
.mg-sel{
  background:rgba(255,255,255,.16);border:1.5px solid rgba(255,255,255,.32);
  color:#fff;border-radius:99px;padding:7px 12px;font-size:17px;font-weight:700;
  transition:background .2s;
}
.mg-sel:hover{background:rgba(255,255,255,.28)}
.mg-sel option{color:#1f2d3d}
.mg-topbtn{
  display:inline-block;text-decoration:none;
  background:rgba(255,255,255,.18);border:1.5px solid rgba(255,255,255,.32);
  color:#fff;border-radius:99px;padding:8px 16px;font-size:17px;font-weight:var(--ce-fw-head);
  transition:background .2s;
}
.mg-topbtn:hover{background:rgba(255,255,255,.32)}

/* ══════════════════════════════════════════════════════════════════
   ★★★ 语言菜单 ✗ 桌面三列 / 平板两列 / 手机单列（本轮 ✓）
   ── 为什么搬这一块进来 ✗（而不是引 components.css ✓）──────────────
     · 三列规则原本只存在于 components.css ✗ 且只对 .lang-menu 生效 ✓
     · 本页【不加载 components.css】✗（只引 design-tokens / my-growth / fredoka ✓）
     · 引整个 components.css ✗ 会把首页那 2800 行组件样式带进这一页 ✗
       回归面太大 ✗（.card / .plan / .grid … 都会盖到本页 ✓）
     ⇒ 所以只把【语言菜单这一小段】搬过来 ✓ 类名一字不改 ✓
       照搬 ⇒ 与首页【同一套类名 + 同一套断点】✗ 观感天然一致 ✓
   ── ★★ 一个必须改的地方 ✗ 颜色 token（这是本页最容易照抄出错的地方 ✗✗）──
     components.css 用的 --card / --ink / --line / --primary / --card-soft / --muted
     全部定义在 themes.css ✓ 而【本页不引 themes.css】✗（见本页 HTML :13 的既有说明 ✓）
     ⇒ 照抄过来会【全部落空】⇒ 菜单变透明 / 继承顶栏白字 ⇒ 白字压白底 ✗✗
     ⇒ 一律换成【本页自己的 --mg-* token】✓（本页 :root 里有 ✓ 已逐条核对 ✓）
        --card      ⇒ --mg-card        （白 / 深色主题下分别是 #fff 等 ✓）
        --card-soft ⇒ --mg-soft
        --ink       ⇒ --mg-ink
        --line      ⇒ --mg-line
        --primary   ⇒ --mg-primary
        --muted     ⇒ --mg-muted       （本页已按对比度加深过 ✓ 见 :root ✓）
     ★ --ce-font-body / --ce-fw-strong / --ce-fw-head 来自 design-tokens.css ✓
       本页【有引】✓（HTML :15 ✓）⇒ 这三个原样保留 ✓ 实测都在 ✓
   ══════════════════════════════════════════════════════════════════ */
.mg-langwrap{position:relative}
.mg-langbtn{cursor:pointer;font-family:inherit}
.lang-menu{
  display:none;position:absolute;top:calc(100% + 8px);inset-inline-end:0;min-width:180px;
  background:var(--mg-card);color:var(--mg-ink);padding:8px;border-radius:16px;
  box-shadow:0 16px 44px rgba(0,0,0,.18);z-index:60;border:1px solid var(--mg-line);
  /* ★ 37 条单列高 ≈1560px ✗ 必须给上限 + 滚动 ✓
     （11 项时实测 465px ⇒ 原来不出现滚动条 ✓ 现在 37 项一定会滚 ✓）*/
  max-height:min(72vh,560px);overflow-y:auto;
}
.lang-menu.open{display:block}
.lang-menu button{width:100%;border:0;background:transparent;text-align:start;padding:10px 12px;border-radius:10px;color:inherit;font-size:17px;font-weight:600;cursor:pointer}
.lang-menu button:hover{background:var(--mg-soft)}
.lang-menu button.active{background:var(--mg-soft);color:var(--mg-primary);font-weight:var(--ce-fw-head)}
/* ★ ISO 代码徽章 ✗ 纯代码 ✗ 不用国旗 ✓（与首页 / 法务页同一口径 ✓）
   ★ RTL ✗ ar / fa / he ⇒ 间距用【逻辑属性】margin-inline-end ✓ 绝不用 margin-right ✗ */
.lang-menu .lang-badge{display:inline-block;min-width:42px;margin-inline-end:8px;padding:1px 5px;border:1px solid var(--mg-line);border-radius:6px;background:var(--mg-soft);color:var(--mg-muted);font-family:var(--ce-font-body);font-size:14px;font-weight:var(--ce-fw-strong);letter-spacing:.05em;line-height:1.4;text-align:center;white-space:nowrap;vertical-align:middle}
.lang-menu button.active .lang-badge{border-color:var(--mg-primary);color:var(--mg-primary)}
/* ★★ 窄屏溢出修复（原来在 components.css ✓ 一并搬 ✓ 不能省 ✗✗）
   本页页头与首页不同 ✗ ⇒ 这一档的数值【本轮真浏览器实测过】✓ 见下方断点注释 ✓ */
@media (max-width:520px){
  .lang-menu{inset-inline-end:auto;inset-inline-start:0;min-width:0;max-width:calc(100vw - 24px)}
}
/* ── ★★★ 三档断点 ✗ 本轮在【本页】真浏览器逐档实测 ✓ 不是照抄首页的数 ✗✗ ──
   ★★★ 为什么【不能】照抄首页那三个门槛（1000 / 768 / 520）✗✗
     components.css 里那套数字是在【首页 .top 顶栏】量的 ✓ 它的前提是：
       「菜单右边缘 ≡ 视口宽 − 209」（209 = 右内边距 + 语言按钮宽 ✓ 各视口恒定 ✓）
     而本页页头是 .mg-topin（另一个结构 ✗ 右侧还多一个"← 返回首页"按钮 ✓）
     ⇒ 那个 209 的前提在本页【不成立】✗ 照抄会把断点locate错 ✓
       （实测差异有多大 ✗ 见下：本页只需 810px，首页要 946px ✗ 差 136px ✓）
   ── 实测环境（可复现 ✓）──────────────────────────────────────────────
     真 Chrome（--headless=new）· CDP Emulation.setDeviceMetricsOverride
     每次测量【新建 target】✗ 杜绝上一档的残留 ✓
     页面 = 本页真实结构（37 门全部渲染 ✓ 见 menu 计数断言 ✓）
     ★ 滚动条已计入 ✗✗：本页内容是长页 ⇒ documentElement 一定带纵向滚动条
       实测 innerWidth − clientWidth ≡ 15px ✓（808→793 / 806→791 / 800→785 一致 ✓）
       ⇒ 三档断点是 @media 在评判 ✗ @media 用的是【innerWidth】✓
         而菜单放不放得下要看【clientWidth】✓ 两者差这 15px ✓ 必须一起算 ✓
   ── 硬数字（37 门 · max-content 列宽 ✓ CSS px ✓）────────────────────
     三列：菜单实宽【634】· 实高【548】（< max-height 560 ⇒ 不滚动 ✓ 37 条全见 ✓）
     两列：菜单实宽【446】· 实高【560】（= 撞上限 ⇒ 滚动 ✓ 可见 26 条 ✓）
     一列：菜单实宽【244】
     ★ 菜单右边缘 ≡ 【innerWidth − 161】（与列数无关 ✓）
       （161 = 右内边距 16 + 语言按钮 127 + 间距 16 + 2px 描边 ✓ 实测恒定 ✓）
       ⇒ 三列左边缘 x = innerWidth − 161 − 634 = 【innerWidth − 795】
   ── 门槛怎么定出来的（逐个数据 ✓）──────────────────────────────────
     三列：innerWidth − 795 ≥ 余量 ⇒ 要求 innerWidth ≥ 810
       实测支撑：innerW 761 ⇒ 左边缘 −35（左溢出 35px ✗ 已实测 ✓）
                 innerW 830 ⇒ 左边缘 +20（✓ 放得下 ✓ 模型与实测一致 ✓）
       ⇒ 取【840】✗ 不是 810：留 30px 余量（字体回退 / 将来某条原生名变长 ✓）
         ★ 为什么【不】用首页的 1000 ✗：本页 840~999 这一段三列【真的放得下】✓
           用 1000 会把 840~999 白白降到两列 ✗ 而两列在这一段是【撞上限要滚动】的 ✗
           ⇒ 等于让 840~999 的用户多滚一次 ✓ 没必要 ✓
     两列：innerWidth − 161 − 446 ≥ 0 ⇒ 要求 innerWidth ≥ 607
       实测下界 768 ✓（远大于 607 ✓ 有 161px 余量 ✓ 不会溢出 ✓）
       ⇒ 取【768】✓（与首页同值 ✗ 但这里是【实测支持】的 ✓ 不是抄的 ✓）
     一列 + 左对齐：实测 320 / 360 / 375 / 520 / 640 / 767 六档
       左边缘 35 / 75 / 90 / 231 / 351 / 159（全 ≥ 0 ✓）· 无横向溢出 ✓
       ⇒ 取【767】✓（本页页头在 ≤600 会换行 ✗ 实测 ✓ 换行后菜单照样放得下 ✓）
   ── 三档的公共写法 ✗ 为什么这么写 ─────────────────────────────────
     · min-width:0 ✗ 必须：基础规则是 min-width:180px ✗
       而 max-content 列宽在多列下会被它顶宽 ✓
     · button{width:auto;min-width:0} ✗ 基础规则的 width:100% 是【给单列铺满】用的 ✓
       放进格子里 ⇒ 每个格子都撑到整行宽 ✗ 三列立即退化成一列 ✓ ⇒ 必须放开 ✓
     · .lang-name{white-space:nowrap} ✗ max-content 列宽的前提 ✓
       ⇒ 全长名（Português (Brasil) / English (Australia) ✓）不换行不截断 ✓
       ★ 实测 37 条【零截断】✗ scrollWidth > clientWidth 的条目 = 0 ✓
     · max-width:calc(100vw - 32px) 是护栏 ✗ 万一将来某条原生名超长 ⇒ 也不出横向滚动条 ✓
   ★ 一个字都没改字体 / 颜色 / 内边距 / 条目结构 ✗ 只动【布局与定位】✓ */
@media (min-width:840px){
  .lang-menu.open{display:grid;grid-template-columns:repeat(3,max-content);column-gap:10px;row-gap:0;min-width:0;max-width:calc(100vw - 32px);grid-auto-flow:column;grid-template-rows:repeat(13,max-content)}/* ★★★ v9.112 列优先填充 ✗ 与 components.css 的 .lang-menu.open 同一口径 ✓（本页不加载 components.css ✗ 所以必须在这里也写一份 ✓）行数 = ceil(37/3) = 13 ✓ 只加两个声明 ✗ 其余一个字节没动 ✓ */
  .lang-menu button{width:auto;min-width:0}
  .lang-menu .lang-name{white-space:nowrap}
}
@media (min-width:768px) and (max-width:839px){
  .lang-menu.open{display:grid;grid-template-columns:repeat(2,max-content);column-gap:10px;row-gap:0;min-width:0;max-width:calc(100vw - 32px);grid-auto-flow:column;grid-template-rows:repeat(19,max-content)}/* ★★★ v9.112 同上（两列档）✗ 行数 = ceil(37/2) = 19 ✓ */
  .lang-menu button{width:auto;min-width:0}
  .lang-menu .lang-name{white-space:nowrap}
}
@media (max-width:767px){
  .lang-menu.open{display:grid;grid-template-columns:1fr;column-gap:10px;row-gap:0;inset-inline-end:auto;inset-inline-start:0;min-width:min(180px,calc(100vw - 24px));max-width:calc(100vw - 24px);width:max-content}
  .lang-menu button{width:auto;min-width:0}
  .lang-menu .lang-name{white-space:nowrap}
}

/* ── 标题 + 副标题 ✓（★ 下划线用主题色变量 ✗ 带兜底 ✓）── */
.mg-hero{max-width:1120px;margin-inline:auto;padding:20px 16px 6px;text-align:center}
.mg-hero h2{
  font-family:var(--mg-display);font-size:clamp(27px,4.2vw,36px);font-weight:var(--ce-fw-head);
  color:var(--mg-navy);display:inline-block;padding-block-end:8px;
  border-block-end:4px solid var(--lv-accent,var(--mg-primary));
  border-radius:2px;
}
.mg-hero p{margin-block-start:10px;color:var(--mg-muted);font-size:clamp(17.5px,1.9vw,19.5px);font-weight:600}

/* ══════════════════════════════════════════════════════════════════
   ② 第一屏：我现在在哪 ✓（手机上【本月在上·终身在下】✗ 桌面并排 ✓）
   ★ 用 grid + DOM 顺序 ✗ 不用 row-reverse ✓（RTL 自动翻转 ✓）
   ══════════════════════════════════════════════════════════════════ */
.mg-wrap{max-width:1120px;margin-inline:auto;padding:10px 16px 48px}
.mg-cards{
  display:grid;grid-template-columns:1fr;gap:14px;margin-block-start:12px;
}
@media(min-width:760px){ .mg-cards{grid-template-columns:1fr 1fr;gap:18px} }

.mg-card{
  background:var(--mg-card);border:1.5px solid var(--mg-line);border-radius:var(--mg-radius);
  box-shadow:var(--mg-shadow);padding:16px 16px 14px;position:relative;overflow:hidden;
  display:flex;flex-direction:column;gap:10px;
}
.mg-card::before{
  content:'';position:absolute;inset-block-start:0;inset-inline:0;height:4px;
  background:linear-gradient(90deg,var(--mg-primary),var(--mg-gold));
}
.mg-card--life::before{background:linear-gradient(90deg,var(--mg-navy),var(--mg-primary))}
.mg-cardhead{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.mg-dot{width:9px;height:9px;border-radius:50%;background:var(--mg-primary);flex:0 0 auto}
.mg-card--life .mg-dot{background:var(--mg-navy)}
.mg-cardhead b{font-family:var(--mg-display);font-size:19px;font-weight:var(--ce-fw-head);color:var(--mg-navy)}
.mg-cardhead em{font-style:normal;font-size:15.5px;color:var(--mg-muted);font-weight:600}
.mg-tag{
  margin-inline-start:auto;font-size:14.5px;font-weight:var(--ce-fw-head);letter-spacing:.4px;
  color:var(--mg-primary-dark);background:#e6f7f4;border:1px solid #c9ece5;
  border-radius:99px;padding:2px 9px;white-space:nowrap;
}
.mg-card--life .mg-tag{color:var(--mg-navy);background:#eaf1fb;border-color:#d3e2f6}

/* ── 大图 / 中图 ✓ 用真图 ✗ 不是 emoji ✓ ── */
/* ★★ 第 47 轮：两张卡的【图区高度必须一致】✗✗（★ 用户报的"图标/进度条错位"的【前 36px】根因 ✓）
   ── 改前 ✗ ──
     .mg-medal    = clamp(84px,20vw,124px)  ← 本月【大图】✓
     .mg-medal--s = clamp(62px,13vw,88px)   ← 终身【中图】✓
     ⇒ 1440 下实测【左 124 / 右 88】✗ .mg-figure 高度一个 124 一个 88 ✓
     ⇒ 下面所有兄弟节点（.mg-bar / .mg-barmeta / .mg-action）整体差 36px ✓
        （★ 这和"右卡少一句 .mg-sub"是【两个独立的不对称】✗
          只补文案只能补回后 36px ✗ 补不回这前 36px ✓ 两个都要修 ✓）
   ── 改后 ✗ ── 两件事一起做 ✗ 缺一不可 ✓
     ① .mg-figure 给【上下共用的最小高度】✓
     ② align-items 从 center 改成 flex-start ✗✗（★ 这一条才是"标题行对齐"的关键 ✓）
        ── 为什么 ✗ ──
          .mg-lvline 里的等级名【在窄语言下会换行】✗
          实测 de / it：左卡 2 行、右卡 1 行 ⇒ 两个 .mg-lvinfo 高度不同 ✓
          再叠加【垂直居中】⇒ 哪边高哪边的标题就被顶上去 ✗ 实测差 30px ✓
        ── 顶对齐之后 ✗ ──
          两张卡的 .mg-lvline 都从图区顶边开始 ⇒ 与"谁换行 / 换几行"彻底无关 ✓
          且①的下限兜住图区高度 ⇒ 下面的进度条 / 标注框也不会被推走 ✓
          ★ 实测 11 语言 × 2 状态 × 两视口：四面对齐全部 0.0px ✓
     ★ 取值 = .mg-medal 的 clamp 上限 124px ✗（不是手填的魔法数字 ✓
       它就是这张大图【本来就会长到】的高度 ✓ 中文/阿拉伯语/窄屏全部一致 ✓）
     ★★ 第 49 轮把【尺寸 / 下限 / 小徽章的槽】并成同一个 token（--mg-icon ✓ 见下 ✗
        以后改尺寸不会漏改下限 ✓ 也不会漏改"小徽章该让出多少"✓）
     ★★ 为什么不把终身图【放大到 124】✗：
        .mg-medal--s 的"小一号"是【故意的视觉层级】✗ 不是错误 ✓
        放大它 = 改设计 ✗ 而且 160×160 的位图被拉大会糊 ✓
     ★★ 为什么不把本月图【缩到 88】✗：
        124 是两张卡里【最高的那张】✗ 缩它 = 把整块图区压小 ✓
        下一条注释里的实测说明了为什么不需要这么激进 ✓
     ★ 有这张图就撑开、没有就退回 88 ✓（min- 不是 height- ✗ 绝不裁切 ✓）*/
/* ══════════════════════════════════════════════════════════════════════════
   ★★★ 第 49 轮：头像槽 + 徽章 +15%（用户反馈 ①②③④ 四条一起落地 ✓）
   ── ①② 徽章再调大 15% ✗ 一个来源 ✓ ──
     · 旧：.mg-medal / .mg-medal--s / .mg-figure 的 min-height 各写各的 ✗
       ⇒ 改一个忘一个就错位 ✓
     · 新：两个 token（--mg-icon / --mg-icon-s）✗ 三个消费者全从它们派生 ✓
           ① .mg-medal 宽高 ② .mg-medal--s 宽高 ③ .mg-figure 的 min-height
     · 取值 = 旧 clamp × 1.15 ✗（★ 这就是用户这一轮点名的 +15% ✓
       不是"对齐用的魔法数字" ✗ 对齐那部分一个数字都没加 ✓ 见下 ✓）
       旧 84/20vw/124 → 96.6 / 23vw   / 142.6
       旧 62/13vw/88  → 71.3 / 14.95vw/ 101.2
     · 安全边界实测（真 Chrome ✓）：.mg-figure 可用宽 501px ✗
       放大后 142.6 + gap 14 + .mg-lvinfo 下限 120 = 276.6 ≪ 501 ⇒ 不换行、不裁切 ✓
       ★ 卡片有 overflow:hidden ✗ 但图区是【内容撑高】的 ⇒ 只会把卡片撑高 ✓ 不会切图 ✓
   ── ③④ 图标左边缘 / 图标↔文字间隔 ✗ 与左侧一致 ✓ ──
     ★★★ 实测根因【不是 padding、不是 gap】✗✗ 那两项左右【本来就完全一样】✓
       左卡 padding 左 17.00px / 盒间距 14.00px ✓
       右卡 padding 左 17.00px / 盒间距 14.00px ✓  ← 四条全部 0.00px 差 ✓
     ★★★ 真根因 = 两张 webp 【素材自带的透明留白差一倍】✓（canvas 取 alpha 包围盒实测 ✗ 不是推断 ✓）
       · mon-1..6（本月盾牌牌 ✗ 160×160 画布）
           画稿只占 53.1%~63.7% 宽 / 67.5%~84.4% 高 ✗ 左留白 18.13%~23.75% ✓
       · life-1..7（终身小精灵圆币 ✗ 同样 160×160）
           画稿占 84.4%~86.9% 宽 / 86.9%~87.5% 高 ✗ 左留白 6.88%~ 8.13% ✓
       ⇒ 同尺寸的盒子下，盾牌【看得见的那块】天然比圆币【往里缩】✓
         实测：可见左边缘 46.45 vs 23.60 = 差 22.85px ✓
               可见右→文字 42.68 vs 20.05 = 差 22.63px ✓
   ── 结构修法 ✗（★ 一个"对齐数字"都没有 ✓）──
     把小徽章放进【和大徽章一样大的图标槽】里并【居中】=
     四边各让出 (--mg-icon − --mg-icon-s) / 2 ✓
     ⇒ 两颗徽章的【画稿光心】重合（两族画稿都与各自画布同心 ✗ 实测偏 ≤0.8px ✓）
     ⇒ 可见左边缘 / 可见右边缘的残差只剩「两族画稿宽度差 ÷ 2」= 4.7px（Lv.1）✓
        那是【素材本身的性质】✗ 不是 CSS 没做好 ✓
     ⇒ 文字列仍然从同一个 x 开始（槽总宽 = 大徽章宽 ✗ 占位与改前一致 ✓）
     ⇒ .mg-lvinfo 仍然顶对齐（align-items 保持 flex-start ✗ 第 47 轮那条结论不动 ✓）
   ── 为什么【不】给 gap / padding 填数字 ✗ ──
     要真归零得让 W终身 = W本月 × (mon 左留白 ÷ life 左留白) ≈ 3.2 ×
     ⇒ 终身徽章要长成本月的 3 倍大 ✗ 与"大 / 小一号"的设计意图完全相反 ✓
     同理"方形盒 + 纯 CSS"在数学上【不可能】把 ①③④ 同时归零 ✗
     （object-fit:cover 一次只能消掉【一个轴】✗ 两族画稿宽占比差 30 个百分点 ✓）
   ── 要连这 4.7px 都消掉 ✗ 唯一的路是【裁素材】✓ ──
     把 13 张 webp 的透明留白裁到画稿包围盒 ✓ 裁完 contain 会让纵轴完全贴边 ✓
     ★ 但那要动 public/brand/badges/* ✗✗ 是【共享素材】✗
       Credits 卡（components.css 的 #ceLvMonthIcon）+ 徽章墙都在用 ✓
       ⇒ 本轮【不动】✓ 已单独提给用户 ✓
   ══════════════════════════════════════════════════════════════════════════ */
.mg-figure{
  /* ★★★ 第 50 轮：用户"成长页面的这个图标再放大10%"✗ 两个 token 同步 ×1.10 ✓
     ── 为什么【两个都放】✗✗ ──
       · .mg-medal--s 的居中 margin = (--mg-icon − --mg-icon-s)/2 ⇒ 两个 token 耦合 ✓
       · .mg-figure 的 min-height = --mg-icon ⇒ 只放小的会让两卡错位 ✓
         （那正是第 47 轮修过的 bug 类型 ✗ 第 49 轮的"大/小一号"层级也要保住 ✓）
     ── 老值 ✗ = 第 49 轮的 1.15 值 × 1.10 ✓ ──
       96.6  / 23vw    / 142.6  → 106.26 / 25.3vw    / 156.86
       71.3  / 14.95vw / 101.2  → 78.43  / 16.445vw  / 111.32
       ★ 1440 下实测：终身圆徽章 101.188 → 111.32（= 1.1000 × ✓）
       ★ 本月徽章 142.59 → 156.86（同样 1.10 × ✓ 层级不变 ✓）*/
  --mg-icon:clamp(106.26px,25.3vw,156.86px);   /* 旧 clamp(84px,20vw,124px) × 1.15 × 1.10 ✓ */
  --mg-icon-s:clamp(78.43px,16.445vw,111.32px);/* 旧 clamp(62px,13vw,88px)  × 1.15 × 1.10 ✓ */
  display:flex;align-items:flex-start;justify-content:center;gap:14px;flex-wrap:wrap;
  min-height:var(--mg-icon);
}
.mg-medal{
  width:var(--mg-icon);height:var(--mg-icon);
  display:block;object-fit:contain;flex:0 0 auto;
  filter:drop-shadow(0 8px 16px rgba(18,58,114,.18));
}
/* ★★ 小徽章 ✗ 尺寸走 token + 【四边让出 (大 − 小)/2】= 居中在大徽章那么大的槽里 ✓ */
.mg-medal--s{
  width:var(--mg-icon-s);height:var(--mg-icon-s);
  margin:calc((var(--mg-icon) - var(--mg-icon-s)) / 2);
}
.mg-lvinfo{min-width:0;flex:1 1 120px;text-align:start}
.mg-lvline{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
/* ★ 对比度：白字压在 --mg-primary-dark 上 ⇒ 随该 token 改为 #0e8570 = 4.56:1 ✓
   （原来是 #0f8f74 = 4.04:1 ✗ 白字只剩 4.04 ✓ 差 0.46 ✗）
   ★ 只改 token ✗ 这里一个字不动 ✓（--mg-navy 那条 .mg-card--life 分支本来就有 10:1 ✓）*/
.mg-lvno{
  font-family:var(--mg-display);font-size:16.5px;font-weight:var(--ce-fw-head);color:#fff;
  background:var(--mg-primary-dark);border-radius:8px;padding:1px 8px;
}
.mg-card--life .mg-lvno{background:var(--mg-navy)}
.mg-lvname{font-family:var(--mg-display);font-size:clamp(21px,3vw,25px);font-weight:var(--ce-fw-head);color:var(--mg-navy)}
/* ★★ 对比度：11.5px 文字压在浅青底 #e6f7f4 上 ✗
   原来用 --mg-primary-dark（#0f8f74）= 3.63:1 ✗✓；改成 #0b755f = 5.07:1 ✓
   ★ 只改颜色 ✗ 字号 / 内边距 / 圆角一律不动 ✓ */
.mg-perk{
  display:inline-block;margin-block-start:6px;font-size:15.5px;font-weight:var(--ce-fw-head);
  color:#0b755f;background:#e6f7f4;border:1px solid #c9ece5;
  border-radius:99px;padding:2px 10px;
}
.mg-card--life .mg-perk{color:var(--mg-navy);background:#eaf1fb;border-color:#d3e2f6}
.mg-sub{font-size:16px;color:var(--mg-muted);margin-block-start:6px;font-weight:600}
/* ★★ 第 47 轮：两张卡的那句话【必须占同样的高度】✗✗（★ 用户报的"左右标题错位"的根因 ✓）
   ── 实测（1440 · 真浏览器 · 11 语言逐个量 ✓）──
     本月卡 "Nothing solved this month yet — one problem and your progress starts"
       en / ko / es ⇒ 2 行（advance 宽 428 / 377 / 415 vs 可用 363px）✗
       zh-CN / zh-TW / ja / ar / fa ⇒ 1 行 ✓
     终身卡（本轮新加的那句）⇒ 也会 1 行或 2 行 ✓
   ⇒ 两句话行数不同 ⇒ .mg-lvinfo 高度不同 ⇒ 它又是【垂直居中】的 ✗
     ⇒ 标题行被挤下 / 挤上 9.6px ✓（.mg-bar / .mg-action 不受影响 ✗ 它们在图区【下方】✓）
   ── 改法 ✗ 给这一行一个【下限】= 2 行 ✗✗ ──
     ★ 只用结构性关键字：min-block-size + lh（= line-height 单位 ✓）
       1lh = 这一行自己的行高 ✗ 3lh = 3 行 ⇒ 内边距 6px + 2 行文字 = 6 + 2lh ✓
     ★★ 为什么不是魔法数字 ✗：它随字号 / 行高自动缩放 ✓ 换语言 / 换视口都不会失准 ✓
     ★★★ 为什么取【2 行】而不是 1 行 ✗：
       取 1 行 ⇒ 本月卡在 en/ko/es 是 2 行 ⇒ 又把两张卡撑成不一样高 ✓
       取 2 行 ⇒ 本月卡真实需要的最多就是 2 行（11 语言实测 ✓）
                 终身卡若某语言只 1 行 ⇒ 那多出来的 1 行是【图区内部的空白】✓
                 （★ 不会把下面的进度条推下去 ✗ .mg-figure 有 124px 下限兜着 ✓）
                 ★ 宁可留一点空 ✗ 也不能让"完成度/进度条"错位 ✓（用户点名的就是对齐 ✓）
     ★ 只锁 .mg-card 里的这一条 ✗ 不碰别处（徽章区那几处 .mg-sub 旁边没有兄弟节点 ✓）*/
.mg-card .mg-sub{min-block-size:3lh}
.mg-subs{margin-block:0 10px}
.mg-smallnote{margin-block-start:12px;font-size:15.8px;color:var(--mg-muted);font-weight:600}
/* ★ 徽章真图缺失时的 emoji 兜底 ✓（绝不留裂图 ✗）*/
.mg-bemoji{font-size:42px;line-height:1.15;display:block}

/* ── 进度条 ✓ ── */
.mg-bar{
  height:11px;border-radius:99px;background:#e8eef4;overflow:hidden;
  border:1px solid #dde6ee;
}
.mg-bar i{
  display:block;height:100%;border-radius:99px;
  background:linear-gradient(90deg,var(--mg-primary),var(--lv-accent,var(--mg-primary-dark)));
  transition:width .6s ease;
}
.mg-card--life .mg-bar i{background:linear-gradient(90deg,var(--mg-navy),var(--mg-primary))}
.mg-barmeta{display:flex;justify-content:space-between;gap:10px;font-size:15.5px;color:var(--mg-muted);font-weight:700;flex-wrap:wrap}
.mg-barmeta b{color:var(--mg-navy)}

/* ── ★★ 具体行动 ✗ 不是干巴巴的数字 ✓ ── */
.mg-action{
  border-radius:16px;padding:10px 13px;font-size:17.5px;font-weight:var(--ce-fw-head);line-height:1.5;
  background:linear-gradient(135deg,#eafaf7,#f6fffd);
  border:1.5px dashed #9fdfd3;color:#0c6d5b;
}
.mg-card--life .mg-action{background:linear-gradient(135deg,#eef4fd,#f8fbff);border-color:#b9cdea;color:var(--mg-navy)}
.mg-action b{color:var(--mg-gold-dark);font-weight:var(--ce-fw-head)}
.mg-action--top{background:linear-gradient(135deg,#fff8e6,#fffdf7);border-color:#f0d79a;color:#8a6100}
.mg-action--top b{color:#b8860b}

/* ══════════════════════════════════════════════════════════════════
   ③ 完整阶梯 ✓（默认【收起】✗ <details> ✓）
   ══════════════════════════════════════════════════════════════════ */
.mg-sec{
  background:var(--mg-card);border:1.5px solid var(--mg-line);border-radius:var(--mg-radius);
  box-shadow:var(--mg-shadow);margin-block-start:18px;overflow:hidden;
}
.mg-sech{
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  padding:14px 16px;border-block-end:1.5px solid var(--mg-line);background:var(--mg-soft);
}
.mg-sech h3{font-family:var(--mg-display);font-size:20px;font-weight:var(--ce-fw-head);color:var(--mg-navy)}
.mg-sech em{margin-inline-start:auto;font-style:normal;font-size:16px;font-weight:var(--ce-fw-head);color:var(--mg-muted)}
.mg-secb{padding:14px 16px 18px}

/* ── <details> 折叠 ✓ ── */
.mg-fold{border:0;background:transparent}
.mg-fold>summary{
  list-style:none;cursor:pointer;padding:15px 16px;display:flex;align-items:center;gap:10px;
  flex-wrap:wrap;background:var(--mg-soft);font-size:17.5px;font-weight:var(--ce-fw-head);color:var(--mg-navy);
}
.mg-fold>summary::-webkit-details-marker{display:none}
.mg-fold>summary::marker{content:''}
.mg-fold>summary:hover{background:#e9f2f9}
.mg-fold>summary:focus-visible{outline:3px solid var(--lv-accent,var(--mg-primary));outline-offset:-3px}
.mg-fold[open]>summary{border-block-end:1.5px solid var(--mg-line)}
.mg-caret{
  flex:0 0 auto;width:0;height:0;border-block:5px solid transparent;
  border-inline-start:7px solid var(--mg-primary-dark);transition:transform .25s ease;
}
.mg-fold[open] .mg-caret{transform:rotate(90deg)}
.mg-foldhint{
  margin-inline-start:auto;font-size:15.5px;font-weight:var(--ce-fw-head);color:var(--mg-primary-dark);
  background:#e6f7f4;border:1px solid #c9ece5;border-radius:99px;padding:2px 10px;white-space:nowrap;
}
.mg-foldimg{
  width:30px;height:30px;object-fit:contain;flex:0 0 auto;
  filter:drop-shadow(0 3px 6px rgba(18,58,114,.16));
}
.mg-foldbody{padding:14px 16px 18px}

/* ── 一行 7 枚 ✓ ── */
.mg-ladderblk{margin-block-start:4px}
.mg-ladderblk+.mg-ladderblk{margin-block-start:18px}
.mg-ladderhd{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-block-end:10px}
.mg-ladderhd b{font-family:var(--mg-display);font-size:18px;font-weight:var(--ce-fw-head);color:var(--mg-navy)}
.mg-ladderhd em{font-style:normal;font-size:15.5px;color:var(--mg-muted);font-weight:700}
.mg-row{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;align-items:flex-start}

/* ── ★ 四态 ✗✗（用户点赞过的设计 ✓ 一个都不许省 ✓）──
   已通过 = 彩色 + 右上角绿勾 ✓
   当前   = 金色描边 + 放大 + 「当前」标签 ✓
   下一级 = 虚线框 + 「下一级」标签 ✓
   未解锁 = 灰度 + 降低透明度 ✓                                          */
.mg-cell{
  flex:1 1 76px;max-width:132px;min-width:0;
  display:flex;flex-direction:column;align-items:center;gap:5px;
  padding:9px 5px 8px;border-radius:16px;border:2px solid transparent;
  background:var(--mg-soft);position:relative;transition:transform .2s ease,box-shadow .2s ease;
}
.mg-cell img{width:100%;max-width:75.9px;height:auto;display:block}
.mg-cname{
  font-size:14.8px;font-weight:var(--ce-fw-head);color:var(--mg-navy);text-align:center;line-height:1.28;
  overflow-wrap:anywhere;
}
.mg-cno{font-size:13.5px;font-weight:var(--ce-fw-head);color:var(--mg-muted);letter-spacing:.3px}

/* 已通过 ✓ */
.mg-cell--done{background:#effaf7;border-color:#cfeae3}
.mg-cell--done .mg-lvcheck{
  position:absolute;inset-block-start:-6px;inset-inline-end:-6px;
  width:21px;height:21px;border-radius:50%;background:#22c55e;color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:var(--ce-fw-head);
  box-shadow:0 2px 6px rgba(34,197,94,.45);border:2px solid #fff;
}
/* 当前 ✓ 金色描边 + 放大 ✓ */
.mg-cell--now{
  background:#fffdf3;border-color:var(--mg-gold);border-style:solid;
  box-shadow:0 0 0 4px rgba(232,179,60,.2),0 8px 20px rgba(232,179,60,.22);
  transform:scale(1.07);z-index:2;
}
.mg-cell--now img{max-width:89.7px}
.mg-cell--now .mg-cname{color:#8a6100;font-size:15.6px}
/* 下一级 ✓ 虚线框 ✓ */
.mg-cell--next{background:#fff;border-color:#9fdfd3;border-style:dashed}
/* 未解锁 ✓ 灰度 + 低透明度 ✓ */
.mg-cell--lock{background:#f6f8fa;border-color:#e6ecf2}
.mg-cell--lock img{filter:grayscale(1);opacity:.42}
.mg-cell--lock .mg-cname,.mg-cell--lock .mg-cno{opacity:.5}

.mg-lvtag{
  font-size:13.5px;font-weight:900/* ★★ 第 2 步例外 ⑧：白字压在 --mg-gold 上只有 1.92:1 ✗ 9.5px 极小字替对比度打工 ⇒ 保留 900 ✓ */;border-radius:99px;padding:1px 7px;white-space:nowrap;
  background:var(--mg-gold);color:#fff;box-shadow:0 2px 5px rgba(232,179,60,.4);
}
.mg-lvtag--next{background:#fff;color:var(--mg-primary-dark);border:1.5px dashed #73cdbc;box-shadow:none}

/* ── 图例 ✓（4 个小圆点 + 文字 ✓）── */
.mg-legend{
  display:flex;flex-wrap:wrap;gap:8px 18px;margin-block-start:16px;padding-block-start:13px;
  border-block-start:1.5px dashed var(--mg-line);font-size:15.8px;font-weight:700;color:var(--mg-muted);
}
.mg-legend span{display:inline-flex;align-items:center;gap:6px}
.mg-legend i{width:12px;height:12px;border-radius:50%;flex:0 0 auto;display:inline-block}
.mg-legend i.now{background:#fffdf3;border:2.5px solid var(--mg-gold)}
.mg-legend i.next{background:#fff;border:2.5px dashed #73cdbc}
.mg-legend i.done{background:#effaf7;border:2.5px solid #22c55e}
.mg-legend i.lock{background:#f6f8fa;border:2.5px solid #cbd5e1;opacity:.7}

/* ══════════════════════════════════════════════════════════════════
   ★ 第 50 轮：阶梯徽章 +15% ✗ 第 51 轮：两排【列对齐】（用户反馈 ✓）
   ── ① 徽章 +15%（数值改在上面 .mg-cell img / .mg-cell--now img ✓
      以及 ≤480 那两处 ✓ 一行都没多 ✓）──
      · .mg-cell img       66px → 75.9px（= 66 × 1.15 ✓）
      · .mg-cell--now img  78px → 89.7px（= 78 × 1.15 ✓）
      · ≤480               52 → 59.8 / 60 → 69（同 ×1.15 ✓）
      · ≤480 的 .mg-cell padding 3px → 2px：格内容盒 67 → 69px ✓
        ⇒ 「当前」格也吃满 15%（62.4 → 71.76 ✓ 实测正好 +15.00% ✓）
        ★ 不改它 ✗ 小屏那格内容盒只有 67px < 目标 69px ⇒ 只吃到 +11.66% ✓
      · 实测：桌面 1400 ⇒ 75.89 / 95.97 ✓ 移动 390 ⇒ 59.80 / 71.76 ✓
        换行方式【一处都没变】✓（10 个宽度逐行格数全等 ✓ 11 语言全 1 行 ✓）
   ── ② 列对齐 ✗ 从上往下【第 N 个 对 第 N 个】（★ 第 51 轮 ✗ 用户拍板 ✓）──
      .mg-row 基础是 justify-content:center ✗ 两排各自居中 ⇒
        7 格排宽 972 / 6 格排宽 832 ⇒ 左边缘天然差 (972−832)/2 = 70px ✗
        而且 6 格排的第 k 格会落在 7 格排第 k+1 格的【正上方】✗ 不是第 k 个 ✓
      第 50 轮曾把它翻成 flex-end（右边缘对齐）✗ 用户否掉了 ✓
        实测（第 51 轮 ✗ 真浏览器 ✓）：1400 第一排首格 x=354 · 第二排 x=214 ⇒
        C1~C6 的 Δx 全是【140.00px】= 132+8 =【整整一个列距】✗
        即 Little Elf(354) 正好压在 Explorer(354) 上 ✗ 正是用户图 1 的症状 ✓
      第 51 轮改成 flex-start ✗ 两排都从【同一个 max-content 列的左边缘】起排 ⇒
        实测 1400 / 1100 / 1040 第 1~6 列 Δx =【0.00px】（★ 目标 ≤2px ✓）
        ⇒ 第一排 6 格 = 832 宽 ✗ 第二排 7 格 = 972 宽 ⇒ 右边缘差 140px ✗
          【这正是用户要的】✗ 第 7 格 Legend 单独在右边 ✗ 下面没有对应的 ✓
      ★ 为什么不干脆删掉本段、只把基础规则的 center 改成 flex-start（★ 实测反例 ✓）：
        闸门以下两排格宽【本来就不相同】（实测 768 ⇒ 110/93 · 900 ⇒ 132/112 ·
        1000 ⇒ 132/127）⇒ 只改方向【对不齐】：Δx = 84.53 / 98.56 / 27.16px ✗
        ⇒【闸门内那句 flex:0 0 132px 才是列对齐的前提】✗ 它不能动 ✓
      ★ 整块【仍然居中】✗ 第二排（列宽 972 那排）位置与第 50 轮逐像素相同 ✓
        只有第一排左移 140px 去对齐 ✓
        两个小标题左边缘仍贴徽章列左边缘（第 50 轮那 +41px 保留 ✓）
        ★ 不改成贴面板左边 ✗ 实测整块会再左移 41px ⇒「当前」格（scale 1.07）
          探进 16px 内边距 4.62px ✗ 不裁切但看着挤 ✗ 用户否掉 ✓
   ── ③ 为什么带闸门（★ 这是【正确性】闸门 ✗ 不是对齐补丁 ✓）──
      972 = 7 格 × 132 + 6 缝 × 8（★ 两个都是【现有值】✗ 没有新增任何数字 ✓）
      面板内容盒 = 视口 − 66（实测 1024 ⇒ 958 ✓）⇒ 放得下 972 要视口 ≥ 1038 ⇒ 取 1040 ✓
      ★★ 不加闸门会怎样（实测 ✓ 不是推断 ✓）：
        max-content 轨道【不会缩】✗ 加刚性 132px 格 ⇒ 行盒被顶死 972px ✗
        481~1020 视口下内容盒只有 415~968 ⇒ 徽章越出面板最多 540px ✗
          （560 ⇒ 越出 461px · 768 ⇒ 253px · 900 ⇒ 121px · 1000 ⇒ 21px ✓）
        而 .mg-sec 有 overflow:hidden ⇒【没有横向滚动条 ✗ 静默裁掉末尾徽章】✗✗
      ★★ 第 51 轮又量了一遍（★ 用 7 列刚性栅格复现 ✗ 同一结论更狠 ✓）：
        320 ⇒ 越出内容盒 710px / 越出裁切边界【694px】· 390 ⇒ 640/624 ·
        768 ⇒ 270/254 · 1000 ⇒ 38/22 · 1039 ⇒ 0 ✓（15 个宽度逐个量 ✓）
        ⇒ 闸门【必须留】✗ 上面那些 px 就是被静默吃掉的那几枚徽章 ✓
      ⇒ 闸门以下【一条规则都不生效】⇒ 实测与改前逐项相同 ✓
        （390 / 481 / 768 / 1024 / 1039 五个宽度的换行·格宽·两排位置全等 ✓
          第 51 轮复测 15 个宽度：越出裁切边界【全部 0.00px】✓）
   ── ④ RTL ✓ 方向跟着【阅读方向】走（flex-start = 行内起点 ✓）
      实测 ar / fa 下两排对齐的是物理【右边】✓ 这是对的 ✗ 不加 [dir=rtl] 特例 ✓
      （第 50 轮的 flex-end 对齐的是物理【左边】✗ 跑得通 ✗ 但跟阅读方向反 ✓ 已换掉 ✓）
   ══════════════════════════════════════════════════════════════════ */
@media(min-width:1040px){
  #mgLadderSec .mg-foldbody{display:grid;grid-template-columns:1fr max-content 1fr}
  #mgLadderSec .mg-ladderblk{grid-column:2}
  #mgLadderSec .mg-legend{grid-column:1/-1}
  #mgLadderSec .mg-row{justify-content:flex-start;gap:8px}
  #mgLadderSec .mg-cell{flex:0 0 132px;max-width:none}
}

/* ══════════════════════════════════════════════════════════════════
   ④ 徽章墙 ✓（只渲染【上墙的 6 枚】✗ 其余不出现 ✓）
   ══════════════════════════════════════════════════════════════════ */
.mg-tier+.mg-tier{margin-block-start:20px}
.mg-tierhd{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;margin-block-end:4px}
.mg-tierhd b{font-family:var(--mg-display);font-size:18.5px;font-weight:var(--ce-fw-head);color:var(--mg-navy)}
.mg-tierhd em{font-style:normal;font-size:15.8px;color:var(--mg-muted);font-weight:700}
.mg-tierhd span{margin-inline-start:auto;font-size:15.5px;font-weight:var(--ce-fw-head);color:var(--mg-primary-dark)}
.mg-badges{display:grid;grid-template-columns:repeat(auto-fill,minmax(146px,1fr));gap:11px;margin-block-start:9px}
.mg-badge{
  border:2px solid var(--mg-line);border-radius:18px;padding:9px 10px 10px;
  background:var(--mg-soft);text-align:center;position:relative;
  display:flex;flex-direction:column;align-items:center;gap:2px;
  transition:transform .2s ease,box-shadow .2s ease;
}
/* ★★ 第 57 轮（产品主人拍板「放大」+「辣一点来增加饱满感」✓）：
   新 v3 素材自带透明留白 ⇒ 同一个 66px 框里【看起来小了】✓
   ── 实测（真浏览器截图像素 · 不透明边界框 + 面积折算 ✗ 不是 CSS 声明值 ✓）──
     · 160px 原图上量：旧不透明 89.10 % 画框  vs  新透明 80.92 % 画框（各 6 枚均值）
       ⇒ 新/旧 = 0.9082 ⇒ 小 9.18 % ⇒ 补偿系数 1.1011 ⇒ 66 × 1.1011 = 72.67px
     · 同一屏并排、量真实像素：旧@66 实心直径 60.03px  vs  新@66 56.00px（−6.71 %）
       新@74 = 62.86px（比旧@66 大 4.71 %）· 墨量多 9.65 % ⇒ 这就是"饱满感"✓
   ── 结论：74px（= 比"一样大"再大一点点 ✓）· 小屏 63px（同比例 −1px ✓）──
     ✗ 不裁图片留白（那是设计者的构图 ✓）✗ 不改饱和度 ✗ 只动 CSS 尺寸与间距 ✓
   ── 高度为什么没涨 ✗（同一浏览器同一页 ✗ 新旧两套规则轮流贴上去做 A/B ✓）──
     · 1440 · 12 枚已得     ：secH 444.92px【一个像素都没动】· 下一节 top 位移 0.00
     · 1440 · 6 已得 6 未得 ：secH 444.92 → 442.92（【变矮 2px】不是撑高 ✓）
     · 390  · 12 枚已得     ：secH 975.36 → 969.36（变矮 6px ✓）
     · 真原因：行高由该行【最高的那张卡】决定 ✗ 而最高的那张一直是未获得那张
       （条件原文三行 ✓）⇒ 已获得卡长高的 8px 被它吸收 ✓ ⇒ 不顶动下方元素 ✓
   ── 装得下吗 ✗ 实测：列宽 166.5px − padding(10+10) − border(2×2) = 可用 142.5px
     图框 74px ⇒ 占 51.9 % ✓；连金边那档（border 3px ✗ 可用 140.5px）也只占 52.7 % ✓
     窄屏：列宽 161.5 − 20 − 4 = 137.5px，63px 占 45.8 % ✓ ⇒ 绰绰有余 ✓
     真浏览器逐枚核对"图框是否越出卡片内容盒"：0/12 越界（6 种组合全 0 ✓）
   ── 全部原始数字：%TEMP%\celf-badgefill\ab.json 与 REPORT.md ── */
.mg-badge img{width:74px;height:74px;object-fit:contain;display:block}
.mg-badge b{font-size:16.3px;font-weight:var(--ce-fw-head);color:var(--mg-navy);line-height:1.3}
.mg-badge small{font-size:14.8px;color:var(--mg-muted);font-weight:700;line-height:1.42}
/* 已获得 = 彩色 + 金边 + 右上角勾 ✓ */
.mg-badge--got{background:#fffdf4;border-width:3px;border-color:var(--mg-gold);box-shadow:0 6px 18px rgba(232,179,60,.20)}
.mg-badge--got .mg-bcheck{
  position:absolute;inset-block-start:-8px;inset-inline-end:-8px;
  width:24px;height:24px;border-radius:50%;background:#22c55e;color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:17px;font-weight:var(--ce-fw-head);
  box-shadow:0 2px 7px rgba(34,197,94,.45);border:2px solid #fff;
}
/* 未获得 = 灰度 + 低透明度 ✓ */
.mg-badge--lock img{filter:grayscale(1);opacity:.4}
.mg-badge--lock b{color:#94a3b8}
.mg-badge--lock small{opacity:.72}

/* ══════════════════════════════════════════════════════════════════
   ★★ 第 38 轮：徽章墙【一枚都没点亮】时的引导 ✗✗（用户点名要 ✓）
   ★ 为什么加在本文件 ✗：那份同构实现原来在 ce-illu.css 的 .gc-badge-empty ✓
     但那个弹窗已退休 ✗（GrowthCards.open('growth') 现在只跳 /my-growth.html ✓）
     ⇒ 用户真正看到的是【本页】✗ 而本页【不引 ce-illu.css】✗
     ⇒ 所以把那条规则【原样搬过来】✓ 一个数值都不改 ✓（88 / 76 / 13.5 / 1.7 ✓）
   ★ 位置 ✗：徽章墙【上方】多一行 ✓ 那 6 张卡照常显示 ✗✗（它们是灰的不是空的 ✓）
   ★ 只在 earnedCount === 0 时渲染 ✓（见 my-growth.html 的 renderBadges ✓）
     已点亮 ≥1 枚 ⇒ 这一行【根本不存在】✓ 不是 display:none ✓（DOM 里查得到 / 查不到可断言 ✓）
   ★ RTL ✗：flex + 逻辑属性 ✓ 不用 row-reverse ✗
   ══════════════════════════════════════════════════════════════════ */
.mg-badge-empty{
  display:flex;align-items:center;gap:12px;
  margin:0 0 12px;
  padding:12px 14px;
  background:#fffdf5;
  border:1px dashed #e8d9a8;
  border-radius:14px;
}
.mg-badge-empty-img{
  width:88px;height:88px;flex:0 0 auto;
  object-fit:contain;
  border-radius:12px;background:#fff;
}
.mg-badge-empty-tx{min-width:0;color:#7a6320;font-size:17.5px;line-height:1.7}
@media(max-width:560px){
  .mg-badge-empty{gap:9px;padding:10px 11px}
  .mg-badge-empty-img{width:76px;height:76px}
  .mg-badge-empty-tx{font-size:16.5px}
}

/* ══════════════════════════════════════════════════════════════════
   ⑤ 我拿到了什么（权益）✓  ⑥ 怎么算的 ✓
   ══════════════════════════════════════════════════════════════════ */
.mg-perks{display:grid;grid-template-columns:1fr;gap:11px}
@media(min-width:700px){ .mg-perks{grid-template-columns:1fr 1fr} }
.mg-perkcard{
  border:1.5px solid var(--mg-line);border-radius:18px;padding:13px 14px;background:var(--mg-soft);
  display:flex;flex-direction:column;gap:7px;
}
.mg-perkcard h4{font-family:var(--mg-display);font-size:17.6px;font-weight:var(--ce-fw-head);color:var(--mg-navy)}
.mg-perkcard p{font-size:16.6px;color:#41546b;font-weight:600;line-height:1.55}
.mg-live{
  align-self:flex-start;font-size:14.8px;font-weight:var(--ce-fw-head);border-radius:99px;padding:2px 10px;
  background:#e6f7f4;color:var(--mg-primary-dark);border:1px solid #c9ece5;
}
.mg-live--look{background:#eef4fd;color:var(--mg-navy);border-color:#cfdff5}
.mg-chips{display:flex;flex-wrap:wrap;gap:6px;margin-block-start:2px}
.mg-chip{
  font-size:15px;font-weight:var(--ce-fw-head);border-radius:99px;padding:2px 9px;
  background:#fff;border:1.5px solid var(--mg-line);color:#41546b;
}
.mg-chip--on{border-color:var(--mg-gold);background:#fffdf4;color:#8a6100;box-shadow:0 2px 6px rgba(232,179,60,.2)}

.mg-rules{margin-inline-start:18px;display:flex;flex-direction:column;gap:8px;font-size:17px;color:#41546b;font-weight:600}
.mg-rules li{padding-inline-start:2px}
.mg-free{
  margin-block-start:14px;border:1.5px dashed #f0d79a;border-radius:16px;
  background:#fff8ec;padding:12px 14px;
}
.mg-free b{display:block;color:#b45309;font-size:17.2px;font-weight:var(--ce-fw-head);margin-block-end:3px}
.mg-free span{font-size:16.6px;color:#6b5322;font-weight:600;line-height:1.55}

/* ══════════════════════════════════════════════════════════════════
   ⑦ 页脚 ✓
   ══════════════════════════════════════════════════════════════════ */
.mg-foot{
  max-width:1120px;margin-inline:auto;padding:6px 16px 46px;text-align:center;
}
.mg-foot .mg-slogan{font-family:var(--mg-display);font-size:clamp(19px,2.6vw,23px);font-weight:var(--ce-fw-head);color:var(--mg-navy)}
.mg-foot .mg-slogansub{font-size:16.6px;color:var(--mg-muted);font-weight:600;margin-block-start:4px}
.mg-foot .mg-back{
  display:inline-block;margin-block-start:16px;text-decoration:none;
  background:linear-gradient(180deg,var(--mg-primary),var(--mg-primary-dark));color:#fff;
  border-radius:99px;padding:11px 24px;font-size:17.5px;font-weight:var(--ce-fw-head);
  box-shadow:0 5px 0 #0b6d59;transition:transform .15s ease,box-shadow .15s ease;
}
.mg-foot .mg-back:hover{transform:translateY(-1px);box-shadow:0 6px 0 #0b6d59}
.mg-foot .mg-back:active{transform:translateY(3px);box-shadow:0 2px 0 #0b6d59}

/* ══════════════════════════════════════════════════════════════════
   状态块：加载中 / 未登录 / 出错 ✓（★ 绝不白屏 ✗）
   ══════════════════════════════════════════════════════════════════ */
.mg-state{
  background:var(--mg-card);border:1.5px solid var(--mg-line);border-radius:var(--mg-radius);
  box-shadow:var(--mg-shadow);padding:22px 18px;text-align:center;
}
.mg-state h3{font-family:var(--mg-display);font-size:21px;font-weight:var(--ce-fw-head);color:var(--mg-navy);margin-block-end:6px}
.mg-state p{font-size:17px;color:var(--mg-muted);font-weight:600;max-width:620px;margin-inline:auto}
.mg-state .mg-cta{
  display:inline-block;margin-block-start:16px;text-decoration:none;
  background:linear-gradient(180deg,var(--mg-primary),var(--mg-primary-dark));color:#fff;
  border-radius:99px;padding:12px 26px;font-size:18px;font-weight:var(--ce-fw-head);
  box-shadow:0 5px 0 #0b6d59;
}
.mg-state .mg-cta:hover{filter:brightness(1.05)}
.mg-retry{
  margin-block-start:16px;background:#fff;border:2px solid var(--mg-primary-dark);
  color:var(--mg-primary-dark);border-radius:99px;padding:10px 24px;font-size:17.5px;font-weight:var(--ce-fw-head);
}
.mg-retry:hover{background:#e6f7f4}
.mg-errmsg{
  margin-block-start:10px;font-size:15.8px;color:#b91c1c;font-weight:700;
  background:#fef2f2;border:1px solid #fecaca;border-radius:12px;padding:8px 11px;
  display:inline-block;overflow-wrap:anywhere;
}
/* 骨架 ✓ */
.mg-skelcard{background:var(--mg-card);border:1.5px solid var(--mg-line);border-radius:var(--mg-radius);
  box-shadow:var(--mg-shadow);padding:18px;display:flex;flex-direction:column;gap:12px}
.mg-skel{
  border-radius:12px;background:linear-gradient(100deg,#eef4f9 30%,#e2ecf4 50%,#eef4f9 70%);
  background-size:220% 100%;animation:mgShimmer 1.4s linear infinite;
}
.mg-skel--medal{width:110px;height:110px;border-radius:50%;align-self:center}
.mg-skel--line{height:13px}
.mg-skel--bar{height:11px;border-radius:99px}
.mg-skel--sm{width:56%}
.mg-loadingtext{text-align:center;font-size:17px;font-weight:var(--ce-fw-head);color:var(--mg-muted);padding:10px 0}
@keyframes mgShimmer{from{background-position:120% 0}to{background-position:-120% 0}}
.mg-fadein{animation:mgFade .45s ease both}
@keyframes mgFade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

.mg-hidden{display:none!important}

/* ══════════════════════════════════════════════════════════════════
   ★ 无障碍：动画一律【尊重】reduce ✓（本页不做豁免 ✗）
   ══════════════════════════════════════════════════════════════════ */
@media(prefers-reduced-motion:reduce){
  .mg-skel{animation:none;background:#eef4f9}
  .mg-fadein{animation:none}
  .mg-caret{transition:none}
  .mg-bar i{transition:none}
  .mg-cell{transition:none}
  .mg-badge{transition:none}
  .mg-sel,.mg-topbtn{transition:none}
  .mg-foot .mg-back{transition:none}
  .mg-foot .mg-back:hover{transform:none}
}

/* 小屏微调 ✓ */
@media(max-width:480px){
  .mg-topin{padding:9px 12px;gap:9px}
  .mg-logo{width:38px;height:38px}
  .mg-brand h1{font-size:22.5px}
  .mg-wrap{padding-inline:12px}
  .mg-cell{flex:1 1 64px;padding:7px 2px 6px;border-radius:13px}
  .mg-cell--now{transform:scale(1.04)}
  .mg-cell img{max-width:59.8px}
  .mg-cell--now img{max-width:69px}
  .mg-cell--done .mg-lvcheck{width:18px;height:18px;font-size:15px}
  .mg-badges{grid-template-columns:repeat(auto-fill,minmax(128px,1fr));gap:9px}
  .mg-badge img{width:63px;height:63px}
}

/* 矮屏（笔记本横屏）✓ —— 第一屏仍要一屏看全 ✓ */
@media(min-width:760px) and (max-height:660px){
  .mg-hero{padding-block-start:12px}
  /* ★★ 第 49 轮：矮屏【只换 token 的取值】✗ 不再各写一条 width/height ✓
     原来两条各写各的 ✗ 而 .mg-medal--s 的居中 margin 是由 (大 − 小) 算出来的 ✓
     ⇒ 只改宽度不改 margin 一定错位 ✓ 改 token 则三处一起跟上 ✓
     取值 = 旧 clamp × 1.15 × 1.10（★ 第 50 轮再 ×1.10 ✗ 与主规则同步 ✓）：
       旧 clamp(70px,14vw, 96px) → 88.55px  / 17.71vw  / 121.44px
       旧 clamp(58px,11vw, 76px) → 73.37px  / 13.915vw /  96.14px */
  .mg-figure{--mg-icon:clamp(88.55px,17.71vw,121.44px);--mg-icon-s:clamp(73.37px,13.915vw,96.14px)}
  .mg-card{padding:13px 14px 12px;gap:8px}
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★★ 第 49 轮：⑤ 终身卡那句鼓励语（用户点名的"蓝框"位置 ✓）
   ── 落点为什么【不是】"同一行右边那块空白"✗✗ ──
     ★ 真浏览器实测（11 语言逐个量 ✗ 不是估算 ✓）：
        · 用户截图那种状态（10 correct）✗ 右卡那句文字右边只剩
            en 209px / ko 173 / ja 161 / es 161 / it 129 / fr 【24px】✓
        · 账号当前真实状态（0 correct ✗ 句子更长）✗ 只剩
            ko 49 / ja 38 / es 【27px】/ zh-CN 93 / zh-TW 97 ✓
        · ar / fa（RTL）✗ 行内末端在【左边】✗ 同一行连 0px 都没有 ✓
     ⇒ 【【【11 语言塞不进同一行】】】✗ 连最短的候选（60px）都放不下 fr / es ✓
   ── 但右卡那块地方【本来就有预留】✗✗ ──
     · .mg-card .mg-sub 已有 min-block-size:3lh = 57.56px（= 3 行 ✓）
     · 数据行只用掉 1 行（17px）⇒ 下面【还空着 2 行】✓（截图里进度条上方那一大片空就是它 ✓）
   ── 结构修法 ✗ ──
     .mg-sub 变成 flex + wrap + space-between ✗ 鼓励语是它的【第二个 flex 项】✓
       · 放得下 ⇒ 落在用户圈的那块空白里（并且贴行内末端 = 正好是"签名"位 ✓）
       · 放不下 ⇒ 自动换到【预留的第 2 行】✗ 仍然是"右边对齐"✓
       · 最多占 3 行 = 正好等于 3lh 的预留 ⇒ 【两卡高度一个 px 都不变】✓
           （左卡在 en / ko / fr / de / it / es 是 2 行 ⇒ 2+1 = 3 ✓ 刚好兜住 ✓）
     ★ 不用 position:absolute ✗ 不用 text-indent ✗ 不用手填宽度 ✓
     ★ RTL 自动正确 ✗ flex 跟 direction 走 ⇒ ar / fa 下它自然落在【左边】✓
   ── 语气 ✗（★ 用户要求：面向小朋友 + 家长 ✗ 不说教 ✗ 不太幼稚 ✓）──
     左侧零数据那句讲"还没开始 ✗ 做一题就起步"✓
     这句讲"已经在路上了 ✗ 继续"✓ —— 同族、呼应、不重复 ✓
     11 语言全有独立文案 ✗ 不走英文兜底 ✓（见 my-growth.html 的 TXT 各语言块）
   ══════════════════════════════════════════════════════════════════════════ */
.mg-card .mg-sub{
  display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;column-gap:10px;
}
.mg-cheer{color:var(--mg-primary-dark);font-weight:var(--ce-fw-head);white-space:nowrap}
.mg-card--life .mg-cheer{color:var(--mg-navy)}
