
:root{
  --c-purple-900:#5B3977;
  --c-purple-800:#7D5B99;
  --c-purple-700:#8557A8;
  --c-purple-600:#8E6FA7;
  --c-purple-400:#9C74BC;
  /* 官方 --c-purple-300 是高彩度亮紫，文件明講「只給漸層用」，不能拿來當一般
     border/outline（會太搶眼）。這裡先校正數值本身，呼叫端的 border 用法另外
     改連 --c-purple-600（見下方各處），不要因為校正了數值就變成滿版霓虹紫框。 */
  --c-purple-300:#D5A4FF;
  --c-purple-200:#D7C8E4;
  --c-purple-100:#EBE3F2;
  /* hpsk-ui 文件記載的推導式寫法（color-mix + --opacity-50），不是自創色階；
     算出來的值跟這裡原本寫死的 #F5F1F8 完全一致，純粹是把「怎麼算出這個顏色」的
     依據換成官方公式，視覺上不會有變化。 */
  --c-purple-50:color-mix(in srgb, var(--c-purple-100) var(--opacity-50), var(--white));
  --opacity-10:10%;
  /* 引導橫幅脈動光暈（.hm-click-hint 的 hm-notice-pulse keyframe）原本寫死
     rgba(133,87,168,.15)，改用 color-mix 需要的透明度階，數值照抄 5168-tokens.css。 */
  --opacity-20:20%;
  --opacity-50:50%;
  /* 圖表色值收攏（sdd/ui-align-list-page/01-UIUX評估與修正建議.md 建議6）新增這兩階，
     數值照抄 5168-tokens.css 官方透明度量表，不自己調整：
     --opacity-80 給直條圖有資料的長條用（原本寫死 opacity="0.82"，官方階最接近的是 80%）；
     --opacity-0 給趨勢圖面積漸層淡出的那一端用（原本寫死 stop-opacity="0.01"，視覺上跟
     完全透明沒有可辨識差異，官方階直接有 0% 可用，不需要湊一個非 0 的假值）。 */
  --opacity-80:80%;
  --opacity-0:0%;
  /* hpsk-ui 0.6.0：橘色價格「文字」專用 800 階（≥20px 且粗體，只放白卡／灰卡）；
     700 階 #F97D03 只留給非文字（底色、描邊、漸層），不得再當價格字色。 */
  --c-orange-800:#E17002;
  --c-orange-700:#F97D03;
  --c-brown-600:#B5A99D;
  --c-yellow-500:#FFFB83;
  --c-yellow-100:#FFFEE0;
  /* 錯誤/警示語意色。「特殊交易」原本用這階做紅底標籤（.tag-spec），2026-09
     異常備註三層收斂（§3-A）拍板拿掉，改成灰字純文字＋ⓘ icon；此階暫無其他呼叫端，
     保留 token 定義本身（不是本輪要清的範圍）。 */
  /* 漲色「文字」專用 800 階（年增率漲幅等）；700 階只給邊框、色塊、圖表線 */
  --c-red-800:#CE331A;
  --c-red-700:#EC3C1F;
  /* 跌色／成交確認「文字」專用 800 階（年增率跌幅、.bc-social「社宅」標籤字）；700 階只給色塊、圖表線、淡底 */
  --c-green-800:#317E1A;
  /* 色塊／淡底用（.bc-social 淡底），當文字請用 --c-green-800 */
  --c-green-700:#3D9921;
  --c-dark-900:#333333;
  --c-dark-100:#F8F7F5;
  /* 填色灰卡底色（規範 --c-surface-sunken → .card-shell.is-sunken，放白底區塊） */
  --c-surface-sunken:var(--c-dark-100);
  --radius:4px;
  --ink:#333333;
  --ink-soft:#666666;
  /* hpsk-ui 文字色只有三階（333/434343/666），沒有自己這個 #767676 的第四階；
     改成跟官方「輔助文字」階（--c-dark-700）同值，不改變數名以免要動所有呼叫端。 */
  --ink-mute:#666666;
  /* 官方灰階中間那一階（--c-dark-800），本站原本的灰階只有 --ink/--ink-soft/
     --ink-mute 三個語意命名、缺這一階，按鈕 hover 需要它，直接沿用官方命名補上。 */
  --c-dark-800:#434343;
  /* 官方灰階分隔線的下一階（比 --line／官方 --c-dark-300 深一階）。官方對這階
     的用途註記是「灰底上的分隔線（白底分隔線用 dark-300）」——本站表格坐在
     白卡上，用途上並不合規，這裡是明知並刻意的偏離，不是「數值照抄官方色階
     就等於合規」。取這階的理由：dark-300 就是本站原值 --line #EAEAEA，對白底
     僅 1.20:1，在密集表格 612px 跨距上淡到等於不存在；參考頁 #CCCCCE 又不在
     官方色階內。PM 拍板（sdd/ui-align-list-page/01-UIUX評估與修正建議.md
     §5 Q4 選項 A）改用這階換取列邊界可讀性，數值照抄 5168-tokens.css，不自己
     調深淺；同一次拍板 PM 也決定不採斑馬紋，避免引入本站與參考頁都沒有的視覺
     語彙。表格元件官方無規範可循，缺件已另案提報設計團隊。 */
  --c-dark-400:#D5D5D5;
  /* 圖表軸線（renderHist／renderQtrTrend 的 X/Y 軸本體，原本寫死 #ccc）要用的官方
     灰階，站上其餘語意名（--ink/--ink-soft/--line/--bg/--c-dark-800/--c-dark-400）
     都沒有對到這一階，比照上面幾個新增 token 的作法，數值照抄 5168-tokens.css。 */
  --c-dark-500:#B0B0B0;
  --line:#EAEAEA;
  --bg:#F1F1F1;
  --card:#FFFFFF;
  --white:#FFFFFF;
  --ff:system-ui,-apple-system,BlinkMacSystemFont,'PingFang TC','Microsoft JhengHei','Segoe UI','Noto Sans TC','Heiti TC',sans-serif;
  --r:8px;
  /* 內容上方固定佔用的高度，JS 執行前的預設值。
     實際值由 app.js 的 setFilterStickyTop() 量測 NavBar／麵包屑／膠囊分頁／
     地圖頁標題列後寫入——2026-08-17 版面重構後這段由四塊可變高度組成，寫死會失準。 */
  --chrome:226px;
  /* --sh 已確認完全等同官方 --shadow（一般卡片階），維持原樣、不要動——
     以下是原本沒有引入、但這次要拿來取代站上其餘 ~8 個自創 box-shadow 數值的
     官方陰影量表其餘幾階，數值照抄 5168-tokens.css，不自己調整模糊/位移。 */
  --shadow-sm:0 1px 2px 0 rgb(0 0 0/.05);
  --shadow-md:0 4px 6px -1px rgb(0 0 0/.1),0 2px 4px -2px rgb(0 0 0/.1);
  --shadow-lg:0 10px 15px -3px rgb(0 0 0/.1),0 4px 6px -4px rgb(0 0 0/.1);
  --shadow-xl:0 20px 25px -5px rgb(0 0 0/.1),0 8px 10px -6px rgb(0 0 0/.1);
  --shadow-2xl:0 25px 50px -12px rgb(0 0 0/.25);
  --sh:0 1px 3px 0 rgb(0 0 0/.1),0 1px 2px -1px rgb(0 0 0/.1);
}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;scrollbar-gutter:stable}
body{font-family:var(--ff);font-size:16px;color:var(--ink);background:var(--bg);min-height:100vh}
a{color:var(--c-purple-800);text-decoration:none}
/* 正式 NavBar 內的連結顏色交回套件自己的 class 決定（否則下拉選單會被染成本站紫）。
   用 :where() 把特異度壓成 0,0,1：贏得過瀏覽器預設連結藍、又輸給 Tailwind 的
   .text-white / .text-c-dark-800（0,1,0），active 項目的白字才不會被壓掉。
   必須放在上面那條 a 之後——兩者特異度相同，靠順序決勝。 */
:where(.navbar-slot) a{color:inherit}
button{font-family:var(--ff);cursor:pointer;border:none;background:none}
select,input{font-family:var(--ff)}
/* 鍵盤 focus 指示：站上多處對可互動元件下了 outline:none 只留邊框變色（不夠明顯，
   純滑鼠使用者也看得到、干擾視覺），鍵盤操作者因此完全看不到焦點在哪。
   統一補一條全站規則，只在鍵盤導覽時出現（:focus-visible 不會在滑鼠點擊時觸發）。 */
:focus-visible{outline:2px solid var(--c-purple-600);outline-offset:2px}

/* HEADER */
/* 一律用 #area-hdr / #area-nav 指名本站的標題列與主選單：
   全站正式 NavBar（@houseprice/shared）本身也是 <header> 且內含 <nav>，
   裸元素選擇器會連它一起套到，造成官方導覽列被塗成紫底 56px。 */
/* 麵包屑列（原本還含紫色標題塊，2026-08-17 版面重構後 H1／徽章移進結果標頭區）。
   外框刻意跟 .query-page / .feat-page 同一組尺寸（max-width:1200 + padding:20），
   左右緣才會跟頁面內容卡片切齊；改那兩個容器時這裡要一起改。 */
#area-hdr{background:transparent;max-width:1200px;margin:0 auto;padding:10px 20px 0;display:block}
/* 麵包屑：文字與層級和 BreadcrumbList 標記一致（見 useAreaPageSeo） */
/* hpsk-ui 麵包屑文字用最深的那階（--c-dark-900／--ink），不是輔助文字階
   （--ink-soft／--ink-mute）；字級對應官方 --text-xs（12px，非本站原本的
   13px）。分隔符號跟連結文字同色，一律 --ink，不吃 --ink-mute。 */
.area-breadcrumb{font-size:12px;line-height:20px;color:var(--ink);margin-bottom:8px;white-space:nowrap;overflow-x:auto}
.area-breadcrumb::-webkit-scrollbar{height:0}
.area-breadcrumb a{color:var(--ink)}
.area-breadcrumb a:hover{color:var(--c-purple-800);text-decoration:underline}
.area-breadcrumb .bc-sep{margin:0 6px;color:var(--ink)}
.area-breadcrumb [aria-current=page]{color:var(--ink)}
/* 地圖頁內距（PM 決議，2026-09 修正）：#page-map 本身在每個寬度都比照
   .query-page／.feat-page（其他三頁的容器）與 #area-hdr／.nav-inner 同值內縮，
   不再有「桌機滿版、只有麵包屑/分頁列內縮」的落差——見下方 #page-map 基本規則
   （≥701px：20px）與 @media(max-width:700px) 的 #page-map.active（12px），
   三者在任何寬度都對齊。
   body.tab-map 由 app.js goTab() 掛。 */
/* 13px 不在官方字級 8 階（12/14/16/18/20/24/30/36），改用最接近的 --text-sm(14px)。 */
.data-badge{font-size:14px;color:var(--ink-soft);white-space:nowrap}
.data-badge .db-period{margin-left:2px}
@media(max-width:700px){.data-badge .db-prefix,.data-badge .db-period{display:none}}
#h-city{background:rgba(255,255,255,.15);border:1px solid rgba(255,255,255,.3);color:var(--white);border-radius:6px;padding:5px 10px;font-size:16px;cursor:pointer;min-width:100px}
#h-city option{color:var(--ink);background:var(--white)}

/* NAV */
/* 膠囊分頁：平常在內容區（透明底），捲過原位置才吸頂並補底色與陰影。
   .is-stuck 由 AppNav.vue 以捲動監聽切換（該環境下 IntersectionObserver 不回報）。 */
#area-nav{position:sticky;top:0;z-index:100;background:transparent;padding:2px 0 10px}
#area-nav.is-stuck{background:var(--bg);box-shadow:var(--shadow-md);padding-top:10px}
.nav-inner{max-width:1200px;margin:0 auto;padding:0 20px;display:flex;gap:8px;overflow-x:auto}
.nav-inner::-webkit-scrollbar{height:0}
/* hpsk-ui 稽核發現原本的膠囊造型（rounded-full + 外框）視覺上等同官方的
   「篩選 chip」（.tag-filter），語意不合——這四個是真正的分頁級導覽，不是篩選器。
   改採 buy.houseprice.tw 正式站分頁列的「資料夾頁籤」造型：只有上緣圓角、無外框、
   同一份樣式套用所有尺寸（只有 padding/字級隨斷點縮放，形狀/顏色不變）。 */
.nt{padding:10px 24px;font-size:16px;font-weight:400;line-height:1.4;white-space:nowrap;border-radius:6px 6px 0 0;background:#F8F7F5;color:var(--ink);cursor:pointer;text-decoration:none;transition:background .2s,color .2s;flex:0 0 auto}
.nt:hover{background:var(--c-purple-100);color:var(--c-purple-800)}
.nt.active{background:var(--c-purple-800);color:var(--white)}
.nt.active:hover{background:var(--c-purple-800)}
/* Back to top */
/* 陰影改連官方陰影量表 --shadow-lg（f894c4e 那次「剩餘一次性 box-shadow」清理
   漏掉的其中一處），不再自己寫死模糊/位移/透明度。 */
#back-to-top{position:fixed;bottom:24px;right:20px;z-index:600;width:44px;height:44px;border-radius:50%;background:var(--c-brown-600);color:var(--white);border:none;cursor:pointer;box-shadow:var(--shadow-lg);display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .25s,transform .25s,background .2s;transform:translateY(10px)}
#back-to-top.visible{opacity:1;pointer-events:auto;transform:translateY(0)}
#back-to-top:hover{background:var(--c-purple-800);opacity:1;transform:translateY(-2px)}
#back-to-top svg{width:20px;height:20px;flex-shrink:0}
/* .nav-inner 的左右內距斷點已併入下方 @media(max-width:700px)，跟 #area-hdr／
   #page-map 同步（見該處說明）；這裡只留頁籤本身（.nt）在窄寬度縮小 padding/字級，
   跟容器內距斷點無關，不能一起搬——640px 是頁籤本身在極窄螢幕不擠爆的門檻，
   跟 700px 的「一般內距→窄內距」門檻是兩件事。 */
@media(max-width:640px){
  /* 離階字級收攏：15px 不在官方階（12/14/16/18/20/24/30/36）。桌機基準是 16px
     （line 140），這裡本來就是窄寬度刻意縮小一階，就近取整時往小的官方階靠
     （14px）才符合原意圖，不是往回退到跟桌機一樣大的 16px。 */
  .nt{padding:9px 12px;font-size:14px}
}
/* 320px 以下 4 個頁籤仍會溢出（實測值，設計已知並接受此限制）：.nav-inner 本來就
   overflow-x:auto 可滑動，這裡只加一個不擋點擊的右緣淡出漸層，提示還有內容在右邊，
   避免使用者要自己試滑才會發現第 4 個頁籤。只在會溢出的極窄寬度出現，其餘寬度不受影響。 */
@media(max-width:340px){
  #area-nav::after{content:'';position:absolute;top:0;right:12px;bottom:0;width:24px;background:linear-gradient(to right,transparent,var(--bg));pointer-events:none}
}

/* MOBILE NAV（≤768px；桌機正式 NavBar 隱藏後的替代入口，取代原本被移除的
   官方裸元件用法，互動與結構比照 hpsk-ui skill 的 mobile-nav + drawer 寫法：
   頂列非 fixed、只有展開的側拉選單／遮罩是 fixed，兩者才不會跟本站原有的
   sticky 麵包屑／膠囊分頁互搶版面。詳見 AppMobileNav.vue） */
.mnav-bar,.mnav-overlay,.mnav-drawer{display:none}
@media(max-width:768px){
  .mnav-bar{display:flex;align-items:center;justify-content:space-between;height:52px;padding:0 8px;background:var(--white);border-bottom:1px solid var(--line)}
  .mnav-hamb,.mnav-close{background:none;border:none;cursor:pointer;color:var(--ink);padding:8px;display:flex;align-items:center;justify-content:center}
  .mnav-logo img{height:24px;width:auto;display:block}
  .mnav-spacer{width:40px}
  .mnav-overlay{display:block;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;opacity:0;pointer-events:none;transition:opacity .2s}
  .mnav-overlay.open{opacity:1;pointer-events:auto}
  .mnav-drawer{display:block;position:fixed;top:0;left:0;width:80%;max-width:320px;height:100vh;background:var(--white);z-index:500;overflow-y:auto;transform:translateX(-100%);transition:transform .3s ease-in-out;box-shadow:var(--sh)}
  .mnav-drawer.open{transform:translateX(0)}
  .mnav-drawer-head{height:52px;display:flex;align-items:center;justify-content:space-between;padding:0 16px;border-bottom:1px solid var(--line)}
  .mnav-drawer-head img{height:22px;width:auto;display:block}
  .mnav-member{display:block;padding:14px 20px;font-size:16px;color:var(--ink);border-bottom:1px solid var(--line)}
  .mnav-item{border-bottom:1px solid var(--line)}
  .mnav-head{width:100%;display:flex;align-items:center;justify-content:space-between;padding:14px 20px;font-size:16px;color:var(--ink);background:var(--white);border:none;cursor:pointer;text-align:left}
  .mnav-head.open,.mnav-item.active>.mnav-head{background:var(--c-purple-800);color:var(--white)}
  .mnav-chev{transition:transform .2s;flex-shrink:0}
  .mnav-chev.open{transform:rotate(180deg)}
  /* 離階字級收攏：15px 不在官方階。同一個抽屜裡 .mnav-head/.mnav-link/.mnav-member
     都是 16px，.mnav-sub a 是巢狀在 .mnav-head 底下的次層連結，原意圖就是要比
     父層小一號、做出層級——就近取整時選 14px（維持「比 16px 小」的層級關係），
     不選 16px（那樣會跟父層同大，層級差異就消失了）。 */
  .mnav-sub a{display:block;padding:11px 32px;font-size:14px;color:var(--ink);border-bottom:1px solid var(--line)}
  .mnav-sub a.hl{color:var(--c-purple-800)}
  .mnav-link{display:block;padding:14px 20px;font-size:16px;color:var(--ink);border-bottom:1px solid var(--line)}
  .mnav-link.active{background:var(--c-purple-800);color:var(--white)}
}
@media(min-width:769px){
  .mnav-overlay,.mnav-drawer{display:none!important}
}

/* PAGES */
.page{display:none;min-height:calc(100vh - var(--chrome));position:relative}
.page.active{display:block}
#page-map.active{display:flex}

/* MAP */
#page-map{flex-direction:row;height:calc(100vh - var(--chrome));overflow:hidden;max-width:1200px;margin:0 auto;padding-left:20px;padding-right:20px}
#the-map{flex:1;min-width:0;overflow:hidden;background:#F2F2F4;position:relative;touch-action:none}
#the-map svg{width:100%;height:100%}
#map-overlay{position:absolute;inset:0;z-index:1;touch-action:none;cursor:inherit}
.map-inset{z-index:3}
#map-sb{width:300px;flex-shrink:0;background:var(--white);border-left:1px solid var(--line);display:flex;flex-direction:column;overflow:hidden}
.mode-bar{display:flex;border-bottom:1px solid var(--line);background:var(--c-purple-50)}
.mode-btn{flex:1;padding:10px;font-size:16px;font-weight:400;color:var(--ink-soft);text-align:center;cursor:pointer;border:none;background:none;transition:background .2s,color .2s}
.mode-btn.active{background:var(--c-purple-800);color:var(--white)}
.sb-scroll{overflow-y:auto;flex:1;padding:16px}
.sb-title{font-size:16px;font-weight:700;color:var(--c-purple-900);margin-bottom:12px}
.sb-hint{color:var(--ink-soft);font-size:16px;line-height:1.6;text-align:center;padding:20px 0}
.kpi-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px}
.kpi-card{background:var(--c-surface-sunken);border:0;box-shadow:none;border-radius:var(--radius);padding:10px;text-align:center}
.kpi-val{font-size:24px;font-weight:700;color:var(--c-orange-800)}
.kpi-lab{font-size:14px;color:var(--ink-mute);margin-top:2px}
#map-legend{position:absolute;bottom:8px;right:8px;background:rgba(255,255,255,.93);border:1px solid var(--line);border-radius:8px;padding:8px 12px;min-width:260px;z-index:5;box-shadow:var(--sh)}
.legend-title{font-size:14px;font-weight:700;color:var(--ink-soft);margin-bottom:6px}
/* 5px 不在官方圓角階（2/4/6/8/12/full），改用最接近的 --radius(4px)。 */
.legend-bar{display:flex;height:10px;border-radius:4px;overflow:hidden}
.legend-bar div{flex:1}
/* 刻度與色塊一格對一格，每個數字置中在自己那格色塊底下。
   原本是 justify-content:space-between 把數字沿色帶兩端攤開，數字位置跟它代表的
   色塊差一格；改成等寬置中之後，手機版隱藏其中幾格（見 @media(max-width:900px)）
   剩下的刻度仍然自動落在對應色塊的正中央。
   2026-09-22 租賃頁月租金額改用「元」後追加修正：原本兩排都是 flex:1，藏起某幾個
   刻度後「留著的那幾個」會被 flex-grow 重新均分整條寬度，格寬跟著變寬、中心點跟著
   偏移——手動試算過，7 格隔一個藏一個剩 4 格時，兩端刻度會偏移掉原格寬的 ~5%，
   量測門檻寬鬆時肉眼看不出來，但不是「精準對齊」。改成 grid 7 個固定欄
   （repeat(7,minmax(0,1fr))，用 minmax(0,…) 是關鍵：不加的話 1fr 隱含的 auto 下限
   會被裡面文字的 min-content 撐開，欄寬又不再是精準的 1/7），每個 span 用 nth-child
   釘死自己是第幾欄——不管藏掉哪幾格、藏幾格，留著的欄「格寬與格位」永遠不變，
   單純變成空著左右鄰欄，文字量測比欄寬（見 app.js _fitLegendLabels()）決定要不要
   顯示這一格，兩者分工：對齊由 CSS 的固定欄保證，密度由 JS 依實際量到的文字寬度
   與可用格寬決定，取代原本寫死在 @media(max-width:900px) 手機斷點裡的隔一個藏一個。 */
.legend-labels{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));font-size:12px;color:var(--ink-mute);margin-top:3px}
.legend-labels span{grid-row:1;min-width:0;text-align:center;white-space:nowrap}
.legend-labels span:nth-child(1){grid-column:1}
.legend-labels span:nth-child(2){grid-column:2}
.legend-labels span:nth-child(3){grid-column:3}
.legend-labels span:nth-child(4){grid-column:4}
.legend-labels span:nth-child(5){grid-column:5}
.legend-labels span:nth-child(6){grid-column:6}
.legend-labels span:nth-child(7){grid-column:7}
.tx-list{list-style:none}
.tx-item{padding:6px 0;border-bottom:1px solid var(--line);font-size:14px;display:flex;align-items:center;gap:4px}
.tx-item:last-child{border-bottom:none}
/* 地圖側欄排行清單（.tx-item）三處共用：.tx-price／.tx-yoy 實際顯示的顏色/粗細來自
   app.js 內嵌的 child <span style="...">（橘色粗體單價、紅綠帶符號年增率），量測外層
   class 本身的 computed style 看不到——這兩個先前被回報「太安靜沒有顏色」，實測其實
   都已經有色；只有地址欄本身確實跟單價同級 16px/700，兩者權重打平、少了主從之分，
   在此把地址降半階到 600，讓橘色粗體的單價數字更明顯是這一列的主要資訊。 */
.tx-addr{color:var(--ink);font-weight:400;font-size:16px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tx-price{text-align:right;white-space:nowrap;min-width:86px;font-size:16px}
.tx-yoy{text-align:right;white-space:nowrap;min-width:58px;font-size:14px}
.city-path{stroke:var(--white);stroke-width:1.5px;vector-effect:non-scaling-stroke;cursor:pointer;transition:opacity .15s,filter .15s}
.city-path:hover,.city-path.active{opacity:.82;filter:brightness(1.06) drop-shadow(0 0 4px rgba(142,111,167,.4))}
/* hover 分界線由最上層的 .hover-outline 複製多邊形負責（app.js setHoverOutline）：
   直接在原多邊形描邊會被後畫的鄰區蓋掉半邊。sb-hover 只留透明度效果。 */
.city-path.sb-hover{opacity:.9}
/* 離島 inset 是獨立 svg 的 rect，無繪圖順序問題，保留 class 描邊當 hover 回饋 */
#inset-svg .city-path.sb-hover{stroke:#F97D03;stroke-width:2px}
.hover-outline polygon{fill:none;stroke:#F97D03;stroke-width:2px;vector-effect:non-scaling-stroke;stroke-linejoin:round;stroke-linecap:round}
.tx-item[data-city]{cursor:pointer}
.tx-item[data-city]:hover,.tx-item[data-city].sb-active{background:var(--c-purple-50);border-radius:4px}
.sb-btype-tabs{display:flex;gap:5px;margin-bottom:10px;position:sticky;top:0;background:var(--white);z-index:5;padding-bottom:6px;padding-top:2px}
.sb-btype-tab{flex:1;padding:4px 2px;font-size:14px;font-weight:400;border-radius:6px;border:1px solid var(--c-purple-800);cursor:pointer;text-align:center;background:var(--white);color:var(--c-purple-800);min-width:0;line-height:1.3;display:flex;align-items:center;justify-content:center;flex-direction:column}
.sb-btype-tab.active{background:var(--c-purple-800);color:#fff;border-color:var(--c-purple-800)}
.dist-path{stroke:var(--white);stroke-width:1.5px;stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke;cursor:pointer;transition:opacity .15s,filter .15s}
.dist-path:hover,.dist-path.active{opacity:.82;filter:brightness(1.06) drop-shadow(0 0 3px rgba(142,111,167,.4))}
.dist-path.sb-hover{opacity:.9} /* 分界線見 .hover-outline（同縣市層的繪圖順序問題） */
.tx-item[data-dist]{cursor:pointer}
.tx-item[data-dist]:hover,.tx-item[data-dist].sb-active{background:var(--c-purple-50);border-radius:4px}
.back-map-btn{position:absolute;top:8px;left:8px;z-index:10;background:var(--white);border:1px solid var(--line);border-radius:6px;padding:5px 10px;font-size:14px;font-weight:400;cursor:pointer;display:none;box-shadow:var(--sh);color:var(--c-purple-800);transition:background .2s}
.back-map-btn:hover{background:var(--c-purple-50)}

/* Inset box for outlying islands */
.map-inset{position:absolute;bottom:8px;left:8px;background:rgba(255,255,255,.9);border:1px solid var(--line);border-radius:6px;padding:6px 8px;font-size:12px;color:var(--ink-mute)}
.map-inset svg{display:block;margin-bottom:4px}
.inset-label{font-size:12px;fill:#3A3A3A;font-weight:700}

/* Mobile */
#drawer-btn{display:none;position:fixed;bottom:20px;right:20px;z-index:500;background:var(--c-purple-800);color:var(--white);border-radius:50%;width:52px;height:52px;box-shadow:var(--shadow-lg);align-items:center;justify-content:center;border:none;cursor:pointer}
#dov{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:480;opacity:0;transition:opacity .3s}
#dov.open{display:block;opacity:1}
/* 16px 不在官方圓角階（2/4/6/8/12/full），改用最接近的 --radius-xl(12px)。 */
#mdrawer{display:none;position:fixed;bottom:0;left:0;right:0;z-index:500;background:var(--white);border-radius:12px 12px 0 0;box-shadow:var(--shadow-xl);max-height:78vh;overflow-y:auto;padding:0 16px 16px;transform:translateY(110%);transition:transform .3s ease}
#mdrawer.open{transform:translateY(0)}
.drawer-hdr{position:sticky;top:0;background:var(--white);padding:10px 0 8px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line);margin-bottom:12px}
.drawer-handle{position:absolute;left:50%;top:6px;transform:translateX(-50%);width:40px;height:4px;background:var(--line);border-radius:2px}
.drawer-title{font-size:16px;font-weight:700;color:var(--c-purple-800)}
.drawer-close{background:none;border:none;font-size:18px;line-height:1;color:var(--ink-soft);cursor:pointer;padding:4px 8px;border-radius:6px}
.drawer-close:hover{background:var(--c-purple-50);color:var(--c-purple-800)}

/* QUERY PAGES */
.query-page{max-width:1200px;margin:0 auto;padding-top:0;padding-right:20px;padding-bottom:20px;padding-left:20px}
/* 陰影改連官方陰影量表 --shadow-md（f894c4e 那次「剩餘一次性 box-shadow」清理
   漏掉的其中一處），不再自己寫死模糊/位移/透明度。 */
.filter-card{background:var(--card);border-radius:var(--r);padding:14px 16px;margin-bottom:16px;box-shadow:var(--shadow-md);position:sticky;top:var(--fst,48px);z-index:98}
.filter-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:10px}
.filter-grid .fl{min-width:0}
.filter-grid input[type=number]{min-width:0;width:100%}
.results-sep{display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin:16px 0 16px;padding:10px 16px;background:var(--c-purple-50);border-radius:8px;border-left:3px solid var(--c-purple-400);font-size:16px;font-weight:700;color:var(--c-purple-800);box-shadow:var(--shadow-sm)}
/* 離階字級收攏：.64em 是相對父層字級算的，這個 class 被用在很多種不同字級的
   父層裡（24px 的 .kpi-val/.kpi-b .val、16px 的表格數字欄與長條圖數值…），同一條
   em 公式在不同父層算出來的值不可能同時都落在官方階上——24px 父層算出 15.36px
   （離階，本項要修的實測值），16px 父層算出 10.24px（低於 12px 下限、被 clamp
   夾到 12px，剛好在階上，純屬巧合）。改成固定值（拿掉 clamp，因為上下限已經
   沒有意義），取 12px＝官方字級階最小那階（--text-xs）。
   ⚠️ 取值方向是「取多數現況值」，不是「取兩端中間值」：實測買賣頁全頁 85 個
   .kpi-unit，其中 82 個父層是 16px、現況已經渲染成 12px（被 clamp 夾住），只有
   3 個大 KPI 的父層是 24px。曾改成 14px，結果是那 82 處（96%）一起變大，手機
   375px 更是每一個單位字都從 12px 變 14px——屋齡長條圖的 .hc-bar-val 父層只有
   16px，單位／數字比從 0.75 變成 0.88，「單位是弱化的輔助資訊」這個層級幾乎
   消失。取 12px 那 82 處零視覺變動，只有 3 個大 KPI 的單位從 15.36px 收到 12px，
   那 3 處父層 24–30px，12px 仍是清楚可讀的輔助字，也更符合弱化的原意圖。
   這是字級收攏的副作用處理，不是刻意放大或縮小單位字的設計決定。 */
.kpi-unit{font-size:12px;font-weight:400;color:var(--ink-soft);margin-left:.15em;white-space:nowrap}
.results-cond-tag{display:inline-block;background:var(--white);color:var(--c-purple-800);border:1px solid var(--c-purple-800);border-radius:4px;padding:1px 9px;font-size:14px;font-weight:700}
.table-toolbar{display:flex;align-items:center;gap:16px;margin-bottom:10px;flex-wrap:wrap}
/* 明細筆數與 KPI 筆數的窗口不同，這行負責說明差異；查無差異時 app.js 會清空 */
/* 明細零筆的空狀態列 */
.tbl-empty{text-align:center;color:var(--ink-mute);padding:28px 12px;font-size:14px;line-height:1.6}
/* 圖表區章節標題（AreaSectionHeading）：與 SSR 摘要區的 h2 同一級 */
.area-section-h2{font-size:18px;font-weight:700;color:var(--c-purple-900);margin:0 0 12px;line-height:1.4}
/* 離階字級收攏：17px 不在官方階，且同一批還有 .rh-title／.area-dist h2／
   .area-summary h2 三處手機 @480 也是同樣的離階 17px（分別是各頁 h1/h2 級標題
   窄螢幕縮小後的值），四處統一在這裡說一次原則，其餘三處只留一行指標。
   17 到官方階 16／18 距離相等（都差 1），純就近取整是平手；但這條規則本身
   存在的目的就是「比桌機版再縮小一階」——四處的桌機基準有 18px（本規則／
   .area-dist h2／.area-summary h2）也有 20px（.rh-title），若平手時選擇往上
   取整到 18px，其中三處會變成「窄螢幕跟桌機一樣大」，這個縮小斷點就等於沒有
   意義；往下取整到 16px 才能讓四處都維持「窄螢幕比桌機小」的原意圖，改用
   16px。 */
@media(max-width:480px){.area-section-h2{font-size:16px}}
/* 屋齡圖的母體說明：缺漏達一成才出現 */
/* 屋齡級距的樣本數標記：不足 30 筆時直接寫在數值旁 */
/* 11px 低於官方字級下限 --text-xs(12px)，是原本全站最小字，改成 12px。 */
/* 樣本數註記（「12筆」）印在數值**前面**，所以留白給右邊：.hc-bar-val 改成右對齊之後
   （見該規則註解），最後一段內容的右緣才是數字的右緣；註記若排在數字後面，有註記的
   那幾列數字會被往左推、個位數對不齊，標頭也跟著對不上。 */
.hc-bar-n{margin-right:4px;font-size:12px;font-weight:400;color:var(--ink-mute)}
.hc-bar-note{font-size:12px;color:var(--ink-mute);line-height:1.6;margin-top:8px}
/* 13px 不在官方字級 8 階，改用最接近的 --text-sm(14px)。 */
.tbl-note{font-size:14px;color:var(--ink-soft);line-height:1.5;flex:1 1 auto;min-width:180px}
/* 明細時間窗口說明的頁尾註腳版：原本在表格 toolbar 裡（.tbl-note 那份 inline 尺寸），
   移到 <AreaSummary/> 與 footer 之間後改當獨立頁尾區塊——寬度比照 .query-page/.feat-page/
   .area-summary 同一組 1200px 內容寬，不讓它孤零零貼滿版；上方一條分隔線＋留白跟摘要表
   拉開距離，字級/顏色沿用 .tbl-note 本身已經很淡，footnote 不需要再競爭版面。
   文字為空時（app.js 判斷無需說明）用 :empty 整塊收掉，不留下一條空分隔線。 */
.area-detail-note{display:block;max-width:1200px;margin:0 auto;padding:16px 20px 28px;border-top:1px solid var(--line)}
.area-detail-note:empty{display:none}
@media(max-width:480px){.area-detail-note{padding:12px 12px 20px}}
/* 異常備註圖例（§3-A 建議8，PM 拍板文案，逐字照用）：緊接在明細表／卡片＋分頁列
   之後（PageBuy.vue 的 #b-pager 後面），不像 .area-detail-note 那樣被推到頁尾
   4000+px 外。行首用跟列上同一顆 ⓘ icon（NOTE_ICON_SVG，見 app.js），文字色沿用
   .tbl-note 同一階 --ink-soft（5.74:1，比參考頁自己的 #999999／2.85:1 好，不抄
   那個未過 AA 的值）。純靜態 markup（非 JS 產生），SSR 就會輸出，爬蟲讀得到。 */
.note-legend{display:flex;align-items:flex-start;gap:6px;padding:12px 4px 4px;font-size:12px;line-height:1.6;color:var(--ink-soft)}
.note-legend-icon{flex-shrink:0;margin-top:2px;color:var(--ink-soft)}
.toolbar-title{font-size:16px;font-weight:700;color:var(--c-purple-900);display:flex;align-items:center;gap:6px;margin-right:auto}
.table-toolbar label{display:flex;align-items:center;gap:6px;font-size:16px;cursor:pointer}
.fl{display:flex;flex-direction:column;gap:2px}
.fl label{font-size:16px;font-weight:400;color:var(--ink-soft);line-height:1.4}
.fl select,.fl input{height:44px;padding:0 10px;border:1px solid var(--c-brown-600);border-radius:4px;font-size:16px;color:var(--ink);background:var(--white);transition:border-color .2s}
.fl select:hover,.fl input:hover{border-color:var(--c-purple-600)}
.fl select:focus,.fl input:focus{border-color:var(--c-purple-600)}
.btn-row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.btn{padding:8px 20px;border-radius:4px;font-size:16px;font-weight:400;cursor:pointer;transition:background .2s,color .2s;border:none}
.btn-primary{background:var(--c-purple-800);color:var(--white)}
.btn-primary:hover{background:var(--c-dark-800)}

/* KPI */
.kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;margin-bottom:20px}
.kpi-b{background:var(--card);border-radius:var(--r);padding:16px;box-shadow:var(--sh);text-align:center}
.kpi-b .val{font-size:24px;font-weight:700;color:var(--c-orange-800);font-variant-numeric:tabular-nums}
.kpi-b .lab{font-size:14px;color:var(--ink-mute);margin-top:4px}
.kpi-tag{font-size:14px;color:var(--ink-mute);margin-bottom:2px;letter-spacing:.02em}

/* Charts */
.charts-row{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:20px}
/* 2026-07-17 版位調整：圖表一行一張佔75%、右側25%菁英房仲直式版位（隨捲動黏附、上限6張） */
.charts-zone{display:grid;grid-template-columns:3fr 1fr;gap:16px;margin-bottom:20px;align-items:start}
.charts-col{min-width:0}
.charts-col .chart-card{margin-bottom:16px}
.charts-col .chart-card:last-child{margin-bottom:0}
/* sticky top 需避開置頂 header+nav（高度由 setFilterStickyTop() 寫入 --fst），否則黏附時版位頂端會被導覽列蓋住 */
.elite-side{position:sticky;top:calc(var(--fst,104px) + 12px);min-width:0}
.elite-side .elite-belt{padding:12px 12px 8px}
.elite-side .elite-belt-grid{flex-direction:column;overflow-x:visible;gap:10px}
.elite-side .elite-card{flex:none;width:100%}
.elite-side .elite-card-img{width:100%;height:auto;aspect-ratio:220/115;object-fit:cover}
/* 10px 不在官方字級階，但不受字級階約束：內容是輪播頁碼指示的「●」字元
   （app.js buildEliteBelt() 產生 <span class="on">●</span>），純裝飾用的圓點
   標記，不是要讓人讀的文字——letter-spacing:6px 拉開的也是點與點的間距，不是
   字距。判斷後維持不動。 */
.elite-dots{display:none;text-align:center;padding:6px 0 2px;letter-spacing:6px;font-size:10px;color:var(--c-purple-300)}
.elite-dots .on{color:var(--c-purple-600)}
/* 租賃頁（桌面）：圖表僅兩張、右欄若放滿6張會比左欄長很多——改為右欄高度以圖表區為準，
   廣告超出部分於版位內部捲動（2026-07-20 定案）。手機版不適用（維持單張滑動），故限定 min-width */
@media(min-width:701px){
  #page-rent .elite-side{position:relative;align-self:stretch;top:auto}
  #page-rent .elite-side .elite-belt{position:absolute;top:0;left:0;right:0;bottom:0;overflow-y:auto;overscroll-behavior:contain}
  #page-rent .elite-side .elite-belt::-webkit-scrollbar{width:5px}
  /* 3px 不在官方圓角階（2/4/6/8/12/full），改用最接近的 --radius-sm(2px)。 */
  #page-rent .elite-side .elite-belt::-webkit-scrollbar-thumb{background:var(--c-purple-200);border-radius:2px}
  #page-rent .elite-side .elite-belt::-webkit-scrollbar-track{background:transparent}
}
/* 交叉分析首次使用導覽（2026-07-17）：全屏攔截層＋聚光挖洞（box-shadow 外擴遮罩）＋說明卡 */
#fa-tour{position:fixed;inset:0;z-index:1000}
.fa-tour-hole{position:fixed;border-radius:12px;box-shadow:0 0 0 9999px rgba(24,12,40,.55);pointer-events:none}
.fa-tour-tip{position:fixed;background:#fff;border-radius:12px;box-shadow:var(--shadow-lg);padding:14px 16px;width:min(320px,calc(100vw - 16px))}
.fa-tour-step{font-size:12px;color:var(--ink-soft)}
.fa-tour-text{font-size:16px;font-weight:700;color:var(--ink);margin:4px 0 12px;line-height:1.5}
.fa-tour-btns{display:flex;justify-content:space-between;align-items:center}
.fa-tour-skip{background:none;border:none;color:var(--ink-soft);font-size:14px;cursor:pointer;padding:6px 4px}
.fa-tour-skip:hover{color:var(--ink)}
.fa-tour-next{background:var(--c-purple-800);color:#fff;border:none;border-radius:8px;padding:8px 20px;font-size:14px;font-weight:700;cursor:pointer}
.fa-tour-next:hover{background:var(--c-purple-900)}
.chart-card{background:var(--card);border-radius:var(--r);padding:16px;box-shadow:var(--sh)}
.chart-card h3{font-size:16px;font-weight:700;color:var(--ink);margin-bottom:10px}
/* HTML Charts */
.hc-bar-rows{display:flex;flex-direction:column;gap:7px}
.hc-bar-row{display:flex;align-items:center;gap:8px;cursor:default}
/* 左欄標籤不截字（2026-09-16，PM 拍板）：原本是 white-space:nowrap + text-overflow:
   ellipsis，手機 88px 欄寬會把「復興南路一段」截成「復興南路…」——而這張圖的路段名
   沒有「點進去看全名」的去處，截掉就等於資訊消失，同圖的「一段／二段」還會截成同一
   個字串。欄寬本身已改成量測內容（app.js _barLblW），正常情況一定放得下；這裡把
   截字換成換行，是給「超過上限寬度」的極端長名留的退路——那一列變高，但名字完整。
   （量測用的探針會自己覆蓋 white-space:nowrap，見 _measureBarLblW。） */
.hc-bar-lbl{font-size:16px;line-height:1.3;color:#1a1a1a;font-weight:400;text-align:right;flex-shrink:0;overflow-wrap:anywhere;min-width:0}
.hc-bar-track{flex:1;height:18px;border-radius:4px;background:var(--c-purple-50);overflow:hidden}
.hc-bar-fill{height:100%;border-radius:4px;background:var(--c-purple-600);transition:filter .15s}
.hc-bar-row:hover .hc-bar-fill{filter:brightness(1.15)}
/* text-align:right（PM 2026-09-11 拍板）：本站所有表格的數字欄都是右對齊，這一欄
   原本是靠左（沒宣告 text-align，實測 start），造成兩個問題：各列數字的個位數對不齊，
   而且上方那條欄位標頭（.hc-bar-head-v，靠欄位盒右緣對齊）實測比數字右緣多出
   32–42px（見 16-圖表批次架構審核.md M-3）。改成右對齊後，標頭右緣＝欄位盒右緣＝
   各列數字右緣，三者同一條線。
   ⚠️ 右對齊成立的前提是「數字必須是這一欄最後一段內容」——樣本數註記 .hc-bar-n
   （「12筆」）因此在 app.js 改成印在數字**前面**（見 renderAgeBar）。若日後把它移回
   數字後面，有註記的那幾列數字就會被往左推約 29px，個位數又會對不齊。 */
.hc-bar-val{font-size:16px;font-weight:400;color:#1a1a1a;width:76px;flex-shrink:0;white-space:nowrap;font-variant-numeric:tabular-nums;text-align:right}
/* 橫條圖（各屋齡單價／主要路段單價）的欄位標頭（PM 2026-09-09「軸標題」拍板）：
   這兩張圖沒有傳統 XY 軸，是「標籤欄＋橫條＋數值」的清單結構，畫不出「軸的左上角／
   右下角」，改用一條欄位標頭承擔軸標題的工作——左邊說明標籤欄在講什麼（屋齡／路段）、
   右邊 flex:1 撐滿「橫條＋數值欄」後靠右對齊。字級／顏色與 SVG 圖表的軸標題一致
   （14px、--ink-soft，走官方字級階與官方灰階），不另立樣式。
   對齊關係（2026-09-11 修正）：.hc-bar-head-v 的右緣落在「橫條＋數值欄」這一段的
   右緣，也就是 .hc-bar-val 欄位盒的右緣；數值欄改成 text-align:right 之後，數字的
   右緣才真的等於欄位盒右緣，標頭與數字這才對得上。改動前數值欄是靠左的，標頭懸在
   數字右邊 32–42px 的空白上（而註解宣稱「正好對齊」）。
   gap:8px 與 .hc-bar-row 相同，左欄寬度由 app.js 的 _axisLblW() 寫入行內樣式，跟
   各列的 .hc-bar-lbl 用同一個數字，標頭左欄與資料列左欄因此等寬。
   （注意：_axisLblW() 已不再是「四張圖繪圖區起點對齊」的共用基準，那條約定已於
   2026-09-10 全面解除，見 app.js _axisLblW/_axisPlL 的註解。） */
.hc-bar-head{display:flex;align-items:baseline;gap:8px;margin-bottom:8px}
.hc-bar-head-c{font-size:14px;color:var(--ink-soft);text-align:right;flex-shrink:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.hc-bar-head-v{font-size:14px;color:var(--ink-soft);flex:1;text-align:right;min-width:0;white-space:nowrap}
/* 提示框全站統一（sdd/ui-align-list-page/11-UIUX執行佇列.md「提示框統一成白底」，
   PM 2026-09-07 拍板）：原本黑底白字 #1a1a1a，改成參考頁 price.houseprice.tw/list/
   實測那套白底樣式——底色 --white、文字 --ink（深灰 #333）、12px/20px（PM 實測值，
   不是官方 --text-xs 的 12px/16px，這裡明寫 line-height:20px 而非套 --lh-xs）、
   左對齊（原本 white-space:normal 沒設 text-align，明寫避免依賴繼承）。
   border-radius 保留原本的 6px：本來就等於官方 --radius-md，不用改。
   邊框／陰影是本輪唯一要實機驗證的風險點：提示框會浮在地圖紫階著色區、熱力圖深色
   格、圖表紫色直條上面（參考頁沒有圖表/地圖，不會遇到這個情境）。實測 --line
   （官方 --c-dark-300 #EAEAEA，一般分隔線階）當框線，配官方 --shadow（--sh，
   已確認完全等同官方階）在地圖最深紫階（--c-purple-900 #5B3977）、熱力圖深色格、
   買賣頁四張圖表的 --c-purple-600 直條上實測邊界仍清楚可辨——白底本身跟這些深色
   背景的亮度差已經足夠大，不需要額外加深框線或陰影量表往上升階。 */
#chart-tip{display:none;position:fixed;background:var(--white);color:var(--ink);padding:4px 10px;border:1px solid var(--line);border-radius:6px;font-size:12px;font-weight:400;text-align:left;pointer-events:none;z-index:9999;white-space:normal;max-width:300px;line-height:20px;box-shadow:var(--sh)}
.hc-donut-rows{display:flex;flex-direction:column;gap:8px}
.hc-donut-row{display:flex;align-items:center;gap:8px}
.hc-donut-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
.hc-donut-lbl{font-size:12px;color:var(--ink);flex:1}
.hc-donut-pct{font-size:12px;font-weight:700;color:var(--ink);width:36px;text-align:right}
.hc-donut-cnt{font-size:12px;color:var(--ink-mute);width:36px;text-align:right}
.hc-donut-total{font-size:12px;color:var(--ink-mute);text-align:right;margin-top:6px}

/* Price check */

/* Table */
.tbl-wrap{background:var(--card);border-radius:var(--r);box-shadow:var(--sh);overflow:auto;margin-bottom:4px}
table{width:100%;border-collapse:collapse;font-size:16px;min-width:600px}
/* hpsk-ui 對標明細表參考頁（sdd/ui-align-list-page/01-UIUX評估與修正建議.md
   建議1）：表頭改用官方 --c-dark-800 深底／白字／14px／--fw-regular／置中，
   取代本站原本自創的 --c-purple-50 淺紫底／深紫字／16px／700／左對齊——後者
   視覺重量過高，且 --c-purple-50 不是官方色階（官方紫階最淺只到 100）。
   官方 guideline 目前完全沒有表格元件規範可循，這組深底白字置中是從參考頁
   逆推而得，屬非正式元件；缺件已另案提報設計團隊，補齊規範後應重新對齊。
   選擇器用 thead th（不用裸 th）：.area-dist／.area-summary 的
   th[scope=row]（行政區/縣市名列頭）在 tbody 裡，若套用同一份規則會讓它跟
   同一列的 <td> 字級對不上，重新踩到 f40d6f6 剛修好的欄名/數字字級不一致。
   數字欄仍靠 .td-num,.th-num 覆寫回右對齊（見下方），跟資料對齊，PM 已拍板
   保留（見該報告 §5 Q3）。 */
thead th{background:var(--c-dark-800);color:var(--white);padding:10px 12px;font-size:14px;font-weight:400;text-align:center;white-space:nowrap}
th.sortable{cursor:pointer;user-select:none}
/* 原本 hover 用 --c-purple-100（淺紫），深底上會反白看不見；改用 --ink（官方
   --c-dark-900）比表頭底色更深一階時，QA／架構審核實測 hover 底色 #333333 對表頭
   底色 #434343 只有 1.28:1，肉眼幾乎看不出變化（見 04-第一波架構審核.md m8、
   06-第一波QA驗收.md D2）。
   往更深走無法解：表頭本身已經很深（L=0.056），就算 hover 用純黑，跟表頭的對比
   上限也只有約 2.12:1（(0.056+0.05)/(0+0.05)），不可能到 3:1。只能往淺色走，但
   往淺走會被「hover 態白字對比不能掉到 4.5:1 以下」這條反向夾住：白字對 hover 底色
   ≥4.5:1 要求 hover 亮度 L ≤0.183，而 L=0.183 對表頭的對比上限只有約 2.20:1——
   兩個門檻在數學上互斥，選了字面 3:1 就會犧牲白字可讀性，這裡的裁決是優先保住白字
   （不能改文字色、不能加框線，見 06- D2 的「維持既有視覺語彙」要求），非文字對比
   取這個夾角下可達到的最大值，未達 3:1 字面門檻，已知悉並記錄，供 PM 裁決是否
   要接受這個上限或改走別的視覺語彙。
   官方 --c-dark-600(#8C8C8C)／--c-dark-700(#666666) 兩階都不落在這個可行區間內
   （600 太淺讓白字掉到 3.36:1；700 太深，對表頭僅 1.72:1，回到原問題），中間又
   沒有官方階可用，比照本檔 --c-purple-50 的既有慣例，用 color-mix 從
   --c-dark-800 與白色推導一個居間值：26% 白混 --c-dark-800，實測 hover 底色
   對表頭 ≈2.12:1（無框線/無改字色前提下數學可達的上限）、白字對 hover 底色
   ≈4.67:1（仍守住 WCAG AA 4.5:1）。 */
/* PM 拍板（第一波最後一項）：上面這個 hover 底色（2.11:1）已經是數學上可行的
   上限——要維持 hover 態白字 ≥4.5:1，hover 底色對表頭的對比上限只有約 2.20:1；
   往更深走上限也只有約 2.12:1，兩條門檻互斥，繼續調底色到不了 3:1 字面門檻。
   改用白色下底線當輔助指示：白色對表頭底色 #434343 是 9.89:1，遠高於改色前
   1.28:1 時代肉眼看不出變化的問題，一眼可辨；跟 hover 底色疊加而非取代。
   用 box-shadow（inset）而非 border-bottom／text-decoration：box-shadow 不佔
   版面盒模型空間，hover 前後 thead／th 的高度實測完全不變，不會推擠文字或
   造成版面跳動。只加在 th.sortable，不可排序欄位 hover 不受影響；跟既有
   ▲/▼（::after）各自佔用不同視覺區域，互不影響、可共存。 */
th.sortable:hover{background:color-mix(in srgb, var(--white) 26%, var(--c-dark-800));box-shadow:inset 0 -2px 0 var(--white)}
th.sort-asc::after{content:' ▲';font-size:12px;opacity:.7}
th.sort-desc::after{content:' ▼';font-size:12px;opacity:.7}
/* Pager */
.pager{display:flex;align-items:center;gap:4px;padding:10px 12px;flex-wrap:wrap}
.pager button{padding:4px 10px;border:1px solid var(--line);border-radius:4px;background:var(--white);cursor:pointer;font-size:14px;color:var(--ink)}
.pager button:hover:not(:disabled){background:var(--c-purple-50)}
.pager button.active{background:var(--c-purple-800);color:var(--white);border-color:var(--c-purple-800)}
.pager button:disabled{opacity:.4;cursor:default}
.pager-info{font-size:14px;color:var(--ink-soft);margin-left:8px}
/* Mobile sort bar */
.mob-sort-bar{display:flex;align-items:center;gap:8px;padding:8px 10px;background:var(--card);border-radius:8px;margin-bottom:8px;box-shadow:var(--sh)}
.mob-sort-lbl{font-size:14px;color:var(--ink-soft);white-space:nowrap;flex-shrink:0}
.mob-sort-sel{flex:1;min-width:0;padding:5px 8px;border:1px solid var(--line);border-radius:6px;font-size:16px;background:var(--white);color:var(--ink);font-family:var(--ff)}
.mob-sort-dir{flex-shrink:0;padding:5px 10px;border:1px solid var(--line);border-radius:6px;background:var(--white);font-size:16px;color:var(--c-purple-800);cursor:pointer}
.mob-sort-dir:hover{background:var(--c-purple-50)}
/* Mobile buy cards */
/* 10px 不在官方圓角階（2/4/6/8/12/full），卡片類改用最接近的 --radius-lg(8px)。 */
.buy-card{background:var(--card);border-radius:8px;box-shadow:var(--sh);padding:12px 14px;margin-bottom:8px}
/* 異常備註三層收斂（§3-A，PM 拍板）：opacity:.8 整卡淡化拿掉——對「命中一個
   關鍵字」這種粗糙判斷做負面歸因不成比例，且淡化不分是 is1f 還是 isspec 觸發，
   一併拿掉不特別區分。左邊框原本保留作為中性列級提示，但架構審核（12-備註與
   提示框架構審核.md m-1）指出桌機的列級標記（tr.row-flagged td 的 opacity）
   已經整個拿掉，手機卡片卻還留這條紫色邊框，兩個斷點不一致——PM 拍板兩邊一致，
   拿掉。row-flagged class 仍保留在 JS 輸出（is1f||isspec 都會掛），只是目前
   兩個斷點都沒有對應的視覺效果，供之後有需要時掛其他中性提示用。故本規則
   直接移除，不留空殼 ruleset。 */
.bc-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:3px}
.bc-date{font-size:14px;color:var(--ink-soft);font-weight:400}
.bc-tags{display:flex;gap:4px;flex-shrink:0;align-items:center}
/* 型態改純文字（sdd/ui-align-list-page/11-UIUX執行佇列.md「型態改純文字」，
   PM 2026-09-07 拍板，只改外觀不動內容）：手機卡片的型態原本也是彩色徽章
   （紫底紫字），跟桌機表格「型態」欄同一顆 bbadge() 產生的邏輯是分開的兩份樣式，
   這裡單獨處理。比照參考頁改普通文字——大小/粗細/顏色跟同一列的 .bc-date
   （14px/400/--ink-soft）一致，不再有底色/框線/圓角/粗體跟旁邊搶注意力。
   保留 span 只是因為它跟 .bc-rtag 共用 .bc-tags 這個 flex 容器需要
   一個可獨立換行/量測的節點，不是要維持「標籤」語意。 */
.bc-btype{font-size:14px;font-weight:400;color:var(--ink-soft)}
/* 以下兩個標籤/badge 的 border-radius:3px 不在官方圓角階，統一改
   --radius-sm(2px)（標籤/badge 用階，見建議15）。 */
.bc-addr{font-size:14px;color:var(--ink);margin-bottom:6px;line-height:1.4;word-break:break-all}
.bc-price{font-size:16px;font-weight:700;color:var(--c-dark-900);margin-bottom:3px;font-variant-numeric:tabular-nums}
.bc-lbl{font-size:14px;font-weight:400;color:var(--ink);vertical-align:baseline}
.bc-meta{font-size:14px;color:var(--ink-soft);line-height:1.6}
.buy-cards-wrap{padding:0 0 4px}
/* 交易標記現況（PM 2026-10-05 決定）：特殊交易在地址下方一行顯示靜態小標「特殊交易」
   （.tx-label，官方 Label 灰款）＋政府備註 ⓘ（.tx-flags 同一行）；1 樓／地下不再用標籤，
   改由樓層欄呈現（「1/總樓層」、地下顯示「地下」）。舊的 .tag-1f、.tag-spec、.td-spec-note 皆已移除。 */
.tx-flags{display:flex;align-items:center;gap:4px;margin-top:4px}
.tx-flags .note-icon{margin-left:0}
/* 特殊交易小標：官方 Label 中性灰款（.label.label-s.label-grey 同值：--c-dark-200 底、--c-dark-800 字、
   高 22px、左右 8px、圓角 2px、14px）；純靜態文字，不可點。 */
.tx-label{display:inline-flex;align-items:center;height:calc(1em + 8px);padding:0 8px;border-radius:2px;font-size:14px;line-height:1;white-space:nowrap;background:var(--bg);color:var(--c-dark-800)}
.buy-card .tx-flags{margin:-2px 0 6px}
/* 價格欄（PM 2026-10-05 刻意偏離 hpsk-ui 規範「≤18px 小字價格用黑字」的例外，請勿「修正」回黑字）：
   只套用在買賣／租賃桌機明細表的單價、總價（月租）欄（.td-price）與手機成交卡價格數字（.bc-pv，
   含交叉分析頁下鑽明細）。地圖側欄排行、物件推薦卡維持黑字。格內只放數字（單位在表頭），
   靠右、等寬數字。 */
.td-price{color:var(--c-orange-800);font-weight:700;font-variant-numeric:tabular-nums;text-align:right}
.bc-pv{color:var(--c-orange-800);font-weight:700;font-variant-numeric:tabular-nums}
.bc-rtag{font-size:14px;font-weight:700;border-radius:2px;padding:1px 5px;background:var(--c-purple-50);color:var(--c-purple-800);margin-left:3px}
/* 租賃手機卡／明細的「社宅」標籤：官方綠色系淡底（--c-green-700 10%）＋文字用 --c-green-800，
   不再是跟本站色盤無關的 Material Design 綠 */
.bc-social{font-size:14px;font-weight:700;border-radius:2px;padding:1px 5px;background:color-mix(in srgb, var(--c-green-700) var(--opacity-10), var(--white));color:var(--c-green-800);margin-left:3px}
/* 整列/整卡 opacity 淡化已拿掉（見下方 .buy-card.row-flagged 與此處），理由同上：
   對一個關鍵字命中做負面歸因不成比例。row-flagged class 本身留著（is1f||isspec
   都會掛），只是不再有視覺效果，供之後有需要時掛其他中性提示用。 */
/* 備註 ⓘ icon：原本是 .note-badge（紫底紫框粗體「備」字，22×16px，<span onclick>
   鍵盤走不到），異常備註三層收斂（§3-A，PM 拍板）改成低調的 info icon 按鈕：
   - 視覺維持小尺寸（不佔版面、不搶戲），觸控/點擊熱區用 ::after 擴大，不改變
     icon 本身大小、不影響列高
   - 顏色用 --ink-soft（#666666，對白底 5.74:1，同時滿足文字 WCAG AA 4.5:1
     與圖像 WCAG 1.4.11 非文字對比 3:1 兩種門檻）
   - <button type=button>：原生可 Tab 聚焦、Enter/Space 觸發，配合全站既有
     :focus-visible 規則（styles.css 開頭 :root 後那條）即可看到聚焦框，
     不需要另外做鍵盤事件或聚焦樣式
   熱區尺寸修正（架構審核 Blocker B-1，12-備註與提示框架構審核.md）：原本熱區
   44×44px 是套 PM 當初「熱區 ≥44×44」的規格（WCAG 2.5.5 AAA 級觸控下限），但
   明細表單行列高實測只有 33.77px，44 > 33.77，熱區必然上下溢出到相鄰列；橫向
   也因為 22px 半徑扣掉 icon 與價格數字間 4px 的 margin 後仍吃掉價格文字約
   10px。實機驗證出的具體後果：桌機滑到單價數字/相鄰列會跳出備註提示框，手機
   點地址會跳出備註視窗。PM 當初要求的尺寸這個列高裝不下，是規格錯，不是做錯，
   這裡改成不超出所在列/儲存格的尺寸——WCAG 2.5.8（AA，2.2）的目標尺寸下限是
   24×24，桌機列高 33+px、手機 .bc-price 該行高度都容得下 24×24 且左右也不會
   吃到旁邊內容（22px 半徑會咬到 4px margin 外的價格文字，12px 半徑不會），改用
   24×24。 */
.note-icon{position:relative;display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;margin-left:4px;border:none;background:none;color:var(--ink-soft);cursor:pointer;vertical-align:middle;flex-shrink:0;line-height:0}
.note-icon::after{content:'';position:absolute;top:50%;left:50%;width:24px;height:24px;transform:translate(-50%,-50%)}
.note-icon:hover{color:var(--c-purple-800)}
/* 手機：ⓘ 可點範圍 44×36（按鈕本身放大；圖示視覺仍 16px）。
   位置在卡片左側地址下方，不會被右下角浮動「回頂端」按鈕遮住。 */
@media(max-width:639px){
  /* 點擊框 44×36：垂直方向不侵入相鄰的地址行／價格行（由該行 min-height 容納），
     水平往左右延伸但左側只蓋到「特殊交易」小標自己的內距，不碰任何文字。 */
  .tx-flags:has(.note-icon){min-height:36px}
  .tx-flags .note-icon{width:44px;height:36px;margin:0 -12px 0 -8px}
  .tx-flags .note-icon::after{display:none}
}
.note-lb{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:9990;align-items:center;justify-content:center;padding:20px}
.note-lb-box{background:var(--white);border-radius:12px;padding:20px;max-width:360px;width:100%;box-shadow:var(--shadow-2xl)}
.note-lb-title{font-size:16px;font-weight:700;color:var(--ink);margin-bottom:10px}
.note-lb-text{font-size:16px;line-height:1.8;color:var(--ink);margin-bottom:16px;word-break:break-all}
.note-lb-close{display:block;width:100%;padding:10px;background:var(--c-purple-800);color:#fff;border:none;border-radius:8px;font-size:16px;font-weight:400;cursor:pointer}
/* ── Listings (external API) ── */
.listings-section{margin:20px 0;background:var(--card);border-radius:var(--r);box-shadow:var(--sh);padding:16px}
.listings-hdr{display:flex;align-items:center;gap:10px;margin:0 0 14px}
.listings-icon{width:20px;height:20px;color:var(--c-purple-600);flex-shrink:0}
.listings-hdr-text{display:flex;flex-direction:column;gap:1px}
.listings-title-main{font-size:18px;font-weight:700;color:var(--c-purple-900);line-height:1.3}
.listings-title-sub{font-size:14px;color:var(--ink-soft);line-height:1.3}
.chart-sub{font-size:14px;color:var(--ink-soft);line-height:1.4;margin:2px 0 6px;min-height:1em}
.listings-grid{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;gap:14px;padding-bottom:10px;-webkit-overflow-scrolling:touch}
.listings-grid::-webkit-scrollbar{height:5px}
.listings-grid::-webkit-scrollbar-track{background:transparent}
/* 3px/10px 都不在官方圓角階，分別改用 --radius-sm(2px)（捲軸拇指）與
   --radius-lg(8px)（卡片）。 */
.listings-grid::-webkit-scrollbar-thumb{background:var(--line);border-radius:2px}
.listing-card{flex:0 0 calc(25% - 11px);min-width:200px;max-width:280px;scroll-snap-align:start;display:flex;flex-direction:column;background:var(--white);border:1px solid var(--line);border-radius:8px;overflow:hidden;text-decoration:none;color:inherit;transition:box-shadow .15s,transform .15s}
.listing-card:hover{box-shadow:var(--shadow-md);transform:translateY(-2px)}
.listing-img{position:relative;width:100%;aspect-ratio:16/9;background:#eee;overflow:hidden;flex-shrink:0}
.listing-img img{width:100%;height:100%;object-fit:cover;display:block}
.listing-no-img{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:12px;color:#aaa}
.listing-img-tag{position:absolute;bottom:6px;left:6px;background:rgba(0,0,0,.62);color:#fff;font-size:12px;font-weight:700;padding:3px 8px;border-radius:4px;white-space:nowrap;max-width:calc(100% - 12px);overflow:hidden;text-overflow:ellipsis}
.listing-hot{position:absolute;top:6px;right:6px;background:rgba(125,79,160,.92);color:#fff;font-size:12px;font-weight:700;padding:3px 8px;border-radius:12px;white-space:nowrap;max-width:calc(100% - 12px);overflow:hidden;text-overflow:ellipsis}
.listing-body{padding:10px 12px;flex:1;display:flex;flex-direction:column;gap:3px;text-align:left}
.listing-name{font-size:16px;font-weight:700;color:var(--ink);line-height:1.4;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.listing-addr{font-size:14px;color:var(--ink-soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.listing-comm{font-size:14px;color:var(--c-purple-800);font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:1.4em}
.listing-price{font-size:16px;font-weight:700;color:var(--c-dark-900);margin-top:4px}
.listing-unit{font-size:14px;font-weight:400;color:var(--ink-soft)}
.listing-meta{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px;min-height:24px}
.listing-meta span{font-size:14px;color:var(--ink-soft);background:var(--bg);padding:2px 7px;border-radius:4px}
.listings-carousel{position:relative;display:flex;align-items:center;gap:6px}
/* 22px 不在官方字級階，但判斷後不受字級階約束：按鈕內容是 &#8249;/&#8250;
   （‹/›）單一符號字元當方向圖示用（見 app/components/area/PageBuy.vue／
   PageFeature.vue 的 carousel-prev/-next），可及性名稱另外靠 aria-label="往前"/
   "往後" 提供，不靠這個字元本身被讀出來——跟 .elite-dots 同一類：字級在這裡是
   在調圖示大小，不是在排版可讀文字，判斷後維持不動。 */
.carousel-btn{flex-shrink:0;width:36px;height:36px;border-radius:50%;border:1px solid var(--line);background:var(--white);color:var(--ink);font-size:22px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:var(--sh);transition:background .15s,opacity .15s;padding:0;margin:0}
.carousel-btn:hover{background:var(--c-purple-50)}
.carousel-btn:disabled{opacity:.3;cursor:default}
.listings-cta{display:flex;justify-content:center;margin-top:16px}
.listings-msg{padding:20px;text-align:center;color:var(--ink-soft);font-size:16px}

/* ── 菁英房仲 banner 腰帶（實驗性版位，非正式 UI KIT 規範） ── */
.elite-belt{position:relative;margin-bottom:20px;background:var(--card);border-radius:var(--r);box-shadow:var(--sh);padding:16px 16px 14px}
.elite-belt-tag{display:inline-flex;align-items:center;gap:6px;background:var(--c-purple-800);color:var(--white);font-size:16px;font-weight:700;padding:5px 12px;border-radius:6px;margin-bottom:12px}
.elite-belt-grid{display:flex;gap:14px;overflow-x:auto;-webkit-overflow-scrolling:touch}
.elite-card{flex:0 0 220px;display:flex;flex-direction:column;border:1px solid var(--line);border-radius:8px;overflow:hidden;text-decoration:none;color:inherit}
.elite-card-img{width:220px;height:115px;display:block;object-fit:cover}
.elite-card-body{padding:8px 10px}
.elite-card-name{font-size:16px;font-weight:700;color:var(--ink)}
.elite-card-brand{font-size:14px;color:var(--ink-soft)}
/* 列分隔線由 --line（官方 --c-dark-300，對白底 1.20:1）升到 --c-dark-400
   （對白底 1.47:1）：密集表格中原本的線幾乎看不見列邊界，PM 拍板選項 A
   （sdd/ui-align-list-page/01-UIUX評估與修正建議.md §5 Q4），不加斑馬紋。 */
td{padding:8px 12px;border-bottom:1px solid var(--c-dark-400);vertical-align:middle}
tr:last-child td{border-bottom:none}
tr:hover td{background:var(--c-purple-50)}
.td-addr{max-width:220px}
.td-btype{width:1%;white-space:nowrap;text-align:center}
/* 買賣/租賃/特徵分析明細表的數字欄（單價／總價／坪數／屋齡／車位…）：th 預設
   text-align:left、td 沒設對齊會吃瀏覽器預設 left，數字靠左讀起來不直覺，也跟
   千位數/小數對不齊。app.js 產生對應 <td>/<th> 時加這個 class。
   此處刻意偏離對標參考頁（該頁數字欄一律置中）：本站表格的核心用途是同一欄
   數字互相比價，右對齊比置中更利於一眼比大小，PM 已拍板保留（見
   sdd/ui-align-list-page/01-UIUX評估與修正建議.md §5 Q3）。font-variant-numeric:
   tabular-nums 讓等寬數字對齊千分位/小數點，右對齊的效果才不會被比例字寬抵銷。
   此偏離已另案提交設計團隊裁決，若規範另有決定則照改。 */
.td-num,.th-num{text-align:right;font-variant-numeric:tabular-nums}
/* 型態改純文字（sdd/ui-align-list-page/11-UIUX執行佇列.md「型態改純文字」，PM
   2026-09-07 拍板，只改外觀不動內容）：桌機表格「型態」欄原本是 bbadge() 產生的
   彩色徽章（大樓/華廈/公寓/其他各一色，.badge + .badge-tower/-mansion/-apt/-other），
   跟旁邊的價格搶注意力。比照參考頁改純文字，字級/粗細/顏色直接吃表格本身
   （thead/td 預設 16px/400/--ink，.td-btype 已有 text-align:center 負責置中），
   不需要再包一層 class——bbadge() 現在只回傳 escHtml(btype) 純文字，不再輸出
   <span>，這四條 .badge/.badge-tower 系規則因此沒有呼叫端，一併刪除（已 grep 全站
   確認 app/ 與 public/app.js 沒有其他地方掛 class="badge"）。 */

/* FEATURE */
.feat-page{max-width:1200px;margin:0 auto;padding-top:0;padding-right:20px;padding-bottom:20px;padding-left:20px}
.hm-wrap{background:var(--card);border-radius:var(--r);padding:16px 16px 14px;box-shadow:var(--sh);overflow-x:auto;margin-bottom:16px}
#hm-title{font-size:18px;font-weight:700;line-height:1.35;margin-bottom:4px;color:var(--c-purple-900)}
.hm-desc{font-size:14px;line-height:1.6;color:var(--ink-soft);margin-bottom:12px}
.hm-hdr{display:flex;justify-content:space-between;align-items:flex-start;gap:8px 16px;flex-wrap:wrap}
.hm-legend{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--ink);margin-top:3px;flex-shrink:0;white-space:nowrap}
.hm-legend-cap{color:var(--ink-soft);margin-right:-2px}
/* 跟 .legend-bar（地圖圖例）同款漸層條，5px 同樣不在官方圓角階，改 --radius(4px)。 */
.hm-legend-bar{width:110px;height:10px;border-radius:4px;border:1px solid var(--line);display:inline-block}
@keyframes hm-pulse{0%,100%{outline:3px solid transparent;outline-offset:0}50%{outline:3px solid var(--c-purple-600);outline-offset:3px}}
/* 動畫 0%/100% 原本用 --c-purple-300——該 token 校正成官方值後是高彩度亮紫
   （官方文件明講「只給漸層用」），動畫跑 4 次期間有一半時間框線是這個顏色，
   改用 --c-purple-200（同一批校正過的柔和淺紫階）。光暈原本寫死
   rgba(133,87,168,.15)，改用 color-mix 搭配官方透明度階（--opacity-20）。 */
@keyframes hm-notice-pulse{0%,100%{border-color:var(--c-purple-200)}50%{border-color:var(--c-purple-600);box-shadow:0 0 0 3px color-mix(in srgb, var(--c-purple-700) var(--opacity-20), transparent)}}
/* border:1.5px 不在官方框線階（0/1/2/4/8），改用 2px（--border-2，區塊強調用框線）。 */
.hm-click-hint{display:flex;align-items:center;gap:8px;font-size:16px;font-weight:700;color:var(--c-purple-900);background:var(--c-purple-100);border:2px solid var(--c-purple-600);border-radius:8px;padding:7px 14px;margin-bottom:12px;animation:hm-notice-pulse 1.8s ease-in-out 4;cursor:default}
.hm-click-hint svg{flex-shrink:0;color:var(--c-purple-600)}
table.hm{border-collapse:separate;border-spacing:4px;min-width:400px}
/* 這是「座標軸標籤」（X 軸/Y 軸，標示比的是哪個行政區/建物型態），不是「表頭」
   （欄位名稱）——第一波把五張表的表頭統一成深色時，這裡被一起套了深底白字，
   結果變成一排一排深灰色圓角方塊夾住中間的彩色資料格，視覺重量壓過資料本身。
   原則（寫下來避免以後有人看到「表頭沒統一」又改回去）：清單型表格（明細表、
   行政區比較表、全台總覽表）用深色表頭，因為那是欄位名稱、需要宣告「這是標題
   列」；矩陣型（熱力圖）的軸標要「比資料弱、但仍然是一個區塊」——弱化的是它的
   視覺重量，不是它的存在。這是兩種性質不同的表格，不是漏統一。
   ⚠️ 這條原則先前寫成「安靜軸標」，被理解成「拿掉底色」，於是在深底白字↔完全
   透明底之間擺盪了兩輪：透明底在白底的 .hm-wrap 上等於沒有處理，軸標變成漂在
   border-spacing:4px 的格線縫隙之間的裸文字，跟它要標示的資料格失去視覺歸屬。
   現在的做法（PM 2026-09-08 看示意圖後拍板）：底色用官方灰階最淺那階
   var(--bg)（#F1F1F1，本站頁面底色，等同官方 --c-dark-200），文字維持
   --ink-soft（#666666，官方輔助文字階，對這個底色 5.08:1），border-radius:6px
   跟資料格同值。讀起來是「一條安靜的帶」：比彩色資料格弱，但仍然是一個區塊。
   字級維持 14px（比資料格的 16px/700 小一階）。
   background 必須明寫、不能只是「不宣告 background」：X 軸標籤在 <thead> 裡，
   不宣告就會落回上面那條 `thead th{background:var(--c-dark-800)}`（全站清單型表頭
   的深底白字）——這條 `table.hm th` 雖然特異度較高、贏得了 color，但沒宣告
   background 就管不到底色，結果是 #666666 深灰字印在 #434343 深灰底上，對比只有
   1.72:1，軸標幾乎看不見（比改動前的深底白字更糟，實測踩過）。 */
table.hm th{background:var(--bg);color:var(--ink-soft);padding:8px 12px;font-size:14px;font-weight:400;border-radius:6px;white-space:nowrap;text-align:center}
/* 左上角改留空的樞紐表角格（見 app.js buildHeatmap()）：它是個純 <td>，會落回吃到
   下面 table.hm td 給資料格用的 cursor:pointer／hover outline，看起來像可點的儲存格
   但點了沒作用；用 pointer-events:none 讓滑鼠事件穿透，不觸發 hover／cursor 變化。 */
table.hm thead td{pointer-events:none}
/* border-bottom:none 蓋掉全站通用 td 規則（見上方裸 td 說明）的 1px 分隔線：table.hm
   是 border-collapse:separate + border-spacing:4px 的獨立圓角色塊，不是列表分隔用途，
   不該有這條線；分隔線加深到 --c-dark-400 後，這條線滲在色塊底緣更明顯（QA D1）。 */
table.hm td{text-align:center;cursor:pointer;border-radius:6px;font-size:16px;font-weight:700;transition:opacity .15s,outline .1s;min-width:70px;padding:10px 8px;font-variant-numeric:tabular-nums;border-bottom:none}
table.hm td:hover{opacity:.85;outline:2px solid var(--c-purple-600)}
table.hm td.hm-hint{animation:hm-pulse 1.2s ease-in-out 5}
table.hm td.selected{outline:3px solid var(--c-purple-600)!important;outline-offset:1px}
.hm-hint-label{display:block;font-size:12px;font-weight:500;opacity:.8;margin-top:3px;pointer-events:none}
.hm-n{font-size:12px;font-weight:400;opacity:.75;display:block}
#fa-detail-panel{margin-bottom:20px;scroll-margin-top:60px}
#fa-tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.fa-detail{background:var(--card);border-radius:var(--r);box-shadow:var(--sh);overflow:hidden}
.fa-detail-hdr{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:14px 20px;background:var(--c-purple-800);color:var(--white)}
.fa-detail-hdr-title{font-size:16px;font-weight:700;line-height:1.4}
.fa-detail-hdr-n{font-size:14px;opacity:.8;margin-top:3px;font-weight:400}
.fa-detail-body{padding:20px}
.close-btn{background:rgba(255,255,255,.15);border:none;color:var(--white);font-size:16px;cursor:pointer;padding:6px 12px;border-radius:6px;font-weight:400;flex-shrink:0;white-space:nowrap;line-height:1.4}
.close-btn:hover{background:rgba(255,255,255,.3)}
.fa-insight{font-size:16px;line-height:1.8;background:var(--c-purple-50);padding:13px 16px;border-radius:8px;margin-bottom:16px;border-left:3px solid var(--c-purple-600);color:var(--ink)}
.fa-kpi-4{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:16px}
.fa-kpi-card{background:var(--c-surface-sunken);border:0;box-shadow:none;border-radius:var(--radius);padding:12px;text-align:center}
.fa-kpi-val{font-size:24px;font-weight:700;color:var(--c-orange-800);line-height:1.2;font-variant-numeric:tabular-nums}
.fa-kpi-lab{font-size:14px;color:var(--ink-soft);margin-top:3px}
.fa-kpi-cmp{font-size:14px;font-weight:400;margin-top:3px}
.fa-charts-row{display:grid;grid-template-columns:1fr 240px;gap:16px;margin-bottom:16px}
.fa-tx-hdr{font-weight:700;font-size:16px;margin:4px 0 8px;padding-top:16px;border-top:1px solid var(--line);display:flex;align-items:center;flex-wrap:wrap;gap:8px}
.fa-filter-row{display:inline-flex;gap:12px;align-items:center;flex-wrap:wrap}
.fa-filter-chk{font-size:14px;color:var(--ink-soft);cursor:pointer;display:inline-flex;align-items:center;gap:2px;font-weight:400}

.rcheck-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-bottom:12px}

/* RWD */
@media(max-width:900px){
  /* 左右內距沿用 #page-map 基本規則的 20px（跟同寬度下 #area-hdr／.nav-inner
     一致），這裡只改直排；@media(max-width:700px) 再往下收到 12px，同步收。 */
  #page-map.active{flex-direction:column;overflow:hidden}
  #map-sb{display:contents}
  #sb-body{display:none!important}
  .mode-bar{order:-1;flex-shrink:0;border-bottom:1px solid var(--line)}
  #the-map{order:0;flex:0 0 auto;background:var(--white)}
  /* 圖例移到地圖下方（PM 2026-09-14 拍板 A'）。原本是 position:fixed 釘在視窗上、
     浮在地圖之上（z-index:5），320px 把屏東縣標籤整張蓋掉（實測 48×28 全部落在圖例
     方框內、遮蔽率 100%），375px 也遮掉 79%——圖例是靜態說明，沒有理由壓在地圖上。
     做法：#the-map 用 padding-bottom 讓出一條橫幅（border-box：SVG 的內容高度會自動
     少掉這段），圖例絕對定位填進那條空白，視覺上就在地圖下方、跟任何標籤都不會重疊。
     這個保留高度 app.js 的 _mapLegendReserve() 會讀同一個值回去調整地圖高度，改這裡
     的數字兩邊會自動一致（它是量 offsetHeight，不是各寫一份）。 */
  :root{--map-legend-h:40px}
  #the-map{padding-bottom:var(--map-legend-h)}
  /* 地圖手勢區（拖曳/縮放）不要蓋到圖例橫幅 */
  #map-overlay{inset:0 0 var(--map-legend-h) 0}
  /* 離島小圖的 bottom 是從 padding box 量的，要往上讓開圖例那條橫幅 */
  .map-inset{bottom:calc(var(--map-legend-h) + 8px)}
  #map-legend{position:absolute;top:auto;left:0;right:0;bottom:0;height:var(--map-legend-h);min-width:0;
    display:grid;grid-template-columns:auto 1fr;column-gap:8px;align-items:center;
    padding:4px 12px;background:var(--white);border-width:1px 0 0;border-radius:0;box-shadow:none}
  /* 右側留白給浮動的「看行情」圓鈕（#drawer-btn：fixed、52px、right:20px）。它釘在
     視窗上、圖例釘在地圖底部，兩者的垂直距離會隨視窗高度變（375 剛好貼齊、414 差 22px），
     所以沒有一個固定的上下位移能永遠閃開；改成橫向讓開——圓鈕佔右起 72px，圖例本身已
     內縮 12px，這裡再留 60px 加一點餘裕，色帶與刻度就不可能被蓋到。 */
  body.tab-map #map-legend{padding-right:72px}
  .legend-title{grid-column:1;grid-row:1/3;align-self:center;margin:0;font-size:12px}
  .legend-bar{grid-column:2;grid-row:1;align-self:end;height:8px}
  .legend-labels{grid-column:2;grid-row:2;margin-top:2px;font-size:11px}
  /* 2026-09-22 前這裡原本寫死「隱藏第 2/4/6 格」，只在手機斷點生效：租賃頁月租
     金額改用「元」之後，桌機 900~1300px（這個 media query 之外）沒有這層保護，
     刻度數字（6,000/8,000/…/16,000+）比格寬還寬，會黏字（<6,0006,000）。改成
     不分斷點一律由 app.js 的 _fitLegendLabels() 依實際量到的文字寬度與可用格寬
     決定要藏第幾格（規則跟 renderHist 的 X 軸刻度「量得下才顯示」同一套），這裡
     不用再單獨寫手機專屬的隱藏規則。 */
  body.tab-map #drawer-btn{display:flex!important}
  #mdrawer{display:block}
}
/* ── Fluid Typography (mobile) ── */
@media(max-width:768px){
  /* 標題塊已移進內容區、不再是 sticky chrome；手機只留分頁選單貼頂（top:0，見上方預設值） */
  /* 離階字級收攏：下限 15px 不在官方階（12/14/16/18/20/24/30/36）。上限已是
     16px，15 到官方階 14／16 距離相等，平手時往下取整到 14px——這條 clamp
     範圍本來就窄（只有 1px），往上取整到 16 會讓上下限相等、clamp 直接退化成
     固定 16px，等於取消了「極窄手機再縮一點」的原意圖；14px 也剛好跟同一個
     media query 內其餘同層級文字（.kpi-b .lab／.kpi-lab／.results-cond-tag／
     .pager-info／.bc-date 等全部都是 clamp(14px,…,16px)）的下限一致，字級階層
     不會因為 body 自己另開一個 15px 而跟其他文字對不齊。 */
  body{font-size:clamp(14px,3.8vw,16px)}
  .fl label{font-size:clamp(16px,4vw,18px)}
  .fl select,.fl input{font-size:16px;padding:4px 10px}
  .fl select{padding-right:24px;background-position:right 4px center;padding-top:0;padding-bottom:0}
  .btn{font-size:clamp(16px,4.2vw,18px);padding:8px 16px}
  .chart-card h3{font-size:clamp(16px,4.2vw,18px)}
  /* 離階字級收攏：上限 26px 不在官方階，26 到官方階 24 距離 2、到 30 距離 4，
     非平手情況取最近的 24——但 .kpi-b .val 在同一個斷點內本來就比 .kpi-val／
     .fa-kpi-val 高一階（hpsk-ui 0.6.0 後兩者下限都是 20px，層級差改靠上限 30 vs 24 維持），若這裡也收斂到跟它們同樣的 24 上限，
     兩種 KPI 數字在寬手機（500-768px）會被壓成一樣大，「.kpi-b 比較大」這個
     原意圖的層級關係就消失了。改成 30（.kpi-val/.fa-kpi-val 24 的下一個官方
     階），維持「.kpi-b 數字永遠比一般 KPI 數字大一階」的關係。 */
  .kpi-b .val{font-size:clamp(20px,5.2vw,30px)}
  .kpi-b .lab{font-size:clamp(14px,3.6vw,16px)}
  /* 離階字級收攏：上限 22px 不在官方階，22 到官方階 20／24 距離相等（都差 2），
     平手時往上取整到 24——這兩個是 KPI 卡的數字（跟旁邊 --c-orange-800 的
     單價數字同一角色），手機字級偏保守比偏小氣更安全，且 24px 剛好是這個數字
     在桌機版本來的大小（.kpi-val{font-size:24px} 桌機規則），寬手機（接近
     768px）長到跟桌機一樣大是合理的封頂，不會超出桌機尺寸。 */
  .kpi-val{font-size:clamp(20px,5vw,24px)}
  .kpi-lab{font-size:clamp(14px,3.6vw,16px)}
  .fa-kpi-val{font-size:clamp(20px,5vw,24px)}
  .fa-kpi-lab,.fa-kpi-cmp{font-size:clamp(14px,3.6vw,16px)}
  .results-sep{font-size:clamp(16px,4.2vw,18px)}
  .results-cond-tag{font-size:clamp(14px,3.6vw,16px)}
  .sb-btype-tab{font-size:clamp(14px,3.6vw,16px)}
  table{font-size:clamp(16px,4.2vw,18px)}
  /* 選擇器改跟桌機版同步用 thead th（建議1）：裸 th（0,0,1）比桌機版新規則
     thead th（0,0,2）specificity 低，即使包在窄寬度 media query 裡也贏不了，
     這個斷點原本的字級縮放會整個失效，改同一組選擇器才吃得到。
     不覆寫 font-size：app.js isMobile() 是 <640px 才卡片化，640–768px 這段
     桌機明細表仍在渲染，若這裡放大字級，表頭會吃到這條規則、桌機版的
     thead th{14px/400}（建議1 的核心）在這一整段完全沒生效，而且方向是反的
     ——表頭比同表內文還大，跟桌機表頭比也大了 4px，層級整個消失。拿掉
     font-size 讓桌機的 14px 一路通到底（仍遠小於這個斷點 table{font-size}
     算出的 18px 內文，維持「表頭視覺重量低於資料本身」），只保留這裡本來
     就要改的 padding。
     左右內距 10→8px（2026-09-11）：768px（iPad 直式／部分安卓平板）是三欄版位，
     明細表容器只剩 713px，而表格的 min-content 是 741px——11 欄全部縮到各自的最小
     寬度後還是放不下，多出來的 28px 變成表格自己的橫向捲動，同時「地址」欄被壓到
     48px、中文變成一個字一行，單列高度衝到 293–469px。
     28px 之中有 21.7px 是 19cf4c4 全站改系統字型造成的（實測：把 --ff 切回舊值，
     表格寬度由 741.2 回到 719.5px），但字型不能為了這張表回退。改用「同一個斷點把
     儲存格左右內距各收 2px」把寬度要回來：11 欄 × 2 側 × 2px = 44px，實測表格寬度
     741.2 → 713（等於容器），橫向溢出 28 → 0，地址欄 48 → 54.2px、單列高度
     293.5 → 168.5px。
     ⚠️ 這條只影響買賣／租賃明細表：.area-dist／.area-summary（比較表）與 table.hm
     （熱力圖）都自己宣告了 padding，且選擇器帶 class（特異度較高），不會被這裡蓋到。
     ⚠️ 這不是「地址欄會擠」的根治：713px 要塞 11 欄本來就不夠，地址欄仍只有 54px
     （約三個字一行）。根治要動欄位組合（768 收掉幾欄或改卡片式），屬另一輪的決策。 */
  thead th{padding:9px 8px}
  td{padding:9px 8px}
  .pager button,.pager-info{font-size:clamp(14px,3.6vw,16px)}
  .hc-bar-lbl{font-size:clamp(16px,4.2vw,18px)}
  .hc-bar-val{font-size:clamp(16px,4.2vw,18px);width:clamp(64px,18vw,78px);white-space:nowrap}
  .hc-bar-track{height:clamp(16px,4.5vw,22px)}
  .bc-date{font-size:clamp(14px,3.6vw,16px)}
  .bc-addr{font-size:clamp(14px,3.6vw,16px)}
  /* 離階字級收攏：上限 19px 不在官方階，19 到官方階 18／20 距離相等（都差 1），
     平手時往上取整到 20——這是手機卡片的價格數字（本站表格數字欄一貫的重點
     強調角色），跟 .listing-price 同款同值，兩者一起處理維持一致。 */
  .bc-price{font-size:clamp(16px,4.4vw,20px)}
  .bc-meta{font-size:clamp(14px,3.6vw,16px)}
  .bc-btype,.tx-label,.bc-rtag{font-size:clamp(14px,3.6vw,16px)}
  .mode-btn{font-size:clamp(16px,4vw,18px)}
  .toolbar-title{font-size:clamp(16px,4.2vw,18px)}
  .table-toolbar{gap:10px}
  .table-toolbar label{font-size:clamp(16px,4vw,18px)}
  .listings-title-main{font-size:clamp(16px,4.2vw,18px)}
  .listings-title-sub{font-size:clamp(12px,3.2vw,14px)}
  .listing-name{font-size:clamp(16px,4.2vw,18px)}
  .listing-addr,.listing-comm,.listing-unit,.listing-meta span{font-size:clamp(14px,3.6vw,16px)}
  /* 離階字級收攏：同 .bc-price 上面的說明（19→20）。 */
  .listing-price{font-size:clamp(16px,4.4vw,20px)}
  .elite-card-name{font-size:clamp(16px,4.2vw,18px)}
  .elite-card-brand{font-size:clamp(14px,3.6vw,16px)}
}
@media(max-width:700px){
  /* 麵包屑／膠囊分頁／地圖容器三者的左右內距統一在這個斷點一起收窄，跟
     .query-page/.feat-page 同一個 700px 門檻同步收，避免各自斷點不一致
     導致左緣參差（.nav-inner 原本另外在 640px 收窄，已併入這裡）。
     .rh-standalone 的同斷點覆寫另外寫在該規則自己旁邊（見下方），因為它在原始碼
     順序上排在這個 @media 區塊之後——寫在這裡會被後面同層級的 .rh-standalone
     基本規則蓋掉，等於沒作用。 */
  #area-hdr,.nav-inner,#page-map.active{padding-left:12px;padding-right:12px}
  .query-page{padding-top:0;padding-right:12px;padding-bottom:12px;padding-left:12px}
  .filter-card{padding:10px 12px}
  .filter-grid{grid-template-columns:1fr 1fr;gap:4px}
  .charts-row{grid-template-columns:1fr}
  .kpi-row{grid-template-columns:1fr 1fr}
  /* M版（2026-07-17 定案）：菁英房仲移到 KPI 與圖表之間（order:-1），改單張左右滑動＋圓點 */
  .charts-zone{grid-template-columns:1fr}
  .elite-side{position:static;order:-1}
  .elite-side .elite-belt-grid{flex-direction:row;overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;gap:10px}
  .elite-side .elite-card{flex:0 0 100%;scroll-snap-align:center}
  .elite-dots{display:block}
  .fa-charts-row{grid-template-columns:1fr}
  .fa-kpi-4{grid-template-columns:repeat(2,1fr)}
  /* 熱力矩陣篩選器：label + select 同一列（700px 以下） */
  #fa-filter-card .fl{flex-direction:row;align-items:center;gap:8px}
  #fa-filter-card .fl label{white-space:nowrap;flex-shrink:0;min-width:5em}
  #fa-filter-card .fl select{flex:1;min-width:0}
  /* M版 listing carousel：隱藏左右按鈕，改用 swipe；卡片佔 82vw */
  .listings-carousel .carousel-btn{display:none}
  .listing-card{flex:0 0 min(260px,82vw);min-width:0}
}
@media(max-width:600px){
  .table-toolbar .toolbar-title{flex:0 0 100%;margin-right:0}
}
@media(max-width:480px){
  /* 手機：外層留白與紫塊高度縮一階（--chrome 只用於桌機滿版計算，手機走 fitMapHeight()） */
  #area-hdr{padding:8px 12px 0}
  .kpi-row{grid-template-columns:1fr 1fr}
  .filter-grid{grid-template-columns:1fr}
  /* 注意：上面那條 .filter-grid{1fr}（單欄堆疊）**不適用**買賣／租賃的篩選卡。
     #b-filter-card/#r-filter-card 有自己的 `#id .filter-grid` 覆寫（在後面
     「Filter-grid layout for buy/rent」那一段），維持三欄一行——單欄堆疊會讓吸頂的
     篩選卡從 64px 長到 160px，在 375×812 上佔掉五分之一個螢幕。完整推理見該處。 */
  #b-area-preset option[value="custom"]{display:none}
  .query-page,.feat-page{padding-top:0;padding-right:12px;padding-bottom:12px;padding-left:12px}
  .kpi-b .val{font-size:clamp(20px,5.2vw,24px);word-break:break-word}
  .fa-kpi-4{grid-template-columns:repeat(2,1fr)}
}
/* Skeleton shimmer — sweep runs on ::after via transform so it composites on the GPU
   instead of repainting background-position every frame (was a CLS/main-thread culprit). */
@keyframes sk-shine{to{transform:translateX(100%)}}
.sk-shimmer{position:relative;overflow:hidden;background:#ebebeb}
.sk-shimmer::after{content:'';position:absolute;inset:0;transform:translateX(-100%);background:linear-gradient(90deg,transparent,rgba(255,255,255,.6),transparent);animation:sk-shine 1.5s infinite linear;will-change:transform}
#map-sk{position:absolute;inset:0;z-index:10;pointer-events:none}
.sb-sk-tabs{height:30px;margin-bottom:10px;border-radius:6px}
.sb-sk-row{height:34px;margin:6px 0;border-radius:6px}
.sk-kpi-ph{height:62px;border-radius:6px}
.sk-chart{height:160px;width:100%;border-radius:var(--r)}
/* SVG 圖表（單價分布／單價趨勢／月租金分布）骨架高度與 app.js 的 _chartH() 同一組，
   兩邊要一起改。骨架若跟實際圖高度對不上，圖畫好的那一刻整頁會往下（或往上）位移。
   桌機：_chartH()=W/CHART_RATIO，長寬比 2.9，用 aspect-ratio 跟著版位寬度走。
   手機（≤700px）：_chartH() 是固定的 CHART_H_MOBILE=210，而 2026-09-10 拿掉
   _chartW() 的 340 下限後（方案 D1）座標系＝容器實寬、縮放比恆為 1.0，SVG 實際渲染
   高度因此恆為 210px，與容器寬度無關——不能再用 340/210 的長寬比（那在 224px 寬的
   交叉分析圖卡上只有 138px，比實際圖矮 72px，圖一畫好整頁就跳一次）。
   橫條圖高度由列數決定、與寬度無關，維持 .sk-chart 的固定高度。 */
.sk-chart-svg{height:210px}
@media(min-width:701px){.sk-chart-svg{height:auto;aspect-ratio:2.9}}
.sk-tbl-ph{height:38px;border-radius:4px;margin:3px 0}
.sk-hm-grid{display:grid;gap:5px;padding:4px 0}
.sk-hm-cell{border-radius:4px}
@keyframes sep-flash{0%{background:var(--c-purple-200)}100%{background:var(--c-purple-50)}}
/* .results-sep 是改版前的舊 class，2026-08-17 版面重構後結果標頭區已經改用
   AreaResultHead.vue 的 .result-head，但 app.js 觸發閃爍效果時（filterBuy()/
   filterRent() 找不到 #results-sep 就退回 .result-head）一路都是幫 .result-head
   加 flashing class——這條規則卻只認 .results-sep，導致閃爍動畫從結構重構後
   就沒生效過。結尾停在 --c-purple-50 也剛好等於 .result-head 平常的底色，
   確認這條本來就是為它寫的，一併補上選擇器。 */
.results-sep.flashing,.result-head.flashing{animation:sep-flash .6s ease-out forwards}
/* Detail-loading tab placeholder */
.detail-loading-msg{
  position:absolute;inset:0;z-index:10;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:12px;color:var(--ink-mute);font-size:14px;
  background:rgba(255,255,255,0.88);
}
.detail-loading-msg .ld-spinner{
  width:32px;height:32px;
  border:3px solid var(--c-purple-100);
  border-top-color:var(--c-purple-800);
  border-radius:50%;
  animation:ld-spin .75s linear infinite;
}
/* ─── Location Picker ─── */
.loc-trigger,.fl select{height:44px;padding:0 10px;border:1px solid var(--c-brown-600);border-radius:4px;font-size:16px;color:var(--ink);background:var(--white);-webkit-appearance:none;-moz-appearance:none;appearance:none;transition:border-color .2s;width:100%;box-sizing:border-box;cursor:pointer;font-family:inherit}
.loc-trigger{display:flex;align-items:center;justify-content:space-between;gap:6px;text-align:left}
.loc-trigger:hover,.fl select:hover{border-color:var(--c-purple-600)}
.loc-trigger:focus,.loc-trigger.open,.fl select:focus{border-color:var(--c-purple-600)}
.loc-trigger.has-value,.fl select.has-value{color:var(--c-purple-800);font-weight:700}
.loc-trigger-caret{flex-shrink:0;transition:transform .2s;color:var(--ink-soft)}
.loc-trigger.open .loc-trigger-caret{transform:rotate(180deg)}
.loc-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:left}
.fl select{padding-right:24px;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%239A9AA0%22%20stroke-width%3D%222%22%3E%3Cpolyline%20points%3D%226%209%2012%2015%2018%209%22%2F%3E%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:right 4px center}
/* hpsk-ui 的下拉浮層（.field-wrap 的 .dropdown-list）本尊只用 border，沒有
   額外陰影；跟這裡同樣道理套用：邊框改用官方預設 border 色（--c-brown-600）、
   圓角改成按鈕/輸入框標準 4px，拿掉自創的陰影。 */
.loc-panel{display:none;position:absolute;top:calc(100% + 4px);left:0;z-index:300;background:var(--white);border:1px solid var(--c-brown-600);border-radius:4px;width:100%;overflow:hidden}
.loc-panel.open{display:flex;flex-direction:column}
.loc-panel-body{display:flex}
.lp-city-col{width:110px;flex-shrink:0;border-right:1px solid var(--line);overflow-y:auto;max-height:320px;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
.lp-dist-col{flex:1;min-width:0;overflow-y:auto;padding:4px;max-height:320px;display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr));grid-auto-rows:min-content;align-content:start;gap:2px;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
.lp-region-label{padding:6px 10px 3px;font-size:12px;font-weight:700;color:var(--ink-soft);letter-spacing:.04em;background:var(--bg)}
.lp-city{padding:11px 12px;font-size:16px;cursor:pointer;transition:background .12s;line-height:1.3}
.lp-city:hover{background:var(--c-purple-50);color:var(--c-purple-800)}
.lp-city.active{background:var(--c-purple-100);color:var(--c-purple-800);font-weight:400}
.lp-dist{padding:10px 12px;font-size:16px;cursor:pointer;border-radius:6px;text-align:left;transition:background .12s;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:flex;align-items:center;min-height:36px}
.lp-dist:hover{background:var(--c-purple-50)}
.lp-dist.active{background:var(--c-purple-800);color:var(--white);font-weight:400}
.lp-dist-hint{padding:24px 10px;text-align:center;font-size:16px;color:var(--ink-soft)}
/* ─── Area custom inputs ─── */
.area-custom-row{display:flex;gap:4px;align-items:stretch;height:40px}
.area-custom-row input{min-width:0;flex:1;height:100%;padding:0 8px;border:1px solid var(--line);border-radius:8px;font-size:clamp(16px,4vw,18px);color:var(--ink);background:var(--white);box-sizing:border-box;appearance:none;-webkit-appearance:none}
.area-custom-row input:focus{border-color:var(--c-purple-600);outline:none}
.area-reset-btn{flex-shrink:0;width:40px;height:100%;border:1px solid var(--line);border-radius:6px;background:var(--white);color:var(--ink-soft);cursor:pointer;font-size:16px;line-height:1;padding:0;box-sizing:border-box}
.area-reset-btn:hover{background:var(--c-purple-50);border-color:var(--c-purple-800);color:var(--c-purple-800)}
.area-sep{color:var(--ink-soft);font-size:12px;flex-shrink:0;align-self:center}
/* ─── Filter-grid layout for buy/rent (3 items, lp-wrap takes full row) ─── */
#b-filter-card .filter-grid,#r-filter-card .filter-grid{grid-template-columns:1.5fr 1fr 1fr;margin-bottom:0}
/* 手機篩選卡：維持「三欄一行」，用重新分配欄寬＋收窄控制項內距換出空間（PM
   2026-09-11 拍板，推翻 2026-09-10 的單欄堆疊）。
   ─ 前一版做錯在哪 ─
   上一輪為了修「375px 下『型態不限』顯示成『型態不阝』」，把 ≤480px 改成單欄堆疊。
   裁字只差 8.9px（選單 91.1px、可用文字寬 55.1px、「型態不限」需 64px），卻用
   「多佔 96px 垂直空間」去換：篩選卡從 64px 變成 160px，而這張卡是 position:sticky
   的，捲動時一直佔著 375×812 螢幕的五分之一。PM 實測正式機舊版是 60px／三欄一行，
   我們把它變成了 20% 的螢幕高度——交換方向反了。
   （附帶更正：當時說「這是原作者的既有設計、只是搬到能生效的位置」。那條單欄規則
   從沒生效過，正是因為三欄一行本來就是刻意的設計；它不該被救活。）
   ─ 這一版怎麼生出那 8.9px ─
   三件事一起做，全部只動版面尺寸，**不動 44px 觸控高度**：
   ① 欄寬比 1.5fr 1fr 1fr → 1.1fr 1fr 1fr。地區欄原本吃 1.5 份（375px 下 136.7px），
      實際只需要放「全部地區」四個字（64px）＋下拉箭頭；多出來的寬度讓給兩個 select。
      地區欄的 .loc-label 有 text-overflow:ellipsis，選了「台北市 大安區」這種長字串
      本來就會優雅截斷（改動前後都一樣），所以它是三欄裡最能讓的一欄。
   ② select 左右內距 10/24 → 6/18，下拉箭頭圖示由 right 4px 移到 right 1px。
      箭頭 SVG 的可見三角形在 16px 方框內左右各內縮 4px，移到 right 1px 後可見右緣
      距邊框 5px，文字結束處距箭頭方框仍有 1px，不會碰在一起。
   ③ .loc-trigger 的左右內距 10 → 6、與箭頭之間的 gap 6 → 4。它在 ≤700px 另外還吃了
      一條 `padding-right:24px`（那是給「用背景圖當箭頭」的 select 準備的，而
      .loc-trigger 的箭頭是真的 <svg> 子元素，等於白白多留 24px），一併收掉。
   ─ 實測（macOS Chromium，canvas measureText 對實際字串量測）─
   篩選卡高度：320/375/414 全部 160px → **64px**（買賣頁與租賃頁相同）。
   可用文字寬 − 最長選項所需寬（正值＝不會被裁）：
     375px：型態 +12.9 / 坪數 +9.6 / 地區 +15.2
     414px：型態 +25.5 / 坪數 +22.1 / 地區 +29.0
     360px：型態  +8.1 / 坪數  +4.7 / 地區  +9.9
   最長選項是「50坪以上」（67.3px），不是「型態不限」（64px）。 */
@media(max-width:480px){
  #b-filter-card .filter-grid,#r-filter-card .filter-grid{grid-template-columns:1.1fr 1fr 1fr}
  #b-filter-card .fl select,#r-filter-card .fl select{padding-left:6px;padding-right:18px;background-position:right 1px center}
  #b-filter-card .loc-trigger,#r-filter-card .loc-trigger{padding-left:6px;padding-right:6px;gap:4px}
}
/* 極窄手機（<360px，實務上只有 iPhone SE 第一代那類 320px 裝置）：三欄一行放不下
   16px 的四個中文字，這是幾何事實不是調參問題——320px 扣掉頁面內距 24、卡片內距、
   欄間距之後只剩 264px，而三欄在 16px 下的最小需求是 ~290px。
   取捨：字級降一階（16 → 14px，仍在官方字級階上）換「一行 64px」。維持 16px 的
   代價是回到單欄 160px，或讓「全部地區」被截成「全部地…」，兩者都比字小一階差。
   觸控高度仍是 44px（.fl select 的 height 沒動）。
   卡片左右內距同步 12 → 6px，把最後 12px 讓給控制項本身。
   實測 320px：篩選卡 64px；可用文字寬餘裕 型態 +7.0 / 坪數 +3.9 / 地區 +7.9。
   ⚠️ 已知取捨：iOS Safari 對 font-size < 16px 的表單控制項會在聚焦時放大頁面，
   320px 裝置點開這兩個下拉選單時可能看到一次縮放。 */
@media(max-width:359px){
  #b-filter-card,#r-filter-card{padding-left:6px;padding-right:6px}
  #b-filter-card .fl select,#r-filter-card .fl select,
  #b-filter-card .loc-trigger,#r-filter-card .loc-trigger{font-size:14px}
}
.lp-wrap{min-width:0;position:relative}
/* feat-page filter 不需置頂：這頁的篩選卡不吸頂，表頭也只吃 --fst，兩者不會互相
   疊住。app.js 的 setFilterStickyTop() 偵測到這裡是 position:static 時會讓 --fst2
   直接等於 --fst（--fst2 目前無呼叫端，是為下一批「明細表表頭吸頂」預留）。 */
#fa-filter-card.filter-card{position:static;top:auto;box-shadow:none}
@media(max-width:700px){
  /* 這裡原本還有一條 `#b-filter-card .filter-grid,#r-filter-card .filter-grid{
     grid-template-columns:1.5fr 1fr 1fr}`，跟上面「Filter-grid layout for
     buy/rent」那條無條件套用的基本規則數值完全相同，純屬多餘（拿掉不影響任何
     寬度的實際渲染結果）——而且它的存在正是「手機選單文字被裁」那個 bug 的
     元兇之一：它比 @media(max-width:480px) 那條單欄覆寫在原始碼裡更晚出現，
     同特異度下永遠贏，害 ≤480px 也吃不到單欄版面。已移除；1.5fr 1fr 1fr 這個
     比例本來就是無條件生效的預設值，不需要在這裡重申一次。 */
  .loc-trigger{padding-right:24px}
  .lp-wrap{min-width:0}
  .loc-panel{width:min(300px,calc(100vw - 20px))}
  .lp-city-col{width:88px}
  .lp-dist-col{grid-template-columns:1fr}
  .lp-dist{font-size:16px;padding:12px 14px}
}
/* ─── Footer ─── */
/* 交叉分析明細面板的載入提示（展開格子時才載入城市明細，見 app.js showFADetail） */
.fa-detail-msg{padding:24px 12px;text-align:center;color:var(--ink-soft);font-size:14px}

/* H1 下方的答案優先摘要（AreaLead.vue）：外框尺寸沿用 .query-page，與內容卡片切齊。
   地圖頁不出現（見該元件），所以不影響 --chrome 與地圖滿版計算。 */
/* 結果標頭區（AreaResultHead.vue）：H1＋時間徽章＋描述。取代改版前的紫色標題塊
   與「買賣行情分析＋條件 chips」列。地圖頁用 .rh-standalone 掛在版面層。

   修正前一版（1f7ec7a）的殘留 bug：那次只補了「文字」的內距（padding），但
   .result-head 本身有 border-left+background（看得見的紫色方框，不像
   #area-hdr／.nav-inner／#page-map 那樣沒有自己的框——它們的「內縮」只有內容
   看得見，方框本身頂到容器邊緣沒關係）。.rh-standalone 若只調 padding，方框
   本身（邊框＋底色）仍頂到容器邊緣，比下方麵包屑/分頁列/地圖凸出一截——
   這正是 PM 回報、附了 incognito 截圖的那個 bug：紫色色塊左緣比「首頁」
   麵包屑文字更凸出去。要讓「方框本身」的可見邊緣對齊其餘三者的內容起點，
   必須讓方框整體位移（max-width+margin:auto 讓瀏覽器決定方框位置），不能只
   靠 padding（padding 只能內縮方框「裡面」的文字，方框自己的邊界不動）。

   padding 還原成元件原本的 12px 16px（拿掉 1f7ec7a 加的 20px/12px 覆寫），
   讓文字相對方框邊緣的縮排跟其他三頁裡巢狀的 .result-head 一致（那三頁的
   .result-head 沒有 .rh-standalone，直接吃 .query-page/.feat-page 已經內縮
   過的內容框，方框邊緣本來就對齊，文字只需方框自己的 border+padding 縮排）。

   ≥701px 這一段刻意不切成 @media(max-width:1199px) 去接 900/700 既有斷點，
   而是用 max-width:min(1160px, calc(100% - 40px)) 一條規則涵蓋到底——這裡
   踩過一個坑：#area-hdr／.nav-inner／#page-map 的 max-width:1200 有沒有限制住
   它們的方框，判斷基準是「容器寬度」（.area-layout-root 的實際 content box，
   受 html{scrollbar-gutter:stable} 影響會比 window.innerWidth 窄一截，實測
   約 15px，且這個差值不是螢幕/瀏覽器都一樣的常數）；但 @media(max-width:…)
   這種寫法判斷基準是「視窗寬度」，兩者在 1200 附近會對不齊——實測視窗寬剛好
   1200px 時，容器寬只有 1185px（<1200，其餘三者的 max-width 已經不再限制，
   內容起點固定 20px），但 .rh-standalone 若用 @media(max-width:1199px) 判斷
   （1200 不 <=1199），還留在「max-width:1160 置中」那條規則，算出方框邊緣只有
   12.5px，兩者對不上。改用 min()：min(1160px, calc(100% - 40px)) 兩個運算元
   跟其餘三者的 max-width:1200 一樣是用「容器寬度」（100% 相對同一個
   containing block）在比大小，不會有這種視窗寬 vs 容器寬的落差，容器寬
   ≥1200 時 min() 選 1160（等同 max-width:1160+margin:auto 置中的效果，方框
   邊緣＝(容器寬-1160)/2，代數上等於其餘三者的 (容器寬-1200)/2+20）；容器寬
   <1200 時 min() 選 calc(100% - 40px)，方框在任何寬度都恆定內縮 20px（兩側
   各佔 40px 的一半）——經 getBoundingClientRect 在 1920/1440/1280/1200/1160/
   1100/1000px 實測全部對齊。也不能改用固定 margin-left/margin-right 兩側都
   給死值：.area-layout-root 為了修另一個 flex 版面坑，強制所有直接子項
   width:100%（見 layouts/default.vue），width:100% 加兩側都非 auto 的 margin
   會 over-constrained，瀏覽器會忽略右邊界重新算成負值，方框整個往右溢出
   容器（已實測踩到這個陷阱，margin 必須保持 auto 才不會溢出）。
   ≤700px 才改用既有 @media(max-width:700px) 斷點，改成 calc(100% - 24px)
   （恆定內縮 12px）——這裡跟其餘三者一樣是用同一個 @media 判斷式切換
   （都是拿「視窗寬度」互相比對），兩邊在同一個視窗寬度同時切換，不會像
   上面 1200 附近那樣有基準不一致的問題。 */
.result-head{margin:0 0 16px;padding:12px 16px;background:var(--c-purple-50);border-radius:var(--r);border-left:3px solid var(--c-purple-400)}
.rh-standalone{max-width:min(1160px, calc(100% - 40px));margin:0 auto 12px}
@media(max-width:700px){.rh-standalone{max-width:calc(100% - 24px)}}
.rh-top{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.rh-title{font-size:20px;font-weight:700;color:var(--c-purple-900);line-height:1.4}
/* 離階字級收攏：15px 不在官方階，就近取整選 14px——這是次要說明文字（跟
   .ad-note／.chart-sub 等站上其他次要文字同一階），改成固定 14px 後跟下面
   @480 的覆寫值相同，那條覆寫變成 no-op，一併拿掉（見下）。 */
.rh-lead{margin-top:6px;font-size:14px;line-height:1.75;color:var(--ink)}
.rh-src{color:var(--ink-soft);font-size:14px}
@media(max-width:480px){
  .result-head{padding:10px 12px}
  /* 離階字級收攏：17px 不在官方階，原則與取整方向見 .area-section-h2 旁的說明
     （四處同一批 17px 之一，這裡不重複整段）。 */
  .rh-title{font-size:16px}
}

/* 行政區比較表（AreaDistrictTable.vue）：版位與樣式沿用 SSR 摘要區，只多一個
   「目前所在行政區」的標示。外框尺寸跟著 .query-page 走，與內容卡片切齊。 */
.area-dist{max-width:1200px;margin:0 auto;padding:0 20px 24px;--as-measure:640px}
/* h2/.ad-note 跟表格共用同一個 --as-measure，避免表格縮寬後說明文字/標題還是滿版
   1160px，變成一段寬說明文字疊在一張窄很多的表格上面、右側留一大片空白。 */
.area-dist h2{font-size:18px;font-weight:700;color:var(--c-purple-900);margin:0 0 8px;line-height:1.4;max-width:var(--as-measure)}
.ad-note{font-size:14px;line-height:1.7;color:var(--ink-soft);margin:0 0 12px;max-width:var(--as-measure)}
/* 卡片背景／圓角／陰影掛在 .ad-scroll（外層捲動容器）而非 table 本身：
   border-collapse:collapse 的表格上設 border-radius，大多數瀏覽器不會拿去裁切
   thead 那排的背景色，變成表頭（現為 --c-dark-800 深灰底）方角蓋在圓角白卡上面，兩者對不齊。
   跟 .area-summary 的 .as-scroll 走同一套模式。
   不再設 overflow-x:auto：table-layout:fixed＋min-width:auto（見下）已經讓表格
   在任何容器寬度下都會自己縮小，實測 320～375px 三頁都不需要橫向捲動，這層
   overflow-x:auto 已是死重，而且會壞事——只設 overflow-x 時 CSS Overflow spec
   會把沒寫的 overflow-y 從 visible 自動配對成 auto（甚至換成 overflow-y:clip
   也一樣會被瀏覽器解析成 hidden），讓這層 wrapper 自己變成一個「捲動範圍是 0」
   的捲動容器（撐滿高度＝內容高度，內部從來沒東西可垂直捲），thead 的 sticky
   定位基準因此變成這個永遠不會捲動的容器而非整個頁面，sticky 表頭完全失效、
   只是跟著整頁一起捲走。拿掉 overflow-x 讓 overflow-y 也真正保持 visible，
   sticky 才會用整個頁面當定位基準。 */
.ad-scroll{background:var(--card);border-radius:var(--r);box-shadow:var(--sh);max-width:var(--as-measure)}
/* min-width:auto 解掉全站通用 table 規則的 min-width:600px（line 295）：
   手機版容器只有 ~350px，鎖 600px 會讓數字整欄被切到畫面外、只能靠使用者自己
   摸到有橫向捲軸——.area-summary 早就這樣解過，這裡漏掉。
   font-size 不寫死：改吃全站預設 16px，跟 .area-summary 一致（原本各寫各的
   14px/16px，同一頁兩張同類型表格字級對不起來）。 */
.area-dist table{width:100%;max-width:var(--as-measure);min-width:auto;table-layout:fixed;border-collapse:collapse}
/* 列分隔線同步升到 --c-dark-400，理由同上方裸 td 規則。 */
.area-dist th,.area-dist td{padding:8px 12px;text-align:right;border-bottom:1px solid var(--c-dark-400);white-space:nowrap}
/* position:sticky 讓表頭在捲動長表格（~22 列）時保持可見；top 吃 --fst（膠囊分頁列
   高度，由 app.js 的 setFilterStickyTop() 實測寫入），不能寫死 top:0，否則會被上方的
   sticky NavBar／分頁列蓋住。
   刻意「不」吃 --fst2（＝--fst 再讓開一層 sticky 篩選卡）：這張表跟買賣/租賃頁的
   .filter-card 在頁面結構上是不同容器，position:sticky 只在自身容器範圍內作用，捲到
   這張表時篩選卡早已完全捲出畫面（1440px 實測其上緣在 y=-450），兩者永遠不會重疊
   （逐格捲動實測重疊 0 次）。曾經改吃 --fst2 是誤判，結果是表頭平白往下掉 87.6px
   （375px 掉 176.4px），空白帶裡看得到表格自己的資料列浮在深色表頭上方，已回退。 */
/* 背景/文字色改跟主表頭統一（見上方 thead th 說明），拿掉全站第三種表頭底色
   （--c-purple-50）。字級/字重也對齊主表頭改成 14px/400（PM 裁決）：原本
   pin 在 16px/700 的理由是「f40d6f6／39563e9／6562930 剛校正過，不在本波
   改動範圍」，但 f40d6f6 的訴求是 (a) 兩張比較表彼此字級一致、(b) tbody
   th[scope=row] 列頭不能比同列 <td> 大——兩者都跟 thead 字級無關，thead 一起
   降到 14px/400 不影響這兩件事（tbody th[scope=row] 仍走 :880 附近的
   th[scope=row] 規則，維持 16px/700）。五張表表頭底色已統一，若表頭型態
   仍停在 14/400 與 16/700 兩套，等於只做半套；改這裡才是真正統一。
   右對齊／white-space:normal／sticky 三項與字級無關，維持不動。 */
.area-dist thead th{background:var(--c-dark-800);color:var(--white);font-weight:400;font-size:14px;text-align:right;white-space:normal;position:sticky;top:var(--fst,48px);z-index:1}
/* table-layout:fixed 只吃第一列（這裡是 thead）的欄寬去定死全表：不設寬的欄位自動平分
   剩下空間。auto layout 原本會依內容判斷、常常把整欄拉得比實際需要寬很多倍
   （實測「單價中位數」欄被撐到快 600px，數字擠在最右緣、跟行政區名中間留一大片
   空白，閱讀性很差）；固定第一欄比例後其餘欄位平均分配，不會再暴衝。 */
.area-dist thead th:first-child{width:30%}
.area-dist th[scope=row],.area-dist thead th:first-child{text-align:left}
/* tbody 的 th[scope=row]（行政區名）不會吃到 thead th（見上方 thead th 選擇器
   說明：thead th 只命中 <thead> 裡的 th，特意不用裸 th 就是為了不波及這裡）。
   這裡明寫無底色深字，讓列頭跟同一列的 <td> 字色一致，也跟同一頁下面「全台
   各縣市」那張表（AreaSummary 的 th[scope=row]）一致。 */
.area-dist th[scope=row]{background:none;color:var(--ink);font-weight:700}
.area-dist tbody tr:last-child th,.area-dist tbody tr:last-child td{border-bottom:none}
/* hover 整列一起變色才看得出「滑到哪一列」：原本只寫 td，行政區名那欄（th）
   不吃 tr 的 hover，滑過去該欄不會變色，跟其他欄不一致。 */
.area-dist tbody tr:hover td,.area-dist tbody tr:hover th[scope=row]{background:var(--c-purple-50)}
/* 目前所在的行政區：讓使用者一眼看到自己在這份排行的哪個位置。
   --c-purple-50 拿掉跟 --c-purple-100 的別名後兩者不再同色，但保險起見另外加一條
   不靠背景色的視覺線索（左側色條），滑過去被 tr:hover 蓋掉背景時仍看得出「這是目前所在列」。 */
.ad-current th[scope=row],.ad-current td{background:var(--c-purple-100);font-weight:700}
.ad-current th[scope=row]{box-shadow:inset 3px 0 0 var(--c-purple-700)}
.ad-rank{margin-left:6px;font-size:12px;font-weight:400;color:var(--ink-mute)}
/* 離階字級收攏：17px 不在官方階，原則與取整方向見 .area-section-h2 旁的說明
   （四處同一批 17px 之一）。 */
@media(max-width:480px){.area-dist{padding:0 12px 20px}.area-dist h2{font-size:16px}}

/* SSR 摘要區塊（AreaSummary.vue）：四頁的 server HTML 原本零筆資料，這塊讓爬蟲與
   未執行 JS 的環境也讀得到全台縣市數字。純靜態內容，app.js 不認得也不會動它。
   外框尺寸沿用 .query-page/.feat-page，與頁面其他卡片切齊。 */
.area-summary{max-width:1200px;margin:0 auto;padding:0 20px 24px;--as-measure:640px}
/* h2/.as-note 跟表格共用同一個 --as-measure，理由同 .area-dist（見上）。 */
.area-summary h2{font-size:18px;font-weight:700;color:var(--c-purple-900);margin-bottom:8px;max-width:var(--as-measure)}
.area-summary .as-note{font-size:14px;color:var(--ink-soft);line-height:1.7;margin-bottom:12px;max-width:var(--as-measure)}
/* 卡片背景／陰影掛在 .as-scroll（外層捲動容器）而非 table 本身，撐滿寬度的判斷
   也要一起改這裡才會跟著縮，否則會變成表格縮了、外面那圈卡片還是滿版 1200px，
   看起來像表格飄在一塊過大的空白卡片裡。
   不再設 overflow-x:auto，理由同 .area-dist 的 .ad-scroll（見上）——會讓這層變成
   捲動範圍是 0 的捲動容器，害 thead 的 sticky 失效。這裡原本在 320～375px 確實會
   橫向溢出（最多到交叉分析頁「縣市＋3 種建物類型」欄數最多的情況，實測溢出達
   31px），但溢出源頭是表頭文字 white-space:nowrap 撐爆固定欄寬，不是表格本身撐不
   下——改讓表頭文字換行（見下 thead th）即可讓內容真正塞進固定欄寬，不需要再靠
   橫向捲動這個會弄壞 sticky 的安全網。 */
.area-summary .as-scroll{background:var(--card);border-radius:var(--r);box-shadow:var(--sh);max-width:var(--as-measure)}
.area-summary table{width:100%;min-width:auto;table-layout:fixed}
/* 同 .area-dist：固定第一欄比例，其餘欄位（縣市數×建物類型等，欄數依頁面而異）
   靠 table-layout:fixed 自動平分剩餘寬度，不用逐頁另外寫欄寬。 */
.area-summary thead th:first-child{width:30%}
/* th[scope=row]（縣市名）原本沒補 border-bottom：全站唯一的隔線規則是第 386 行
   裸的 `td{border-bottom}`，只吃 <td> 不吃 <th>，.area-dist 那邊是額外用
   `.area-dist th,.area-dist td` 兩個都寫才有隔線，這裡漏寫，導致縣市名那一欄
   看起來沒有列與列的分隔線、只有後面的數字欄有。 */
/* 列分隔線同步升到 --c-dark-400，理由同上方裸 td 規則；.area-summary td 沒
   自己設 border-bottom，會吃到上面已改過的裸 td 規則，兩者一起變深才一致。 */
.area-summary th[scope=row]{background:none;color:var(--ink);font-weight:700;text-align:left;white-space:nowrap;border-bottom:1px solid var(--c-dark-400)}
.area-summary td{text-align:right;white-space:nowrap}
/* 等寬數字補到四張比較表（2026-09-11，補 17-測試機QA驗收.md D3）：
   `.td-num,.th-num{font-variant-numeric:tabular-nums}` 只掛在買賣／租賃的明細表，
   四張比較表（買賣各行政區／全台總覽、租賃各行政區／全台總覽，以及交叉分析頁的
   縣市×型態總覽）的 <td> 沒有那個 class，右對齊是靠上面兩條規則達成的，等寬數字
   因此漏掉——「五張表統一」只做了五分之二。
   這些 <td> 全部都是數字欄（縣市／行政區名在 th[scope=row]），直接掛在 td 上即可，
   不用替 Vue 元件的每個儲存格補 class。成交筆數欄（8,094／17,116／1,743）在比例
   字寬下位數對不齊，正是 tabular-nums 要解決的情境。 */
.area-dist td,.area-summary td{font-variant-numeric:tabular-nums}
/* 同 .area-dist：加 sticky 讓「全台各縣市」那張長表格捲動時表頭留在畫面上。
   表頭文字改 white-space:normal 允許換行（跟下面資料格的數字不同，數字才需要不
   換行）：欄數較多的頁面（如交叉分析的「大樓／華廈／公寓（萬/坪）」）在窄螢幕
   上，表頭全字不換行會比欄位固定寬度還寬，實測撐出畫面外；讓表頭文字可以換行
   成兩行，內容就能真正塞進 table-layout:fixed 分配的欄寬，不需要犧牲 sticky
   換橫向捲動。明寫 normal（而非只是不寫）：全站通用的 thead th 規則
   本身就是 white-space:nowrap，不明寫會落回去吃到那條、又變回不換行。 */
/* 原本沒設背景/文字色，會落回舊版紫底表頭樣式；改跟主表頭統一（見上方
   thead th 說明），拿掉全站第三種表頭底色。字級/字重也對齊主表頭改成
   14px/400（PM 裁決，理由見 .area-dist thead th 旁的說明），跟 .area-dist
   thead th 維持一致——明寫 font-size/font-weight 而非留給 cascade 落回上面
   的 thead th{14px/400}，是為了兩表對齊這件事不必依賴選擇器 specificity
   隱性生效，之後任一邊改動都能一眼看出是刻意同步。
   top 同步吃 --fst（吸頂只讓開膠囊分頁列，刻意不吃 --fst2，理由見 .area-dist
   thead th 旁的註解，這裡不重複一份）。 */
.area-summary thead th{background:var(--c-dark-800);color:var(--white);font-weight:400;font-size:14px;text-align:right;white-space:normal;position:sticky;top:var(--fst,48px);z-index:1}
.area-summary thead th:first-child{text-align:left}
/* 原本完全沒有 hover 效果，滑過去整列不會有任何反應；補上跟 .area-dist 一致的
   hover 樣式，兩張同類型的比較表行為才一致。 */
.area-summary tbody tr:hover td,.area-summary tbody tr:hover th[scope=row]{background:var(--c-purple-50)}
/* 離階字級收攏：17px 不在官方階，原則與取整方向見 .area-section-h2 旁的說明
   （四處同一批 17px 之一）。 */
@media(max-width:480px){.area-summary{padding:0 12px 20px}.area-summary h2{font-size:16px}}
/* 表頭「單價中位數（萬/坪）」這類全形括號單位在窄欄位撐爆：括號本身沒有資訊量卻要吃
   ~32px，且跟數值欄已用的 .kpi-unit 一樣，單位本來就該弱化成輔助資訊而非跟主label同重。
   拿掉括號、單位改用這個 inline 小字 class。表頭現為 --c-dark-800 深灰底白字：這裡不設
   color，直接繼承表頭本身的白字，對比 9.89:1。不可改成借用 .kpi-unit 的灰階配色
   （--ink-soft #666666）——那階是設計給白卡上的「數值＋單位」組合用的，套在這個深灰
   表頭上實測只有 1.72:1，比繼承白字差得多；這是明確不能這樣改的理由，不是可有可無的
   附註。 */
.area-summary thead th .th-unit,
.area-dist thead th .th-unit{
  font-size:clamp(12px,.64em,16px);font-weight:400;margin-left:.2em;
  white-space:nowrap;display:inline-block
}
/* 兩張表原本 cell padding 不一致（.area-dist 是 8px 12px；.area-summary 沒覆寫，落回全站
   thead th 的 10px 12px），同一頁兩張表表頭高度對不齊，統一成 8px 12px。 */
.area-summary thead th,.area-summary td,.area-summary th[scope=row]{padding:8px 12px}
@media(max-width:768px){
  /* 桌機版這兩張表的表頭已跟主表頭一起改成 14px/400（PM 裁決，見上方
     .area-dist/.area-summary thead th 說明），這裡不再需要鎖死字級：以前鎖
     16px 是為了不讓表頭被全站斷點規則推大過桌機的 16px，現在桌機本身就是
     14px，欄寬同時在變窄，字級不需要也不應該比桌機大，直接落回基礎 14px
     即可，不再另外覆寫。 */
  /* 「中位數」3 個中文字（~48px）在手機欄寬（62-66px）無論如何塞不下，視覺上隱藏，
     語意靠兩張表既有的 sr-only caption（已各自完整寫出「…單價中位數與成交筆數」）保留。 */
  .area-summary thead th .th-mid,
  .area-dist thead th .th-mid{display:none}
  .area-summary thead th,.area-summary td,.area-summary th[scope=row],
  .area-dist th,.area-dist td{padding-left:8px;padding-right:8px}
}
/* 只給輔助技術讀的說明（table caption），視覺上不顯示 */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
footer{background:#f1f1f1}
.ft-wrap{display:flex;flex-direction:column;max-width:1200px;margin:0 auto;padding:40px 20px 24px;gap:24px}
.ft-top{display:grid;grid-template-columns:repeat(5,1fr);gap:16px}
.ft-col{display:flex;flex-direction:column;gap:12px}
.ft-col-head{font-size:14px;font-weight:700;color:var(--ink-soft);line-height:25px}
.ft-subcols{display:flex;flex-direction:row;gap:24px}
.ft-subcol{display:flex;flex-direction:column}
.ft-link{display:block;font-size:14px;color:var(--ink);text-decoration:none;padding:2px 0;line-height:23px}
.ft-link:hover{color:var(--c-purple-800);text-decoration:none}
.ft-bottom{display:flex;flex-direction:column;gap:8px}
.ft-bottom-main{display:flex;flex-direction:row;gap:20px;align-items:flex-end;padding-bottom:16px;border-bottom:1px solid #b5a99d}
.ft-logo-wrap{flex:1}
.ft-logo{height:34px;width:auto;aspect-ratio:218/34}
.ft-right{display:flex;flex-direction:row;gap:8px;align-items:center}
.ft-socials{display:flex;flex-direction:row;gap:8px;align-items:center}
.ft-social-icon{position:relative;display:inline-flex;width:38px;height:38px;flex-shrink:0}
.ft-social-icon .si-d,.ft-social-icon .si-h{width:38px;height:38px;display:block;transition:opacity .18s}
.ft-social-icon .si-h{position:absolute;inset:0;opacity:0;pointer-events:none}
.ft-social-icon:hover .si-d{opacity:0}
.ft-social-icon:hover .si-h{opacity:1}
.ft-app-icon{position:relative;display:inline-flex;flex-shrink:0}
.ft-app-icon .si-d,.ft-app-icon .si-h{height:36px;width:auto;display:block;transition:opacity .18s}
.ft-app-icon .si-h{position:absolute;left:0;top:0;height:36px;opacity:0;pointer-events:none}
.ft-app-icon:hover .si-d{opacity:0}
.ft-app-icon:hover .si-h{opacity:1}
.ft-apps{display:flex;flex-direction:row;gap:8px;align-items:center}
.ft-app-img{height:38px;width:140px;object-fit:contain;display:block}
.ft-copy{font-size:12px;color:var(--ink-soft);line-height:16px}
/* FOOTER MOBILE */
.footer-mobile{display:none;background:var(--bg)}
.facc-item{border-bottom:1px solid var(--line)}
.facc-head{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;font-size:16px;font-weight:700;color:var(--ink-soft);cursor:pointer;user-select:none;background:var(--bg)}
.facc-head .facc-chev{width:20px;height:20px;color:var(--ink-mute);transition:transform .2s;flex-shrink:0}
.facc-head.open .facc-chev{transform:rotate(180deg)}
.facc-body{display:none;padding:4px 16px 12px;background:var(--bg)}
.facc-body.open{display:block}
.facc-body a{display:block;padding:6px 0;font-size:16px;color:var(--ink);transition:color .15s}
.facc-body a:hover{color:var(--c-purple-800)}
.ft-mob-bottom{padding:24px 16px;display:flex;flex-direction:column;align-items:center;gap:16px;background:var(--bg)}
.ft-mob-logo{height:34px;width:auto;aspect-ratio:218/34;display:block}
.ft-mob-socials{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}
.ft-mob-apps{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}
.ft-mob-copy{font-size:12px;color:var(--ink-soft);text-align:center}
@media(max-width:960px){
  .ft-wrap{display:none}
  .footer-mobile{display:block}
}
body.tab-map footer{display:none}