/* ══════════════════════════════════════════════════════════════════════════
   avatar-frame.css　頭像框圖層契約（共用單一來源）　v0.61.0
   ══════════════════════════════════════════════════════════════════════════
   ★為什麼獨立成一支檔★（v0.61.0 hotfix，店長追加需求⑤）
     後台「頒發頭像框」需要★真正的合成預覽★（玩家目前頭像 ＋ 選中的框
     ＋ 玩家目前的裝備特效），而且店長明確要求：
       「預覽必須走正式共用 avatar renderer，不能另外做一套假的靜態示意，
         否則正式前台和後台 preview 會漂移。」
     renderer 那一半本來就已經是共用的（avatar-render.js 的 frameHtml）；
     缺的是 CSS —— 它原本整段住在 styles.css 裡，而 admin.html ★不載入 styles.css★。
     若把這 300 行複製到後台，就會出現第二份、然後開始漂移
     ——★那正是這個專案一路在修的同一種病★。
     ⇒ 原封不動抽成這一支，index.html 與 admin.html 都 link 它。
     ★內容逐行搬移，一個字都沒有改★（搬移前後 .lk-* 規則位元組相同）。
   ══════════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════════
   節慶／收藏頭像框　圖層契約（v0.60.994）
   ══════════════════════════════════════════════════════════════════════════
   ★雙 equip slot★：頭像框 1 個 ＋ 裝備特效 1 個可以同時啟用，玩家不必二選一。

     .lk-fr   z-index 1   頭像框（五槽，長在頭像外緣）
     頭像本體  z-index 2   既有的 img / background（★不改尺寸、不改 border-radius★）
     .lk-fx   z-index 3   裝備特效的覆蓋層（光效／粒子）

   ★中央安全區是結構性保證★
   店長的要求不是「頭像一定在最上層」，而是
   「任何 frame / effect 都不得以不透明內容侵入或遮住玩家頭像核心辨識區」。
   所以不靠「禁止不透明填色」的紀律，改用 clip-path 把該保護的區域
   【從裝飾層身上挖掉】——畫不出來，就不可能遮到：

     .lk-fr  挖掉【整個頭像方框】       ⇒ 框永遠只長在外面
     .lk-fx  挖掉【頭像中央 60%】       ⇒ 特效可以在外緣發光，但碰不到寵物的臉

   ★踩坑紀錄（中秋 v2 像素比對抓到的）★
   有定位且 z-index:0/1 的子元素會畫在父層自己的 background 之上，
   所以「放後面就會被頭像蓋住」是錯的 —— 一定要用 clip-path 挖掉。
   ══════════════════════════════════════════════════════════════════════════ */
:root{
  /* ★框層不再有遮罩★（v0.60.994-3）
     「不遮臉、不遮眼睛、不遮主要身體」由【繪製順序】保證：
     框層 z-index:-1 ⇒ 永遠畫在寵物圖片下面 ⇒ 跨進來的裝飾會被寵物自己擋住。
     幾何遮罩反而是做不出攀附感的原因（靠近中央一律被淡掉，
     所以怎麼調都是「五張貼紙圍在外面」）。

     下面兩個值只給【特效層】用 —— 特效層刻意在寵物之上（外緣光效要壓過邊緣），
     所以它需要保護臉部。臉部橢圓是實際量四隻寵物圖得到的：
     頭部落在 x 0.22～0.78、y 0.06～0.52 ⇒ 取中心 (50%, 32%)、半徑 (20%W, 20%H)，
     四隻的眼睛與口鼻全部在裡面。★改動要重跑視覺 Gate★。 */
  --lk-face-x: 20%;      /* 臉部保護橢圓的水平半徑（佔頭像寬） */
  --lk-face-y: 20%;      /* 臉部保護橢圓的垂直半徑（佔頭像高） */
  --lk-face-cy: 32%;     /* 臉部中心（偏上） */
  /* ★前層（.lk-fr2）的保護橢圓★：要保護的是【臉 ＋ 主要身體】，
     不是只有臉 —— 前層畫在寵物之上，身體被壓到就是「遮住主要辨識輪廓」。
     半徑 (34%W, 42%H)、中心 (50%, 46%) 是實際量四隻寵物圖的不透明輪廓得到的
     （頭 x 0.22～0.78 / y 0.06～0.52，身體到 y 0.88）。
     ★這一層的盒子是 2 倍大（inset:-50%），所以半徑要寫一半★。 */
  --lk-body-x: 15%;
  --lk-body-y: 18%;
  --lk-body-cy: 42%;
  /* ★邊緣前景層（.lk-fr3，只放 main）的保護橢圓★：半徑 26%W／24%H、中心 (50%, 34%)。
     與上面的身體橢圓是兩件事，理由與夾出來的量測值寫在 .lk-fr2.lk-fr3 規則上面。
     ★這一層的盒子也是 2 倍大 ⇒ 半徑寫一半★。 */
  --lk-edge-x: 13%;
  --lk-edge-y: 12%;
  --lk-edge-cy: 34%;
}

/* 需要戴框的容器：只加 position 與 overflow，★尺寸與圓角一律沿用既有規則★ */
/* 需要戴框的容器：只加 position / overflow / isolation，★尺寸與圓角一律沿用既有規則★
   isolation:isolate 讓這個容器成為 stacking context，
   框層才能安全地用 z-index:-1 待在「頭像本體之下、容器背景之上」。 */
/* ══ ★底板狀態：有配戴頭像框 ⇒ 原底板透明★（v0.60.994-5 店長正式裁定）═════
   實機比對後確認：配戴頭像框之後還看得到的那塊「奶油／蜜桃圓角方形卡片」
   不是頭像框、也不是遮罩，而是正式碼自己的頭像底色。底板透明之後，
   五槽的攀附感明顯強很多。

   ★沒有配戴框的玩家完全不受影響★ —— 這不是全站永久刪除底板，
   而是只在 .lk-framed 這個狀態下切換。狀態由【共用 renderer】決定
   （avatar-render.js 的 frameStateClass / markHost），CSS 這端只有這一條規則，
   ★沒有任何逐頁特判★。卸下頭像框時 class 被移除，底板自己就回來了。

   .cw-dot（賽事點點）刻意不列入：它的漸層是「沒有頭像時顯示姓名首字」的底，
   不是裝飾用的底板 —— 切透明會讓首字浮在空中。 */
.mehub-ava.lk-framed,
.avf-prev.lk-framed{ background: transparent; }
.hs-house .hs-ava.lk-framed{ background: transparent; }
.lb-pet.lk-framed > .lb-ava,
.nm-pet.lk-framed .nm-ava{ background: transparent; }

/* ══ ★有配戴頭像框 ⇒ 不顯示原本右下角的寵物 badge★（v0.61.0 hotfix）══════
   ── 店長實機回報③ ────────────────────────────────────────────────────────
     「套用頭像框後，右下寵物小圖仍疊在框上，小豬被頭像框遮住，視覺錯誤。」
   ── 正式規則（全站統一，不逐頁特判）────────────────────────────────────
     有 equipped avatar frame ⇒ 不顯示原本的寵物 emoji / pet badge
     沒有 equipped avatar frame ⇒ 才顯示玩家自己的寵物標記
   ── 為什麼寫在這裡 ──────────────────────────────────────────────────────
     .lk-framed 是★共用 renderer 唯一的「這個頭像有戴框」狀態★
     （avatar-render.js 的 frameStateClass / markHost 決定，CSS 這端沒有任何
      逐頁判斷）。所以規則只要掛在它身上，★所有 avatar surface 自動適用★，
     以後新增的 surface 只要照既有規矩帶 .lk-framed 就也會正確 ——
     不需要、也不准再去每一頁各寫一次。
   ── 刻意保留的事 ────────────────────────────────────────────────────────
     ★只收掉 badge，不動裝備特效★：特效是另一個獨立 slot（.axfx-*／.axfx-ring
     畫在別的層），這條規則一個字都沒碰到它 ⇒ 框與特效仍然可以同時存在。
     卸下框時 .lk-framed 被移除，badge 自己就回來了，
     ★不需要另外寫一條卸下的邏輯★（和上面底板透明同一個機制）。 */
.lk-framed .ava-badge,
.lk-framed > .ava-badge{ display: none !important; }

/* ★白內圈：弱化版★（店長裁定：不要原本 2px 純白，也不要完全取消）
   目的是讓淺色寵物在不同背景仍有辨識度，但肉眼不能看成一個方形框。
   ⇒ 保留 2px 的厚度（太細在高解析度手機上會消失），把純白降到 45% 透明度。
   正式碼原本那條在 index.html:1443，這裡用更高的特異度覆蓋，
   ★沒有刪掉原本那一行★，要回去比對只要把這條註解掉。 */
.mehub-ava.mehub-ava{ box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .45); }

.lb-pet, .nm-pet, .hs-ava, .mehub-ava, .cw-dot, .le-pet-inner{
  position: relative; overflow: visible; isolation: isolate; }

/* ══ 固定 avatar slot 契約（多人列表）══════════════════════════════════════
   店長要求：排行榜／鄰居／拜訪／訪客／好友／活動參賽者這些多人列表，
   ★無框／有框／只有特效／框＋特效四種狀態都必須同尺寸、同列高、同卡高、
     同 gap、同每頁人數★。

   做法（三條，缺一不可）
     ① slot 是固定尺寸的盒子 —— 尺寸由 CSS 決定，★不准由內容決定★
        （否則頭像載入失敗退回 emoji 時，那一列的 slot 就會變大小）
     ② 在 flex 列裡是 flex:none ⇒ 不會被擠壓、也不會被內容推大
     ③ 框層與特效層一律 position:absolute ＋ pointer-events:none
        ⇒ ★不參與 document flow★ ⇒ 絕對不可能影響列高或每頁人數
   裝飾允許的外溢範圍（visual safe zone）：FULL 10 / MID 8 / COMPACT 7 px。
   超過就用 FULL→MID→COMPACT 降級處理 —— ★不准撐大父容器、不准加 spacer★。
   由 tools/avatar-list-geometry-gate.mjs 混排四種狀態實測。
   ══════════════════════════════════════════════════════════════════════════ */
.lb-pet, .nm-pet, .hs-ava, .cw-dot{ flex: none; }
/* ★真問題★：.nm-pet（新成員列表）原本只有 font-size:22px ＋ flex:none，
   ★沒有固定寬高★ —— 尺寸是由裡面的 .nm-ava（34px）或 emoji 的行高決定的。
   同一個列表裡只要有一列退回 emoji，那一列的 slot 就跟別人不一樣大，
   百分比定位的框層也會跟著縮放。補上固定尺寸（與 .nm-ava 相同的 34px），
   ★視覺上沒有任何改變★（原本有照片時就是 34px），但契約從此成立。 */
.nm-pet{ width: 34px; height: 34px; line-height: 34px;
  display: inline-flex; align-items: center; justify-content: center; }
/* ★真 bug★：這兩個容器在正式碼裡有 overflow:hidden（而且選擇器比上面那一條更specific），
   框層會被裁在盒子裡面 ⇒ 這兩個場景一個像素都看不到框。
   preview 沒有 .hs-house／#cupScreen 外層，所以量不到 —— 只有讀正式碼才會發現。
   頭像 img 本身是 object-fit:contain/cover，從來不會溢出，所以放開 overflow
   ★不會改變頭像本體的外觀★（由 Gate 逐像素回驗）。 */
div.hs-house div.hs-ava{ overflow: visible; }
#cupScreen span.cw-dot{ overflow: visible; }

/* ── 框層 ─────────────────────────────────────────────────────────── */
.lk-fr{
  /* ★inset:0 ＋ 沒有遮罩★（v0.60.994-3）
     · 上一版把盒子做成 2 倍大（inset:-50%），那是為了避開 mask-clip 的 border-box
       裁切；遮罩拿掉之後這個變通就不需要了，回到頭像自己的座標系，
       子槽的百分比直接以頭像為基準，看得懂也好調。
     · overflow 由祖先保持 visible（見上面的容器規則），裝飾可以自由長到頭像外面。
     · ★z-index:-1 是這一套的安全基礎★：依 CSS 繪製順序，負 z-index 的定位子元素
       永遠畫在「容器背景之上、在流內容（也就是寵物 img）之下」。
       所以裝飾不論貼多近、跨多少進來，都會被寵物自己擋住 ——
       不遮臉、不遮眼睛、不遮主要身體是結構性的，不是靠一個幾何遮罩。 */
  position: absolute; inset: 0; pointer-events: none;
  z-index: -1;
}
/* ══ 前層：畫在寵物【前面】的那幾槽 ═══════════════════════════════════════
   只有後層的話，寵物會擋掉每一槽的主體（逐槽診斷實測：五槽都只剩一條葉子），
   而把槽往外推又會遮到文字（Gate 抓到 90 處）。所以 hang / flora / band
   改由這一層畫在寵物前面 —— 這才是「局部互相壓住、前後交錯」。
   ★這一層一定要有遮罩★（後層一定不能有，兩者剛好相反）：
   它在寵物之上，保護臉與主要身體的責任完全在遮罩身上。
   橢圓中心 (50%,46%)、半徑 (34%W,42%H) 是實際量四隻寵物圖的不透明輪廓得到的；
   橢圓內完全透明，往外 1.45 倍才完全顯示 ⇒ 只在頭像外圈有存在感。
   ★沒有任何直邊，不會出現方卡感★。
   inset:-50% 是因為 mask-clip 預設 border-box 會把整層裁成方形。 */
.lk-fr2{
  position: absolute; inset: -50%; pointer-events: none; z-index: 2;
  -webkit-mask-image: radial-gradient(ellipse var(--lk-body-x) var(--lk-body-y)
      at 50% calc(25% + var(--lk-body-cy) / 2),
      transparent 0 100%, rgba(0, 0, 0, .35) 112%, rgba(0, 0, 0, .75) 124%, #000 138%);
  mask-image: radial-gradient(ellipse var(--lk-body-x) var(--lk-body-y)
      at 50% calc(25% + var(--lk-body-cy) / 2),
      transparent 0 100%, rgba(0, 0, 0, .35) 112%, rgba(0, 0, 0, .75) 124%, #000 138%);
}
/* 前層的子槽：座標系是 2 倍盒子 ⇒ 尺寸÷2、位移 25%+原值÷2（幾何與後層一致） */
.lk-fr2 > i{
  position: absolute; display: block; background: center/contain no-repeat;
  background-color: transparent;
}
/* ══ 邊緣前景層 .lk-fr3（v0.61.3-3）══════════════════════════════════════
   ★它同時帶 lk-fr2★ ⇒ 子槽幾何、動效、清除邏輯全部沿用既有規則，
   ★main 的幾何一個像素都沒有動★（動了就會與後層同一張圖錯位＝疊影）。
   這裡只覆寫兩件事：
     ① z-index: 1 —— 在玩家照片（in-flow、z:auto）之上，在 .lk-fr2（z:2）之下
     ② 遮罩換成【給 main 用】的小橢圓＋短淡出帶，不是 .lk-fr2 那個
        【臉＋主要身體】的大橢圓＋長淡出帶

   ★為什麼一定要換遮罩（v0.61.3 正式站被打回的真正原因）★
   .lk-fr2 的遮罩半徑是 30%W/36%H、要到 1.38 倍才完全不透明 —— 那是為了 hang／flora／band
   這種會垂掛、繞過寵物身體的槽而設計的。main 是【外圈角落主視覺】，它跨過照片邊緣的位置
   正好落在那個大橢圓的淡出帶裡：真頁實測頭像上緣 y=5% 只剩 alpha 0.41、y=15% 直接 0，
   所以正式站那一版雖然結構完全正確、Gate 全綠，畫面上只剩「淡淡的小圈」。

   這一層的橢圓＝正式碼原本就量好的【臉部橢圓】：中心 (50%, 32%)、半徑 (20%W, 20%H)
   （四隻寵物的眼睛與口鼻都在裡面，見檔頭 --lk-face-*）。
   盒子是 2 倍大（inset:-50%）⇒ 半徑寫一半（10%）、中心 y 寫 25% + 32%/2 = 41%。
   同一個 y=5% 的點：alpha 0.41 → 0.95。★臉仍然是結構性保護，不是紀律★。 */
.lk-fr2.lk-fr3{
  z-index: 1;
  /* ★這一層的保護橢圓，與 .lk-fr2 的是兩件不同的事★（v0.61.3-3 定案）
     .lk-fr2 的 (30%W,36%H) 大橢圓是為了 hang／flora／band —— 那幾槽會垂掛、
     會繞過寵物身體，所以要連主要身體一起保護、而且要很長的淡出帶。
     main 是【外圈角落主視覺】，它的任務只有一個：跨過頭像邊緣壓在照片上面。
     沿用那個大橢圓，跨界的那一段正好整片落在淡出帶裡 —— 真頁實測頭像上緣
     y=5% 只剩 alpha 0.41、y=15% 直接 0 ⇒ 結構全對、畫面只剩「淡淡的小圈」，
     就是 v0.61.3 正式站被店長打回的那個狀態。

     ★這裡的數值是夾出來的，不是喊的★（15 套 × 3 強度全量測，同一條淡出帶）：
       半徑 20%W/20%H（＝純臉部橢圓）⇒ V-07 紅 4 組、蓋到寵物核心 41 px
       半徑 22%W/20%H               ⇒ V-07 紅 1 組（dragonboat 13 px）
       半徑 24%W/22%H               ⇒ ★全綠★（第一個安全值）
       半徑 26%W/24%H               ⇒ ★全綠，再往外留一格餘裕★ ← 採用
     取再往外一格是因為 V-07 的判準是「一個像素都不准」，而發布 Gate 會在
     另一個瀏覽器（Windows Chrome）上重跑，不留餘裕會被 1px 的算繪差異翻掉。

     ★淡出帶刻意短★（100%→120%，不是 .lk-fr2 的 100%→138%）：
     真正壓掉亮度的是長淡出帶，不是洞的大小。洞只挖掉「本來就必須保護」的中央，
     短淡出帶讓洞外面很快回到全亮 —— 這才是「明確跨在上層」與「淡淡一圈」的差別。
     真實不透明大頭照 15 套實測，框內接近全亮（ΔRGB≥110）的像素：
       無邊緣層 0 ｜ 身體遮罩（正式站 v0.61.3）5459 ｜ ★本版 8471★（1.55 倍）
     盒子是 2 倍大（inset:-50%）⇒ 半徑寫一半、中心 y 寫 25% + 34%/2 = 42%。 */
  -webkit-mask-image: radial-gradient(ellipse var(--lk-edge-x) var(--lk-edge-y)
      at 50% calc(25% + var(--lk-edge-cy) / 2),
      transparent 0 100%, rgba(0, 0, 0, .55) 104%, rgba(0, 0, 0, .85) 112%, #000 120%);
  mask-image: radial-gradient(ellipse var(--lk-edge-x) var(--lk-edge-y)
      at 50% calc(25% + var(--lk-edge-cy) / 2),
      transparent 0 100%, rgba(0, 0, 0, .55) 104%, rgba(0, 0, 0, .85) 112%, #000 120%);
}

/* ★邊緣前景複本：main★（v0.61.3 建立／v0.61.7 修正對齊）
   同一張 main 在後層畫一次（整張、無遮罩、當景深），在這一層再畫一次；
   這一層的橢圓遮罩讓它★只在「跨過頭像邊緣」那一圈★顯示在照片之上，
   越靠近臉越淡、中央完全透明 ⇒ 邊緣裝飾看得到，臉結構上蓋不到。
   幾何是後層那組的等價換算（2 倍盒：尺寸÷2、位移 25%+原值÷2）。

   ★★v0.61.7 共用 root cause：兩份 main 的 background-position 不一致 ⇒ 15 套都出現雙影★★
   ── 原本這裡寫 background-position: left top，理由寫成「.lk-fr2 > i 的 background
      簡寫會把它設回 center，那會讓兩張圖對不齊」。★那個前提是錯的★：
      後層的 .lk-fr > i 用的是同一個 `background: center/contain no-repeat` 簡寫，
      而 .lk-fr-main 的 `background-position: left top`（特異度 0,1,0）
      ★打不過 .lk-fr > i（0,1,1）★ ⇒ ★後層實際上是 center★。
      這一層的 .lk-fr2 .lk-fr-main（0,2,0）卻打得過 ⇒ ★前層是 left top★。
   ── 真瀏覽器逐框實測（15/15，tools/_probe/a5_bgpos.mjs）：
        後層 main background-position = 50% 50%（center）
        邊緣複本 main background-position = 0% 0%（left top）
        兩者的「盒」完全一致、background-size 同為 contain
      ⇒ 同一張圖在同一個盒裡被放在兩個位置，contain 的留白越大位移越大：
        cny-lantern（205×384，細長）在 64%×60% 的盒裡留白約半個盒寬
        ⇒ 畫面上就是★兩盞燈籠並排★（店長看到的雙影）；
        ma-moon（384×382，接近正方）留白小 ⇒ 只是邊緣變厚。
      這是共用 renderer／CSS 的單一原因，不是任何一套素材或某一格的個案。
   ── 修法（共用、一行）：讓複本沿用與後層完全相同的 center
      ⇒ 兩份 main 逐像素重合（複本原本就該只是「同一張圖的前景段」），
        後層／前層／遮罩／z-index／15 套原始美術一律 0 變更。
   ★不要再把它改回 left top★：要改對齊，必須連後層 .lk-fr > i 一起改，
   那會移動 15 套已驗收的構圖，屬於美術決策、不是這一行的事。 */
.lk-fr2 .lk-fr-main { width: 32%;   height: 30%;   left: 17.5%;  top: 16.5%;
                      background-position: center; }
.lk-fr2.lk-fr-mid .lk-fr-main { width: 35%; height: 32%; left: 16.5%; top: 16.5%; }
.lk-fr2.lk-fr-compact .lk-fr-main { width: 29%; height: 28%; left: auto; right: 15%; top: 15%;
                      background-position: right top; }
.lk-fr2 .lk-fr-hang { width: 16%;   height: 28%;   right: 19%;   top: 20%;
                      background-position: center top; transform-origin: 50% 0%; }
.lk-fr2 .lk-fr-flora{ width: 23%;   height: 26%;   right: 18.5%; bottom: 19.5%;
                      background-position: right bottom; transform-origin: 88% 92%; }
.lk-fr2 .lk-fr-band { width: 63%;   height: 22%;   left: 18.5%;  bottom: 20.5%;
                      background-position: center bottom; }
/* ★v0.61.2 hotfix★ pet（吉祥物：兔子／舞獅／柴犬…）改由前層畫。
   原本它在後層（z-index:-1），而幾何是 left:-13% / bottom:-7% ——
   主體整個壓在頭像方框內 ⇒ 被頭像照片蓋掉，實機只看得到左下角一小截。
   幾何是後層那組的等價換算（width 40→20、height 46→23、
   left -13 → 25+(-13)/2 = 18.5、bottom -7 → 25+(-7)/2 = 21.5），
   ★視覺位置與原設計完全一樣，只是換了繪製順序★。
   前層的橢圓遮罩保護臉與主要身體，所以移上來不會遮到臉。
   pet 只出現在 FULL（registry 的 tiers：mid／compact 都沒有它），
   所以不需要 MID／COMPACT 的對應規則。 */
.lk-fr2 .lk-fr-pet  { width: 20%;   height: 23%;   left: 18.5%;  bottom: 21.5%;
                      background-position: left bottom; }
/* MID / COMPACT 的前層跟著各自的配比（同樣是原值÷2、位移 25%+原值÷2） */
.lk-fr2.lk-fr-mid .lk-fr-hang { width: 17%;   height: 28%;   right: 17.5%; top: 19%; }
.lk-fr2.lk-fr-mid .lk-fr-flora{ width: 25%;   height: 28%;   right: 17%;   bottom: 18.5%; }
.lk-fr2.lk-fr-mid .lk-fr-band { width: 65%;   height: 23%;   left: 17.5%;  bottom: 19%; }
.lk-fr2.lk-fr-compact .lk-fr-hang { width: 21%; height: 31%; right: 16%;   top: 17%; }
.lk-fr2.lk-fr-compact .lk-fr-flora{ width: 26%; height: 27%; right: 16%;   bottom: 17%; }
.lk-fr2.lk-fr-compact .lk-fr-band { width: 63%; height: 23%; left: 18.5%;  bottom: 18%; }
/* pet 的 MID／COMPACT（有幾套框在這兩個 tier 也帶吉祥物，例如 taichung／groupbuy）。
   同樣是後層那組的等價換算：MID 42/50/-16/-10 → 21/25/17/20；
   COMPACT 46/52/-18/-14 → 23/26/16/18。特異度 (0,3,0) 高於後層的 .lk-fr-mid .lk-fr-pet，
   ★不靠排列順序取勝★。 */
.lk-fr2.lk-fr-mid .lk-fr-pet  { width: 21%; height: 25%; left: 17%;   bottom: 20%; }
.lk-fr2.lk-fr-compact .lk-fr-pet { width: 23%; height: 26%; left: 16%; bottom: 18%; }
.lk-fr > i{
  position: absolute; display: block; background: center/contain no-repeat;
  /* ★每一槽的圖要靠自己那一側對齊★（v0.60.994-3）
     contain 預設置中，於是素材的主體會落在槽的正中央 —— 而槽是壓在頭像上的，
     框層又畫在寵物下面（z-index:-1）⇒ ★主體剛好被寵物遮住，只露出外圈的葉子★。
     逐槽診斷時五槽都只看得到一條綠邊，小舖、好物袋、👍 吊飾全部認不出來。
     改成往自己那一側對齊，主體就落在頭像的角落（寵物是透明的那一塊），
     素材自己的透明留白則疊在寵物上 —— 這才是「沿邊生長」而不是「被擋住」。 */
  /* 每一槽的位置與尺寸都用百分比，所以 56 / 44 / 30 三種尺寸共用同一組規則
     ★不需要任何 magic number★ */
}
/* ══ 攀附感的共用 layout 規則（★15 套共用，不准每套手調★）═══════════════
   店長要的是「素材像植物、飾品、緞帶一樣攀附在頭像邊緣」，
   不是「五個素材平均分布在頭像四周」。所以每一槽都：
     · 貼著某一條邊或某一個角（負位移只留一小截在外面）
     · 沿著那條邊延伸（形狀被拉長，不是四平八穩的方塊）
     · 大方地跨進頭像內部 —— 跨進來的部分會被寵物自己擋住（z-index:-1），
       所以視覺上就是「沿著寵物輪廓咬合」
   百分比都以頭像自己為基準（框層 inset:0）。 */
.lk-fr > i{
  transform-origin: 50% 50%;
  /* ★只能有 background-image，不得有 background-color★
     任何一塊底色都會在頭像上疊出第二層卡片感 —— 那正是店長否決的「奶油白圓角方框」。
     由 tools/avatar-frame-gate.mjs 的 V-17 逐槽回驗。 */
  background-color: transparent;
}
/* ══ 前後交錯（z-order）══════════════════════════════════════════════════
   五個 <i> 是兄弟節點，不指定的話畫的順序就是 DOM 順序
   main→pet→hang→flora→band ⇒ ★下緣緞帶會壓在吉祥物身上★。
   那是意外不是構圖。一個完整構圖的前後關係是：
     main 最後面（背景層次）→ flora → band（緞帶壓住花枝下段）
     → pet（★吉祥物坐在緞帶上，不是被緞帶蓋住★）→ hang 最前面（掛在所有東西之前）
   ★這些 z-index 不會逃出框層★：.lk-fr 有 position:absolute ＋ z-index:-1，
   non-auto 的 z-index 讓它自己成為 stacking context，
   子槽只在框層內部排序，不可能跑到玩家寵物之上。 */
/* ★v0.61.2 店長裁定的層級★：main / band 在中層，flora / pet / hang 在上層。
   （原本是 flora(2) < band(3)，緞帶會壓住花枝下段；店長要花枝也算前景裝飾。） */
.lk-fr-main  { z-index: 1; }
.lk-fr-band  { z-index: 2; }
.lk-fr-flora { z-index: 3; }
.lk-fr-pet   { z-index: 4; }
.lk-fr-hang  { z-index: 5; }
/* ① 主視覺：咬住左上角，並★沿著上緣往右延伸★（寬 > 高，不是一顆球黏在角上） */
.lk-fr-main  { width: 64%; height: 60%; left: -15%; top: -17%;
               background-position: left top; transform-origin: 10% 12%; }
/* ② 吉祥物：坐在左下角的框邊上，只露一小截在外面 ⇒ 像扒著邊 */
.lk-fr-pet   { width: 40%; height: 46%; left: -13%; bottom: -7%;
               background-position: left bottom; }
/* ③ 吊掛物：從右上外緣掛下來，★提繩頂到頭像上緣★（擺動軸心就在那裡） */
.lk-fr-hang  { width: 32%; height: 56%; right: -12%; top: -10%;
               background-position: center top; transform-origin: 50% 0%; }
/* ④ 植物：從右下往上攀，沿著右緣與下緣生長（高 ≈ 寬 ⇒ 像藤蔓不是花束） */
.lk-fr-flora { width: 46%; height: 52%; right: -13%; bottom: -11%;
               background-position: right bottom; transform-origin: 88% 92%; }
/* ⑤ 下緣帶：★包住下緣★（往上吃到頭像高度的 6 成處），左右各外溢一小截 */
.lk-fr-band  { width: 126%; height: 44%; left: -13%; bottom: -9%;
               background-position: center bottom; }

/* MID（鄰居 44px）：留 2～3 個元素。同樣的百分比在 44px 上換算出來的像素比較小，
   看起來會變成「卡片裡放了插圖」而不是「攀附在邊緣」——
   所以 MID 的外溢比例要★再大一點★，讓元素確實破出方框的輪廓。
   上限是 safe zone 8px ÷ 44px ＝ 18%，下面都壓在那之內（由 Gate V-08 量）。 */
.lk-fr-mid .lk-fr-main { width: 70%; height: 64%; left: -17%; top: -17%; }
.lk-fr-mid .lk-fr-hang { width: 34%; height: 56%; right: -15%; top: -12%; }
.lk-fr-mid .lk-fr-band { width: 130%; height: 46%; left: -15%; bottom: -12%; }
.lk-fr-mid .lk-fr-pet  { width: 42%; height: 50%; left: -16%; bottom: -10%; }
.lk-fr-mid .lk-fr-flora{ width: 50%; height: 56%; right: -16%; bottom: -13%; }

/* COMPACT（排行榜 30px）：只剩 1～2 個元素，所以主視覺要★咬住右上角★、
   大方地壓進頭像一半，才不會看起來像一顆浮在旁邊的小點。
   （右上角是因為左邊有名次數字，避開它。） */
.lk-fr-compact .lk-fr-main{ width: 58%; height: 56%; left: auto; right: -20%; top: -20%;
                             background-position: right top; }
.lk-fr-compact .lk-fr-hang{ width: 42%; height: 62%; right: -18%; top: -16%; }
.lk-fr-compact .lk-fr-flora{ width: 52%; height: 54%; right: -18%; bottom: -16%; }
.lk-fr-compact .lk-fr-band{ width: 126%; height: 46%; left: -13%; bottom: -14%; }
.lk-fr-compact .lk-fr-pet { width: 46%; height: 52%; left: -18%; bottom: -14%; }

/* 動態：只有 main / hang / band 有動畫（四個角都在動會變跑馬燈）。
   每一條的時長都乘上 --lk-mo，reduced-motion 時 --lk-mo:0 ⇒ 0s ⇒ 停在靜態樣式。 */
:root{ --lk-mo: 1; }
.lk-fr-main{ animation: lkFrBreath calc(4s * var(--lk-mo)) ease-in-out infinite; }
.lk-fr-hang{ animation: lkFrSway   calc(6.5s * var(--lk-mo)) ease-in-out infinite;
             transform-origin: 50% 0%; }
.lk-fr-band{ animation: lkFrDrift  calc(11s * var(--lk-mo)) ease-in-out infinite; }
@keyframes lkFrBreath{ 0%,100%{ opacity:.92 } 50%{ opacity:1 } }
@keyframes lkFrSway  { 0%,100%{ transform: rotate(-3.2deg) } 50%{ transform: rotate(3.2deg) } }
@keyframes lkFrDrift { 0%,100%{ transform: translateX(-1.5%) } 50%{ transform: translateX(1.5%) } }

/* ── 特效覆蓋層（未來的粒子／閃光走這一層）────────────────────────── */
.lk-fx{
  /* 特效層★刻意★在寵物之上（外緣光效、粒子、閃光要壓過邊緣才好看），
     所以它不能用負 z-index ⇒ 保護臉的責任在這一層自己身上。
     遮罩改成【臉部橢圓】而不是一個大圓／方框：
     橢圓中心 (50%, 32%)、半徑 (20%W, 20%H)，是實際量四隻寵物圖得到的
     （頭部 x 0.22～0.78、y 0.06～0.52），眼睛與口鼻全部在裡面。
     往外 1.35 倍才完全顯示 ⇒ 光效在臉外圍柔和淡入，臉上永遠是 0。
     ★mask-clip 預設是 border-box★，所以這一層刻意做成 2 倍大（inset:-50%），
     否則光效會被裁成方形（上一輪踩過的坑）。 */
  position: absolute; inset: -50%; z-index: 3; pointer-events: none;
  -webkit-mask-image: radial-gradient(ellipse calc(var(--lk-face-x) / 2) calc(var(--lk-face-y) / 2)
      at 50% calc(25% + var(--lk-face-cy) / 2),
      transparent 0 100%, rgba(0, 0, 0, .35) 115%, rgba(0, 0, 0, .8) 126%, #000 135%);
  mask-image: radial-gradient(ellipse calc(var(--lk-face-x) / 2) calc(var(--lk-face-y) / 2)
      at 50% calc(25% + var(--lk-face-cy) / 2),
      transparent 0 100%, rgba(0, 0, 0, .35) 115%, rgba(0, 0, 0, .8) 126%, #000 135%);
}

/* ★頭像本體的層級★（v0.61.5 修正）
   ── 原本這一條寫的是 z-index: 1，註解說「負 z-index 已經保證了，這是第二層保險」──
   那是【只有後層】的年代寫的。後來加了前層（z:2），1 < 2 所以還是對的；
   但 v0.61.3 又加了★邊緣前景層 .lk-fr3（z:1）★ —— 與這一條【同層級】，
   而頭像 <img> 在 DOM 裡排在三個框層之後 ⇒ ★同 z-index 由後者勝★
   ⇒ 在這五個 surface（排行榜／新朋友／鄰居／聊天小圓點／活動參賽者）上，
   main 的邊緣複本被玩家照片整片蓋掉，畫面回到「被照片硬切」。
   .mehub-ava（會員卡）不在這個選擇器裡，img 是 in-flow、z-index:auto，
   所以同一版在會員卡是對的、在排行榜是錯的 —— 這就是店長看到的差異。
   ── 修法 ──
   改成 z-index: 0：仍然明確在後層（-1）之上（保險的原意完全保留），
   但明確在邊緣前景層（1）與前層（2）之下，順序在所有瀏覽器都一樣，不靠 DOM 順序。
   ★這是共用契約的一行修正，不是替排行榜寫的 hack★。 */
.lb-pet > .lb-ava, .nm-pet > .nm-ava, .hs-ava > img,
.cw-dot > .cw-dotimg, .le-pet-inner > .le-pet-img{ position: relative; z-index: 0; }

/* ★reduced-motion★
   只把 --lk-mo 設成 0（時長變 0s）不夠：Chrome 的 getAnimations() 仍會把
   「0s ＋ infinite」算成 running，Gate 量到的動畫數不會歸零，而且行為含糊。
   ⇒ 直接 animation:none，語意最清楚，量測也一定是 0。 */
@media (prefers-reduced-motion: reduce){
  :root{ --lk-mo: 0; }
  .lk-fr-main, .lk-fr-hang, .lk-fr-band{ animation: none !important; }
}
.lk-rm{ --lk-mo: 0; }
.lk-rm .lk-fr-main, .lk-rm .lk-fr-hang, .lk-rm .lk-fr-band{ animation: none !important; }
