/* ============================================================
   股票大亂鬥 · 全員全市場純度 ROI 競賽
   設計語言：盤房 Trading Floor（報紙編輯感 × 交易終端）
   規格：docs/dev/design/01-tokens.md、02-motion.md
   ============================================================ */

/* ---------- 自架字型 ----------
   CSP 是 default-src 'self'（serve.py 沒有 font-src 指令，回落到 default-src），
   Google Fonts 之類的外部來源一律被擋，字型只能同源。中文完全交給系統字，
   這裡只下載 latin 子集（unicode-range 讓瀏覽器在沒有拉丁字時根本不抓）。 */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("./assets/fonts/IBMPlexSans-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("./assets/fonts/IBMPlexSans-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("./assets/fonts/IBMPlexSans-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("./assets/fonts/IBMPlexMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("./assets/fonts/IBMPlexMono-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* ---------- 語意層（盤房日場）----------
     既有變數全部指向這一層。改膚只改這裡，不必動下面 6,000 行元件樣式。 */
  --paper: #f2eee6;
  --paper-sunk: #e9e2d3;
  --sheet: #fbf8f2;
  --sheet-raised: #ffffff;
  --sheet-top: #ffffff;
  --rule-hair: #dfd8ca;
  --rule-strong: #8f897c;
  --ink-1: #1a1713;
  --ink-2: #57503f;
  --ink-3: #6b6457;
  --brass: #835f13;
  --brass-deep: #6e4e0f;
  --brass-wash: #f1e7d2;
  --on-brass: #ffffff;
  --gain: #0e7354;
  --loss: #b4322b;
  --caution: #98500a;
  --info: #1f5f7a;
  --on-gain: #ffffff;
  --on-loss: #ffffff;
  /* 深底（報頭／hero／toast）上的漲跌色：兩套主題共用，日場的深色 gain/loss 在
     暗底上只有 2 點多的對比，直接沿用會看不見。 */
  --gain-on-dark: #3fae84;
  --loss-on-dark: #e06a5e;
  --masthead: #221e18;
  --masthead-ink: #ede7da;
  --masthead-muted: #a79c87;

  /* ---------- 相容層：既有變數名一個都不改名，只換值 ---------- */
  --canvas: var(--paper);
  --inset: var(--paper-sunk);
  --overlay: var(--sheet);
  --bg: var(--canvas);
  --bg-soft: var(--inset);
  --card: var(--overlay);
  --ink: var(--ink-1);
  --ink-soft: var(--ink-2);
  --ink-faint: var(--ink-3);
  --hairline: var(--rule-hair);
  --line: var(--hairline);
  --line-strong: var(--rule-strong);
  --brand: var(--brass);
  --primary: var(--brand);
  --primary-strong: var(--brass-deep);
  --primary-soft: var(--brass-wash);
  --up: var(--gain);
  --down: var(--loss);
  --amber: var(--caution);
  --warn: var(--amber);
  --blue: var(--info);
  --nav: var(--masthead);
  --nav-ink: var(--masthead-ink);
  --nav-muted: var(--masthead-muted);
  --sidebar-bg: linear-gradient(180deg, #2a241b 0%, #1a1610 100%);

  /* 市場配置色：色相與明度兩軸分離，六色排成明度階梯（相鄰 ≥ 1.26:1），
     不可只靠色相區分，圖例必須同時有色塊與中文市場名。 */
  --alloc-crypto: #a68423;
  --alloc-tw: #b9562c;
  --alloc-cash: #695f4f;
  --alloc-fund: #495126;
  --alloc-us: #523518;
  --alloc-uk: #451a17;

  --radius: 10px;
  --radius-sm: 6px;
  --radius-overlay: 14px;
  --control-h: 40px;

  /* ---------- 間距（4px 基數）---------- */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;
  --s7: 48px;
  --s8: 64px;

  /* ---------- 字級 ---------- */
  /* 字級用 rem（1rem = 瀏覽器根字級，預設 16px）：寫死 px 的話使用者在瀏覽器
     設定裡調大字級完全不會生效（只有整頁縮放有效）。渲染結果與原本的 px 值相同。 */
  --fs-micro: 0.6875rem;   /* 11px */
  --lh-micro: 1.5;
  --ls-micro: 0.08em;
  --fs-caption: 0.8125rem; /* 13px */
  --lh-caption: 1.6;
  --ls-caption: 0.01em;
  --fs-body: 1rem;         /* 16px */
  --lh-body: 1.7;
  --ls-body: 0;
  --fs-lead: 1.125rem;     /* 18px */
  --lh-lead: 1.65;
  --ls-lead: 0;
  --fs-h3: 1.25rem;        /* 20px */
  --lh-h3: 1.45;
  --ls-h3: -0.005em;
  --fs-h2: 1.625rem;       /* 26px */
  --lh-h2: 1.3;
  --ls-h2: -0.01em;
  --fs-h1: 2.125rem;       /* 34px */
  --lh-h1: 1.2;
  --ls-h1: -0.015em;
  --fs-display: 2.875rem;  /* 46px */
  --lh-display: 1.1;
  --ls-display: -0.02em;

  /* ---------- Elevation ----------
     陰影帶棕不用純黑：純黑在暖底上會發灰。 */
  --surface-1: var(--sheet);
  --surface-2: var(--sheet-raised);
  --surface-3: var(--sheet-top);
  --elev-1: 0 1px 2px rgba(58, 42, 20, 0.05), 0 1px 3px rgba(58, 42, 20, 0.04);
  --elev-2: 0 2px 4px rgba(58, 42, 20, 0.06), 0 8px 20px rgba(58, 42, 20, 0.07);
  --elev-3: 0 4px 10px rgba(58, 42, 20, 0.08), 0 18px 40px rgba(58, 42, 20, 0.14);
  --shadow: var(--elev-2);
  --shadow-sm: var(--elev-1);
  --shadow-lg: var(--elev-3);

  /* ---------- 焦點環 ----------
     內圈隔離帶 + 外圈黃銅的雙環，任何背景上都能達 3:1。 */
  --ring-color: var(--brass);

  /* ---------- 動效 ----------
     時長：微互動 150–300ms；退場 ≈ 進場的 60%，讓「離開」比「到達」更果斷。 */
  --dur-0: 90ms;
  --dur-1: 150ms;
  --dur-2: 220ms;
  --dur-3: 320ms;
  --dur-exit: 130ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-std: cubic-bezier(0.4, 0, 0.2, 1);
  --stagger: 40ms;

  /* 深底（側欄／報頭／行動版導覽）上的黃銅：日場的 --brass #835f13 對深墨底
     只有 2.85:1，深底一律改用夜場黃銅。兩套主題共用，studio 不必重複定義。 */
  --brass-on-dark: #d9a425;

  --font: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
    "PingFang TC", "Noto Sans TC", "Microsoft JhengHei", "Heiti TC",
    "Helvetica Neue", Arial, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo,
    Consolas, "Liberation Mono", "PingFang TC", "Microsoft JhengHei", monospace;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  overflow-x: hidden;
  max-width: 100%;
  overscroll-behavior-x: none;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  /* 本站數字密度遠高於長文：等寬數字全域預設開，排行榜與損益表才不會跳動。 */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* 股票代號／市場代碼走等寬，數字的 0 帶斜線、1 有襯腳，辨識度高。 */
.num,
.symbol,
.ticker,
.mono {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

.symbol,
.ticker,
.mono {
  font-family: var(--font-mono);
  letter-spacing: 0.02em;
}

/* 全站單一焦點環：內圈隔離帶 + 外圈黃銅，任何背景上都達 3:1。
   深色報頭區域內把主色反轉成亮黃銅，否則日場的深黃銅對 --nav 只有 2.85:1。 */
.sidebar,
.mobile-nav,
.toast {
  --ring-color: var(--brass-on-dark);
}

/* 焦點環用 outline 而不是 box-shadow。
   box-shadow 版本（`:where(...)` 只有 0,1,0 特異性）會被元件自己的 box-shadow 蓋掉：
   `.primary-button { box-shadow: none }` (0,1,0，源序在後)、`.nav-item.is-active`、
   `.auth-tab.is-active`、`.room-tab.is-active`、`.chat-react-btn.is-reacted`、
   `.emoji-select-btn.is-selected` 全都會贏，結果是最常被鍵盤操作的按鈕根本沒有焦點指示。
   outline 是沒有人會去設的獨立屬性，用它當不可被搶的底線；offset 產生的空隙由元素
   自己的背景填滿，等同雙環的隔離帶效果。 */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--ring-color);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.is-up {
  color: var(--up);
}

.is-down {
  color: var(--down);
}

.is-warn {
  color: var(--warn);
}

[hidden] {
  display: none !important;
}

button {
  font-family: inherit;
  cursor: pointer;
}

input,
select,
textarea {
  font-family: inherit;
  /* 不可低於 16px：iOS Safari 會在 focus 時自動放大整頁，放大後不會縮回來。 */
  font-size: var(--fs-body);
}

a {
  color: var(--primary);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* ---------- 文字流裡的 inline 圖示 ----------
   取代原本當圖示用的 emoji。刻意不寫成裸的 [data-icon] svg：那與既有的
   .icon-button svg / .heading-icon svg 特異性相同（0,1,1），誰寫在後面誰贏，
   會依檔案順序意外蓋掉既有尺寸。新用法一律加 class="inline-icon"。 */
.inline-icon {
  display: inline-flex;
  align-items: center;
  flex: none;
  vertical-align: -0.14em;
}

.inline-icon svg {
  width: 1.05em;
  height: 1.05em;
}

/* 狀態圓點（取代 🟢🔴🟡）：用 CSS 畫，不值得為了一個圓做一個 SVG。
   顏色一律 currentColor，語意由外層的 .is-up / .is-down / .is-warn 決定。 */
.inline-dot::before {
  content: "";
  display: inline-block;
  width: 0.55em;
  height: 0.55em;
  border-radius: 50%;
  margin-right: 0.4em;
  background: currentColor;
}

/* ===================== 整體骨架 ===================== */

.app-shell {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  width: 252px;
  position: fixed;
  inset: 0 auto 0 0;
  background: var(--sidebar-bg);
  color: var(--nav-ink);
  display: flex;
  flex-direction: column;
  padding: 16px 14px;
  /* 內容比視窗高時要能捲：1366x768 這種常見尺寸下，側欄原本是直接被切掉，
     最底下的版本／更新日誌按鈕整個落在畫面外，點不到也捲不到。 */
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
  z-index: 40;
  transition: transform 0.24s ease;
}

.main-content {
  flex: 1;
  min-width: 0;
  margin-left: 252px;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.page-content {
  padding: 26px 30px 60px;
  max-width: 1180px;
  width: 100%;
  margin: 0 auto;
}

/* ===================== 側欄 ===================== */

.brand {
  display: flex;
  align-items: center;
  gap: 11px;
  color: var(--nav-ink);
  text-decoration: none;
  padding: 2px 8px 10px;
  flex: none;
}

.brand:hover {
  text-decoration: none;
}

/* 報頭標記：兩根 K 線的自繪 monogram。深墨側欄上用亮黃銅描邊而非實心底
   —— 實心塊配光暈是舊主題的語彙，紙面／終端語言裡報頭應該是「刻上去的」。 */
.brand-mark {
  width: 38px;
  height: 38px;
  border-radius: var(--radius-sm);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--brass-on-dark) 55%, transparent);
  color: var(--brass-on-dark);
  font-size: 24px;
  font-weight: 800;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  box-shadow: none;
}

.brand strong {
  display: block;
  font-size: 16.5px;
  line-height: 1.25;
}

.brand small {
  display: block;
  color: var(--nav-muted);
  font-size: 11.5px;
}

.primary-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 4px;
  position: relative;
  /* 撐開剩餘高度，讓 .sidebar-footer 永遠貼在最底下 */
  flex: 1 0 auto;
}

/* 滑動藥丸：整個側欄只有這一個元素在動，換頁時它從舊項滑到新項，
   取代原本「底色瞬間從 A 跳到 B」的硬切。位置由 syncNavPill() 量測後寫成 CSS 變數
   （不能用 :nth-child 純 CSS 算：nav-label 夾在中間、admin 項是條件顯示、登出項行高不同）。 */
.primary-nav::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: var(--pill-h, 40px);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--brass-on-dark) 16%, transparent);
  box-shadow: inset 3px 0 0 var(--brass-on-dark);
  opacity: var(--pill-o, 0);
  transform: translateY(var(--pill-y, 0px));
  transition:
    transform var(--dur-2) var(--ease-out),
    height var(--dur-2) var(--ease-out),
    opacity var(--dur-1) var(--ease-out);
  pointer-events: none;
  z-index: 0;
}

/* 首次定位（或側欄剛展開）時不要從 y=0 滑過來。 */
.primary-nav.no-anim::after {
  transition: none;
}

.nav-label {
  margin: 7px 10px 3px;
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--nav-muted);
  text-transform: uppercase;
}

.nav-label:not(:first-of-type) {
  margin-top: 16px;
  padding-top: 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 7px 12px;
  /* 觸控下限明寫出來，不要靠內距與行高剛好湊到——側欄字級為了塞得下被調小過一次，
     下次再調就會無聲掉到 36px 以下。 */
  min-height: 36px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--nav-ink);
  font-size: 13.5px;
  text-align: left;
  transition: color var(--dur-1) var(--ease-out);
  /* 底色交給 .primary-nav::after 那顆滑動藥丸，item 本身只負責文字與圖示，
     所以必須浮在藥丸上方。 */
  position: relative;
  z-index: 1;
}

.nav-unread-badge {
  margin-left: auto;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--down);
  color: var(--on-loss);
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  box-shadow: 0 2px 6px color-mix(in srgb, var(--down) 45%, transparent);
  animation: pulse-badge 2s infinite ease-in-out;
}

.mobile-nav-icon-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.mobile-unread-badge {
  position: absolute;
  top: -4px;
  right: -8px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  border-radius: 8px;
  background: var(--down);
  color: var(--on-loss);
  font-size: 9.5px;
  font-weight: 700;
  line-height: 15px;
  text-align: center;
  box-shadow: 0 2px 5px color-mix(in srgb, var(--down) 50%, transparent);
  border: 1px solid var(--card);
}

@keyframes pulse-badge {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.08);
  }
}

.nav-item svg {
  width: 19px;
  height: 19px;
  opacity: 0.85;
}

.nav-item:hover {
  background: rgba(255, 255, 255, 0.07);
  color: var(--nav-ink);
}

.nav-item.is-active {
  background: transparent;
  color: var(--brass-on-dark);
  font-weight: 600;
  box-shadow: none;
  opacity: 1;
}

.nav-item.is-active::before {
  display: none;
}

.nav-item-logout {
  margin-top: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  padding-top: 12px;
  color: var(--loss-on-dark);
}

.nav-item-logout:hover {
  background: color-mix(in srgb, var(--down) 15%, transparent);
  color: color-mix(in srgb, var(--loss-on-dark) 75%, white);
}

.sidebar-footer {
  margin-top: auto;
  padding: 10px 8px 2px;
  flex: none;
}

.mini-tip {
  display: flex;
  gap: 10px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: var(--radius-sm);
  padding: 12px;
}

.tip-spark {
  color: var(--brass-on-dark);
  font-size: 16px;
  line-height: 1.3;
}

.mini-tip strong {
  display: block;
  color: var(--nav-ink);
  font-size: 13px;
}

.mini-tip small {
  display: block;
  color: var(--nav-muted);
  font-size: 11.5px;
  line-height: 1.5;
  margin-top: 2px;
}

.version-label {
  margin: 14px 8px 0;
  color: var(--nav-muted);
  font-size: 11px;
  letter-spacing: 0;
  background: none;
  border: none;
  padding: 4px 0;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  width: calc(100% - 16px);
}

.version-label:hover,
.version-label:focus-visible {
  color: var(--canvas);
  text-decoration: underline;
}

/* ===================== 頂欄 ===================== */

.workspace-head {
  position: sticky;
  top: 0;
  z-index: 30;
  background: color-mix(in srgb, var(--canvas) 92%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.topbar {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  background: transparent;
  border-bottom: 1px solid var(--line);
  padding: 12px 30px;
}

.breadcrumb {
  font-size: 13.5px;
  color: var(--ink-faint);
  display: flex;
  align-items: center;
  gap: 8px;
}

.breadcrumb i {
  font-style: normal;
  color: var(--line-strong);
}

.breadcrumb strong {
  color: var(--ink);
  font-weight: 600;
}

.topbar-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

.sync-state {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  color: var(--ink-soft);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 12px;
}

.sync-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--primary);
  flex: none;
}

.sync-state.is-pending .sync-dot {
  background: var(--amber);
  animation: pulse 1.1s ease-in-out infinite;
}

.sync-state.is-error {
  color: var(--down);
  border-color: color-mix(in srgb, var(--down) 35%, transparent);
}

.sync-state.is-error .sync-dot {
  background: var(--down);
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.icon-button {
  width: 38px;
  height: 38px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--card);
  color: var(--ink-soft);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.icon-button svg {
  width: 18px;
  height: 18px;
}

.icon-button:hover {
  background: var(--primary-soft);
  color: var(--primary);
  border-color: var(--brand);
}

.avatar {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 0;
  background: var(--brand);
  color: var(--on-brass);
  font-weight: 700;
  font-size: 15px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.mobile-menu {
  display: none;
  width: 38px;
  height: 38px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--ink-soft);
  align-items: center;
  justify-content: center;
}

.mobile-menu svg {
  width: 19px;
  height: 19px;
}

/* ===================== 頁面區塊 ===================== */

.page-view {
  display: none;
}

.page-view.is-active {
  display: block;
}

/* 進場動畫掛在 .is-page-enter，不掛在 .is-active。
   掛在 .is-active 的代價是：任何讓這條規則重新 match 的 class 變動都會讓瀏覽器
   把 page-enter 當成全新動畫再播一次。v1.0.40–v1.0.45 就是這樣——View Transitions
   結束後移除 html.is-vt，下面那條 animation: none 不再 match，剛落定的頁面立刻掉回
   opacity: 0 / translateY(10px) 再淡進來，每次換頁都抖一下。
   現在改成由 swapPageView() 明確決定誰要播：沒有 View Transitions 才加 .is-page-enter，
   有的話交給 ::view-transition-new(page-stage)，兩者永遠只有一個在演。 */
.page-view.is-page-enter {
  animation: page-enter var(--dur-2) var(--ease-out) both;
}

/* 進場：從下方 10px 推上來 + 淡入。10px 是刻意選小的——夠讀出「新內容到達」的方向，
   又不會在長頁面上像整頁在跳。只動 transform / opacity，兩者都在 compositor 上跑。
   用 transform: none 而非 translateY(0)：動畫結束後移除 transform，元素才不會一直是
   獨立合成層，也避免 position: fixed 的子孫被困在 containing block 裡。 */
@keyframes page-enter {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

@keyframes page-exit {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-4px); }
}

/* 舊名保留：專案其他地方仍在用 fadeIn。 */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* 轉場只作用在內容區：側欄與頂欄是「框」，不該跟著閃。 */
.page-content {
  view-transition-name: page-stage;
}

::view-transition-old(page-stage) {
  animation: page-exit var(--dur-exit) var(--ease-in) both;
}

::view-transition-new(page-stage) {
  animation: page-enter var(--dur-2) var(--ease-out) both;
}

/* 預設的 root 交叉淡出會讓整頁（含側欄）一起閃，關掉。 */
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

/* ===================== Skeleton 佔位 ===================== */

.skel {
  border-radius: var(--radius-sm);
  background: linear-gradient(
    90deg,
    var(--bg-soft) 25%,
    var(--line) 37%,
    var(--bg-soft) 63%
  );
  background-size: 400% 100%;
  /* 300ms 之前完全透明：資料很快回來時使用者不會看到骨架一閃而過（那比沒有骨架更糟）。
     用 animation-delay 做延遲，不用 setTimeout —— 專案規範禁止未清除的計時器。 */
  opacity: 0;
  animation:
    skel-appear var(--dur-1) var(--ease-out) 300ms both,
    skel-sweep 1400ms linear 300ms infinite;
}

@keyframes skel-appear {
  to { opacity: 1; }
}

/* 用 background-position 掃描而不是 opacity 脈動：前者讀成「載入中」，後者讀成「壞掉了」。 */
@keyframes skel-sweep {
  from { background-position: 100% 0; }
  to   { background-position: -100% 0; }
}

/* 尺寸要等於真實內容的高度，這是避免內容抵達時跳版的全部關鍵。 */
.skel-line { height: 14px; margin: 8px 0; }
.skel-line.is-short { width: 42%; }
.skel-title { height: 22px; width: 38%; margin: 0 0 12px; }
.skel-card { height: 128px; margin-bottom: var(--s3); }
.skel-row { height: 44px; margin-bottom: 6px; }

/* ===================== 列表 stagger ===================== */

/* 進場時依序浮現。上限 8 項：40ms × 8 = 320ms 尾延遲，加上 220ms 本體約 540ms 收尾，
   還在「一眼掃完」的範圍；超過 8 項的長尾會讀成卡頓，所以不再加延遲。

   閘門是 .is-entering 而不是 .is-active：.is-active 會一直掛著，30 秒自動刷新重繪
   列表時每張卡都是新元素，規則一 match 就再播一次整片 stagger——那是「畫面自己在抖」。
   .is-entering 只在「這次換頁進來」的期間有，由 swapPageView() 掛上、route() 跑完
   且動畫播完後由 endEntering() 收掉。

   排除 .skel：骨架有自己的延遲淡入與掃描動畫（.skel 的 specificity 比這裡低，
   不排除的話會被整條 animation 覆蓋掉，骨架就不掃描了）。 */
.page-view.is-entering.stagger-in > *:not(.skel),
.page-view.is-entering .stagger-in > *:not(.skel) {
  animation: stagger-item var(--dur-2) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

/* index 用 :nth-child() 靜態指派，上限 8；第 9 個以後全部吃 --i: 7。
   用 CSS 變數而不是在 JS 樣板字串裡插 style="--i:n"：後者會把「第幾個」寫進 HTML，
   連帶污染 renderIfChanged() 的內容指紋，列表一換順序就永遠判定為「有變」。 */
.stagger-in > *:nth-child(1) { --i: 0; }
.stagger-in > *:nth-child(2) { --i: 1; }
.stagger-in > *:nth-child(3) { --i: 2; }
.stagger-in > *:nth-child(4) { --i: 3; }
.stagger-in > *:nth-child(5) { --i: 4; }
.stagger-in > *:nth-child(6) { --i: 5; }
.stagger-in > *:nth-child(7) { --i: 6; }
.stagger-in > *:nth-child(n + 8) { --i: 7; }

@keyframes stagger-item {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.view-header {
  margin: 0 0 16px;
}

.welcome-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}

.eyebrow {
  margin: 0 0 4px;
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--primary);
  text-transform: none;
  font-weight: 600;
}

.welcome-row h1,
.view-header h1 {
  margin: 0;
  font-size: 24px;
  line-height: 1.3;
  letter-spacing: 0.01em;
  font-weight: 700;
}

.wave {
  color: var(--amber);
}

.page-subtitle {
  margin: 4px 0 0;
  color: var(--ink-soft);
  font-size: 14px;
}

.record-actions {
  display: flex;
  gap: 10px;
  flex: none;
}

/* ===================== 按鈕 ===================== */

.primary-button,
.secondary-button,
.outlined-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: var(--control-h);
  padding: 9px 16px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 600;
  border: 1px solid transparent;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
}

.primary-button {
  background: var(--brand);
  color: var(--on-brass);
  box-shadow: none;
}

.primary-button:hover {
  background: var(--primary-strong);
}

.primary-button:active,
.secondary-button:active,
.outlined-button:active {
  transform: translateY(1px);
}

.primary-button svg {
  width: 16px;
  height: 16px;
}

.secondary-button {
  background: var(--card);
  border-color: var(--line-strong);
  color: var(--ink);
}

.secondary-button:hover {
  background: var(--bg-soft);
  border-color: var(--line-strong);
}

.outlined-button {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--ink-soft);
  font-weight: 500;
}

.outlined-button:hover {
  background: var(--bg-soft);
  color: var(--ink);
}

/* ===================== 主數字帶（儀表板 A 區） =====================
   不包卡片、不置中：左對齊 + 大字 + 上下 hairline，就是「編輯感」的全部技術含量。
   原本這裡是兩張等寬卡（總資產卡 + 配置卡），主數字被卡片邊框框住、
   競賽的唯一量尺（純度 ROI）還被藏在 studio 專屬的隱藏元素裡。 */

.stage-band {
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  padding: var(--s5) 0;
  margin: 0 0 var(--s5);
}

.stage-band-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  flex-wrap: wrap;
}

.stage-band-meta {
  font-size: var(--fs-caption);
  color: var(--ink-faint);
  display: inline-flex;
  align-items: baseline;
  gap: var(--s1);
}

.stage-hello {
  color: var(--ink-soft);
}

.stage-sep {
  color: var(--ink-faint);
  opacity: 0.6;
  margin: 0 0.35em;
}

.stage-band-main {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s5);
  flex-wrap: wrap;
  margin: var(--s3) 0 var(--s4);
}

.stage-label {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--ink-soft);
  letter-spacing: 0.02em;
}

/* 主數字：正負由 .is-up / .is-down 上色，不加漸層、不加陰影、不加發光。 */
.stage-value {
  margin: 2px 0 0;
  font-size: clamp(2.75rem, 9vw, 4.5rem); /* 44–72px */
  line-height: 1.02;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  /* 黃銅在儀表板只出現這一次：數字底下一條短規尺線。 */
  border-bottom: 3px solid var(--brand);
  display: inline-block;
  padding-bottom: 2px;
}

.stage-sub {
  margin: var(--s2) 0 0;
  font-size: var(--fs-caption);
  color: var(--ink-faint);
}

.stage-aside {
  text-align: right;
  min-width: 200px;
  padding-bottom: var(--s1);
}

.stage-aside-label {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--ink-soft);
}

.stage-aside-value {
  margin: 2px 0 0;
  font-size: var(--fs-h3);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: var(--s1);
}

.stage-aside-value small {
  font-size: var(--fs-caption);
  font-weight: 500;
}

.stage-aside-note {
  margin: var(--s1) 0 0;
  font-size: var(--fs-micro);
  color: var(--ink-faint);
  line-height: 1.5;
  max-width: 34ch;
  margin-left: auto;
}

/* 次級統計是一整行句子，不是三張卡。 */
.stage-facts {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--ink-soft);
  line-height: 1.8;
}

.stage-facts strong {
  color: var(--ink);
  font-weight: 600;
}

.stage-faint {
  color: var(--ink-faint);
}

.stage-note {
  margin: var(--s2) 0 0;
  font-size: var(--fs-micro);
}

/* ===================== 配置 rail（儀表板 B 區） ===================== */

.alloc-rail {
  margin: 0 0 var(--s6);
}

.alloc-rail-label {
  margin: 0 0 var(--s2);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-micro);
  color: var(--ink-faint);
  text-transform: uppercase;
}

.alloc-rail .alloc-bar-wrap {
  margin: 0 0 var(--s2);
}

.alloc-rail .alloc-legend {
  margin-bottom: 0;
}

@media (max-width: 860px) {
  .stage-band-main {
    flex-direction: column;
    align-items: stretch;
    gap: var(--s3);
  }

  .stage-aside {
    text-align: left;
    min-width: 0;
  }

  .stage-aside-value {
    justify-content: flex-start;
  }

  .stage-aside-note {
    margin-left: 0;
  }

  .alloc-rail .alloc-legend {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s1) var(--s3);
  }
}

/* ===================== Hero 區 ===================== */

.hero-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 32px;
  margin-bottom: 24px;
  align-items: start;
}

.hero-card {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--sidebar-bg);
  color: var(--nav-ink);
  padding: 24px 26px;
  box-shadow: var(--shadow-lg);
}

.hero-card::after {
  content: "";
  display: block;
  position: absolute;
  right: -70px;
  top: -70px;
  width: 230px;
  height: 230px;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--brand) 35%, transparent), transparent 70%);
}

.hero-heading {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  letter-spacing: 0.04em;
  color: var(--nav-muted);
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.14);
  padding: 3px 10px;
  border-radius: 999px;
}

.status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--up);
  box-shadow: 0 0 8px color-mix(in srgb, var(--up) 80%, transparent);
}

.header-tools .status-pill,
.room-hero-card .status-pill,
.modal-header .status-pill {
  color: var(--ink-soft);
  background: var(--bg-soft);
  border: 1px solid var(--line);
}

.hero-label {
  margin: 18px 0 2px;
  font-size: 13px;
  color: var(--nav-muted);
  font-weight: 500;
}

.hero-value {
  margin: 0;
  font-size: clamp(28px, 4vw, 40px);
  font-weight: 800;
  letter-spacing: 0.01em;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}

.hero-caption {
  margin: 4px 0 0;
  color: var(--nav-muted);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

.hero-card .is-up {
  color: var(--gain-on-dark);
}

.hero-card .is-down {
  color: var(--loss-on-dark);
}

.hero-daily-pnl-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-top: 14px;
  flex-wrap: wrap;
}

.hero-daily-pnl-row span {
  font-size: 13px;
  color: var(--nav-muted);
}

.hero-daily-pnl-row strong {
  font-size: 18px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.hero-daily-pnl-row small {
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.hero-divider {
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
  margin: 18px 0 14px;
}

.hero-foot {
  display: flex;
  gap: 40px;
}

.hero-foot div span {
  display: block;
  font-size: 12px;
  color: var(--nav-muted);
}

.hero-foot strong {
  display: block;
  font-size: 18px;
  font-weight: 700;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}

/* 4% 目標卡 */

.quick-card {
  background: var(--card);
  border-radius: var(--radius);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  padding: 22px 24px;
  display: flex;
  flex-direction: column;
}

.card-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.card-heading h2 {
  margin: 0;
  font-size: 17px;
  line-height: 1.35;
}

.heading-icon {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--primary-soft);
  color: var(--primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 17px;
  flex: none;
}

.heading-icon svg {
  width: 19px;
  height: 19px;
}

.quick-text {
  margin: 14px 0 16px;
  color: var(--ink-soft);
  font-size: 14px;
  line-height: 1.75;
}

.quick-text b {
  color: var(--ink);
  font-size: 15px;
}

.inline-input {
  width: 62px;
  border: 0;
  border-bottom: 2px solid var(--line-strong);
  background: transparent;
  color: var(--ink);
  font-weight: 700;
  font-size: 14.5px;
  text-align: center;
  padding: 1px 2px;
  border-radius: 0;
}

/* 邊框與底色兩種焦點都要；只有 outline: none 限縮到非鍵盤焦點，
   否則會把全站的 focus ring 一起殺掉。 */
.inline-input:focus:not(:focus-visible) {
  outline: none;
}

.inline-input:focus {
  border-bottom-color: var(--primary);
}

.quick-metric {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 0;
  border-top: 1px solid var(--line);
}

.metric-icon {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  flex: none;
}

.metric-icon.income-icon {
  background: var(--primary-soft);
  color: var(--primary);
}

.metric-icon.investment-icon {
  background: var(--brass-wash);
  color: var(--amber);
}

.quick-metric small {
  display: block;
  font-size: 11.5px;
  color: var(--ink-faint);
}

.quick-metric strong {
  display: block;
  font-size: 15.5px;
  font-variant-numeric: tabular-nums;
}

/* ===================== 區塊標題 ===================== */

.section-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2);
  margin: var(--s6) 0 var(--s2);
  padding-bottom: var(--s1);
  border-bottom: 1px solid var(--hairline);
}

.section-heading h2 {
  margin: 0;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  font-weight: 600;
  /* 中文標題不套負字距：負值會讓方塊字黏在一起 */
  letter-spacing: 0;
}

.as-of {
  font-size: 12.5px;
  color: var(--ink-faint);
}

.filter-tabs {
  position: relative;
  display: inline-flex;
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 3px;
  gap: 2px;
}

/* 滑動指示器。用 transition 而不是 @keyframes —— transition 對「值沒有改變」是完全的
   no-op，這是房間分頁籤那幾組整段 innerHTML 重建時不重播動畫的根本保證。
   這裡的 width 確實是 layout 屬性，但 ::after 是 position: absolute 的孤立元素，
   改它不會讓任何兄弟或父層重排；而分頁籤寬度差很多（「本週」vs「本週即時戰況榜」），
   純 translateX 涵蓋不了，所以這是「不動 layout 屬性」的唯一豁免。 */
.filter-tabs::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 0;
  height: calc(100% - 6px);
  width: var(--tab-w, 0px);
  border-radius: 999px;
  background: var(--primary);
  opacity: var(--tab-o, 0);
  transform: translateX(var(--tab-x, 0px));
  transition:
    transform var(--dur-2) var(--ease-out),
    width var(--dur-2) var(--ease-out),
    opacity var(--dur-1) var(--ease-out);
  pointer-events: none;
  z-index: 0;
}

.filter-tabs.no-anim::after {
  transition: none;
}

.filter-tab {
  position: relative;
  z-index: 1;
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  font-size: 12.5px;
  padding: 5px 13px;
  border-radius: 999px;
  font-weight: 600;
  transition: color var(--dur-1) var(--ease-out);
}

/* 底色交給指示器，active 只改文字顏色。 */
.filter-tab.is-active {
  background: transparent;
  color: var(--on-brass);
}

/* 不在 .filter-tabs 容器裡的獨立分頁籤（房間清單、成就分頁等）沒有指示器可用，
   維持實心底色，否則會完全看不出哪個被選中。 */
:not(.filter-tabs) > .filter-tab.is-active {
  background: var(--primary);
}

.period-toggle-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
  background: var(--bg-soft);
  padding: 4px;
  border-radius: 12px;
  border: 1px solid var(--line-strong);
}

.period-toggle-wrap .filter-tab {
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  font-weight: 700;
  font-size: 13.5px;
}

.holdings-heading {
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 12px;
}

.holdings-filter-tabs {
  flex-wrap: wrap;
  max-width: 100%;
}

.order-budget-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}

.quick-cash-btns {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

.table-row-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
}

.chat-quick-tags {
  padding: 0;
  background: transparent;
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

/* ===================== 資產卡片 ===================== */

.cards-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* 紙面主題靠 hairline 分層，不靠陰影；陰影會讓整頁浮成一面「卡片牆」。 */
  box-shadow: none;
}

/* ===================== 總覽退休進度卡 ===================== */

.retire-card {
  padding: 20px 22px;
  margin-top: var(--s4);
  margin-bottom: var(--s5);
}

.retire-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2);
  margin-bottom: var(--s3);
  padding-bottom: var(--s2);
  border-bottom: 1px solid var(--hairline);
}

.retire-header h2 {
  margin: 0;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  font-weight: 600;
  color: var(--ink);
}

.retire-empty {
  padding: var(--s5) var(--s3);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s3);
}

.retire-empty p {
  color: var(--ink-soft);
  margin: 0;
  font-size: var(--fs-caption);
}

.retire-progress-wrap {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin: var(--s3) 0 var(--s4);
}

.retire-progress {
  flex: 1;
  height: 8px;
  border-radius: 999px;
  background: var(--bg-soft);
  overflow: hidden;
  position: relative;
}

.retire-progress-fill {
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: var(--primary);
  transition: width var(--dur-3) var(--ease-out);
}

.retire-progress-pct {
  font-size: var(--fs-caption);
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
  min-width: 44px;
  text-align: right;
}

.retire-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--s3);
}

.retire-cell {
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: var(--s3);
  background: var(--bg-soft);
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
}

.retire-label {
  font-size: var(--fs-caption);
  color: var(--ink-faint);
  margin: 0 0 var(--s1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.retire-value {
  font-size: var(--fs-lead);
  font-weight: 700;
  line-height: var(--lh-lead);
  color: var(--ink);
  margin: 0;
  font-variant-numeric: tabular-nums;
  word-break: break-word;
}

.retire-sub {
  font-size: var(--fs-micro);
  color: var(--ink-faint);
  margin: var(--s1) 0 0;
  line-height: var(--lh-micro);
}

.retire-sub:empty {
  display: none;
}

.asset-card {
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.asset-card:hover {
  border-color: var(--brand);
  box-shadow: none;
}

.asset-card.is-dim {
  opacity: 0.72;
}

.asset-main {
  display: flex;
  align-items: baseline;
  gap: 9px;
  flex-wrap: wrap;
  margin: 16px 0 6px;
}

.asset-qty {
  font-size: 13px;
  color: var(--ink-faint);
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 1px 8px;
  font-variant-numeric: tabular-nums;
}

.asset-price {
  font-size: 21px;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
}

.asset-change {
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

.asset-change.is-up {
  color: var(--up);
}

.asset-change.is-down {
  color: var(--down);
}

.asset-change.is-neutral {
  color: var(--ink-faint);
}

.asset-prev-close {
  font-size: 11.5px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.asset-value-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-top: 1px dashed var(--line-strong);
  padding-top: 10px;
  margin-top: auto;
}

.asset-value-row span {
  font-size: 12.5px;
  color: var(--ink-faint);
}

.asset-value-row strong {
  font-size: 17px;
  font-variant-numeric: tabular-nums;
}

.asset-note {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--ink-faint);
  line-height: 1.5;
}

.asset-list {
  margin-top: 10px;
  border-top: 1px dashed var(--line-strong);
}

.asset-list-row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: 10px;
  align-items: baseline;
  padding: 6px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.asset-list-row:last-child {
  border-bottom: 0;
}

.al-symbol {
  font-weight: 700;
}

.al-qty {
  color: var(--ink-soft);
  text-align: right;
}

.al-price {
  color: var(--ink-faint);
  text-align: right;
  min-width: 58px;
}

.al-value {
  text-align: right;
  min-width: 78px;
}

/* ===================== 歷史紀錄 ===================== */

.history-card {
  padding: 20px 22px;
}

.history-chart {
  width: 100%;
}

.history-chart svg {
  width: 100%;
  height: auto;
  display: block;
}

.empty-hint {
  margin: 0;
  padding: 34px 0;
  text-align: center;
  color: var(--ink-faint);
  font-size: 13.5px;
}

.history-table {
  margin-top: 14px;
  overflow-x: auto;
}

.history-chart-plot {
  position: relative;
}

/* 橫向拖曳用來逐筆查看，直向仍交給頁面捲動 */
.history-chart-plot svg {
  touch-action: pan-y;
  cursor: crosshair;
  border-radius: var(--radius-sm);
}

.history-chart-plot svg:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 4px;
}

.chart-value-label {
  fill: var(--ink-soft);
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  paint-order: stroke;
  stroke: var(--card);
  stroke-width: 3px;
  stroke-linejoin: round;
}

.chart-crosshair {
  stroke: var(--ink-faint);
  stroke-width: 1;
}

.chart-hover-dot {
  fill: var(--primary);
  stroke: var(--card);
  stroke-width: 2;
}

.chart-tooltip {
  position: absolute;
  z-index: 2;
  min-width: 168px;
  max-width: 240px;
  padding: 9px 12px;
  margin-left: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card);
  box-shadow: var(--shadow);
  pointer-events: none;
  font-variant-numeric: tabular-nums;
}

.chart-tooltip.is-flipped {
  margin-left: 0;
  transform: translateX(calc(-100% - 12px));
}

.chart-tooltip[hidden] {
  display: none;
}

.chart-tooltip-value {
  font-size: 15px;
  font-weight: 800;
  color: var(--ink);
}

.chart-tooltip-date {
  font-size: 12px;
  color: var(--ink-soft);
  margin-top: 1px;
}

.chart-tooltip-meta {
  font-size: 12px;
  color: var(--ink-faint);
  margin-top: 4px;
}

/* 窄螢幕：提示框改放在圖表下方，不蓋住折線 */
@media (max-width: 640px) {
  .chart-tooltip,
  .chart-tooltip.is-flipped {
    position: static;
    margin: 8px 0 0;
    max-width: none;
    transform: none;
  }
}

.history-table-details {
  margin-top: 12px;
}

.history-table-details summary {
  cursor: pointer;
  width: fit-content;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
  padding: 4px 0;
}

.history-table-details[hidden] {
  display: none;
}

/* ===================== 圖表 SVG ===================== */

.grid-line {
  stroke: var(--line);
  stroke-width: 1;
  stroke-dasharray: 3 4;
}

.axis-label {
  fill: var(--ink-faint);
  font-size: 11px;
}

.chart-area {
  fill: color-mix(in srgb, var(--brand) 12%, transparent);
}

.chart-line {
  fill: none;
  stroke: var(--primary);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.roi-line {
  fill: none;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.chart-dot {
  fill: var(--primary);
  stroke: var(--overlay);
  stroke-width: 2;
}

.target-line {
  fill: none;
  stroke: var(--amber);
  stroke-width: 2;
  stroke-dasharray: 7 5;
}

.retire-line {
  stroke: var(--blue);
  stroke-width: 2;
  stroke-dasharray: 5 5;
}

.retire-label {
  fill: var(--blue);
  font-size: 12px;
  font-weight: 700;
}

.chart-legend {
  display: flex;
  gap: 18px;
  margin-bottom: 8px;
  font-size: 12px;
  color: var(--ink-soft);
}

.legend-line::before,
.legend-dash::before {
  content: "";
  display: inline-block;
  width: 20px;
  height: 3px;
  border-radius: 2px;
  margin-right: 6px;
  vertical-align: middle;
}

.legend-line::before {
  background: var(--primary);
}

.legend-dash::before {
  background: repeating-linear-gradient(90deg, var(--amber) 0 6px, transparent 6px 10px);
}

.market-code {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
}

.market-btn.is-active .market-code {
  color: inherit;
  opacity: 0.85;
}

/* 表格裡的標的欄：代碼用等寬、名稱降一級壓在下面，一格裝兩層資訊。 */
.holding-sym {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  font-weight: 600;
}

.holding-name {
  display: block;
  font-size: var(--fs-micro);
  color: var(--ink-faint);
  font-weight: 400;
  margin-top: 1px;
}

/* 桌機不出現水平捲軸：欄位擠了就隱藏次要欄，不橫捲。 */
@media (max-width: 1180px) and (min-width: 861px) {
  .col-optional {
    display: none;
  }
}

/* ===================== 表格 ===================== */

.history-table table,
.table-card table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
}

.history-table th,
.table-card th {
  text-align: left;
  font-size: 12px;
  letter-spacing: 0.05em;
  color: var(--ink-faint);
  font-weight: 600;
  padding: 8px 12px;
  border-bottom: 2px solid var(--line);
  white-space: nowrap;
}

.history-table td,
.table-card td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.history-table tr:last-child td,
.table-card tr:last-child td {
  border-bottom: 0;
}

.history-table tbody tr:hover,
.table-card tbody tr:hover {
  background: var(--bg-soft);
}

/* ===================== 匯率統整 ===================== */

.fx-summary-card {
  padding: 22px 24px;
}

.fx-chart-card {
  padding: 22px 24px 20px;
  margin-bottom: 18px;
}

.fx-chart-heading {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
}

.fx-chart-heading h2 {
  margin: 4px 0 0;
  font-size: 20px;
}

.fx-chart-subtitle {
  margin: 5px 0 0;
  color: var(--ink-soft);
  font-size: 13px;
}

.fx-chart-selector {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 190px;
}

.fx-chart-selector label {
  color: var(--ink-faint);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.fx-chart-select {
  min-height: 38px;
  padding: 7px 32px 7px 11px;
  border: 1px solid var(--line-strong);
  border-radius: 9px;
  background: var(--bg-soft);
  color: var(--ink);
  font-weight: 700;
}

/* 只留邊框變色；outline 交給全站的焦點環，
   原本這裡用 20% 透明的黃銅（約 1.5:1）把它蓋掉了。 */
.fx-chart-select:focus {
  border-color: var(--primary);
}

.fx-chart-select:disabled {
  cursor: not-allowed;
  opacity: 0.7;
}

.fx-chart {
  margin-top: 20px;
}

.fx-chart-canvas {
  min-width: 0;
  overflow: hidden;
  padding: 12px 10px 0 0;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: linear-gradient(180deg, var(--inset) 0%, var(--overlay) 100%);
}

.fx-chart-svg {
  display: block;
  width: 100%;
  height: auto;
  min-height: 260px;
}

.fx-chart-grid {
  stroke: var(--line);
  stroke-width: 1;
  stroke-dasharray: 3 5;
}

.fx-chart-axis-label {
  fill: var(--ink-faint);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.fx-chart-area {
  fill: color-mix(in srgb, var(--brand) 10%, transparent);
}

.fx-chart-line {
  fill: none;
  stroke: var(--primary);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.fx-chart-point {
  stroke: var(--overlay);
  stroke-width: 2;
}

.fx-chart-point.is-current {
  fill: var(--primary);
  filter: drop-shadow(0 2px 3px color-mix(in srgb, var(--brand) 25%, transparent));
}

.fx-chart-point.is-high {
  fill: var(--amber);
}

.fx-chart-point.is-low {
  fill: var(--down);
}

.fx-chart-summary {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-top: 14px;
}

.fx-chart-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-soft);
}

.fx-chart-stat span {
  color: var(--ink-faint);
  font-size: 11.5px;
  font-weight: 600;
}

.fx-chart-stat small {
  color: var(--ink-faint);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.fx-chart-stat strong {
  font-size: 16px;
  font-variant-numeric: tabular-nums;
}

.fx-chart-stat.is-current {
  border-color: color-mix(in srgb, var(--brand) 28%, transparent);
  background: var(--primary-soft);
}

.fx-chart-stat.is-current strong {
  color: var(--primary-strong);
}

.fx-chart-stat.is-high strong {
  color: var(--amber);
}

.fx-chart-stat.is-low strong {
  color: var(--down);
}

.fx-chart-reading {
  margin: 13px 0 0;
  color: var(--ink-soft);
  font-size: 13px;
}

.fx-chart-reading strong {
  color: var(--ink);
}

.fx-chart-reading.is-high strong:nth-of-type(2) {
  color: var(--amber);
}

.fx-chart-reading.is-low strong:nth-of-type(2) {
  color: var(--down);
}

.fx-chart-reading.is-flat strong:nth-of-type(2),
.fx-chart-reading.is-mid strong:nth-of-type(2) {
  color: var(--primary-strong);
}

.fx-summary-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.fx-table-wrap {
  overflow-x: auto;
}

.fx-table-wrap table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
}

.fx-table-wrap th {
  text-align: left;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  font-weight: 600;
  padding: 10px 12px;
  border-bottom: 2px solid var(--line);
  white-space: nowrap;
}

.fx-table-wrap td {
  padding: 12px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.fx-table-wrap tr:last-child td {
  border-bottom: 0;
}

.fx-table-wrap tbody tr:hover {
  background: var(--bg-soft);
}

.fx-table-wrap td:first-child {
  min-width: 110px;
}

.fx-table-wrap td small {
  display: block;
  color: var(--ink-faint);
  font-size: 11.5px;
  margin-top: 2px;
}

.fx-rate-row.is-unavailable {
  opacity: 0.58;
}

.fx-data-note {
  margin-top: 14px;
}

/* ===================== 重大市場新聞 ===================== */

.section-link {
  color: var(--primary-strong);
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
}

.market-news-card {
  padding: 20px 22px;
}

.news-page-card {
  padding: 22px 24px;
}

.market-news-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.news-filter-tabs {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.news-filter-tab {
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--card);
  color: var(--ink-soft);
  padding: 5px 12px;
  font-size: 12.5px;
  font-weight: 700;
  transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}

.news-filter-tab:hover {
  border-color: var(--primary);
  color: var(--primary-strong);
}

.news-filter-tab.is-active {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-brass);
}

.market-news-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.market-news-item {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr) auto;
  align-items: start;
  gap: 16px;
  min-width: 0;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--bg-soft);
  transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

.market-news-item:hover {
  border-color: var(--line-strong);
  background: var(--card);
  box-shadow: var(--shadow);
}

.news-score-block {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 2px;
  color: var(--ink-faint);
  line-height: 1;
}

.news-score-block strong {
  font-size: 1.38rem;
  font-weight: 800;
  color: var(--ink-soft);
}

.news-score-block span {
  font-size: 11px;
}

.news-score-block small {
  flex-basis: 100%;
  margin-top: 5px;
  font-size: 10px;
  color: var(--ink-faint);
}

.news-item-body {
  min-width: 0;
}

.news-item-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  color: var(--ink-faint);
  font-size: 11.5px;
}

.news-category-badge {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 2px 8px;
  background: color-mix(in srgb, var(--brand) 10%, transparent);
  color: var(--primary-strong);
  font-size: 11px;
  font-weight: 700;
}

/* 分層徽章：總經與政策永遠排在最前面，顏色要一眼認得出層級 */
.news-tier-badge {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 700;
  background: color-mix(in srgb, var(--ink-faint) 12%, transparent);
  color: var(--ink-soft);
}

.news-tier-badge.news-tier-1 {
  background: color-mix(in srgb, var(--down) 12%, transparent);
  color: var(--down);
}

.news-tier-badge.news-tier-2 {
  background: color-mix(in srgb, var(--warn) 12%, transparent);
  color: var(--warn);
}

.news-tier-badge.news-tier-3 {
  background: color-mix(in srgb, var(--blue) 12%, transparent);
  color: var(--blue);
}

.news-item-title {
  margin: 5px 0 3px;
  color: var(--ink);
  font-size: 1rem;
  line-height: 1.45;
  transition: color 0.15s ease, text-shadow 0.15s ease;
}

.news-item-body a:hover {
  text-decoration: none;
}

.news-item-body a:hover .news-item-title {
  color: var(--primary-strong);
}

.news-item-summary {
  display: -webkit-box;
  overflow: hidden;
  margin: 0;
  color: var(--ink-soft);
  font-size: 13px;
  line-height: 1.55;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}

.news-source-link {
  align-self: center;
  color: var(--ink-faint);
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
}

.news-source-link:hover {
  color: var(--primary-strong);
}

.market-news-item.news-score-critical {
  border-color: var(--hairline);
  background: transparent;
  box-shadow: none;
}

.news-score-critical .news-score-block strong {
  color: var(--down);
  text-shadow: none;
}

.news-score-critical .news-item-title {
  color: var(--ink);
  font-size: 13px;
  font-weight: 700;
  text-shadow: none;
}

.market-news-item.news-score-high {
  border-color: color-mix(in srgb, var(--warn) 30%, transparent);
}

.news-score-high .news-score-block strong {
  color: var(--warn);
  text-shadow: 0 0 10px color-mix(in srgb, var(--warn) 22%, transparent);
}

.news-score-high .news-item-title {
  color: var(--warn);
  font-size: 1.05rem;
  font-weight: 750;
}

.news-score-medium .news-score-block strong {
  color: var(--blue);
}

.news-score-low {
  opacity: 0.86;
}

/* ===================== 計算機 ===================== */

.calc-layout {
  display: grid;
  grid-template-columns: 330px 1fr;
  gap: 22px;
  align-items: start;
}

.calc-form {
  padding: 22px 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  position: sticky;
  top: 78px;
}

.calc-field label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
  margin-bottom: 5px;
}

.calc-field input {
  width: 100%;
  min-height: var(--control-h);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  background: var(--bg-soft);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  transition: border-color 0.15s ease, background 0.15s ease;
}

/* 邊框與底色兩種焦點都要；只有 outline: none 限縮到非鍵盤焦點，
   否則會把全站的 focus ring 一起殺掉。 */
.calc-field input:focus:not(:focus-visible) {
  outline: none;
}

.calc-field input:focus {
  border-color: var(--primary);
  background: var(--card);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 12%, transparent);
}

.calc-actions {
  display: flex;
  gap: 10px;
  margin-top: 4px;
}

.calc-actions .primary-button,
.calc-actions .secondary-button {
  flex: 1;
}

.calc-results {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.result-summary {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px 24px;
}

.result-summary h2 {
  margin: 0 0 10px;
  font-size: 17px;
}

.result-summary p {
  margin: 6px 0;
  font-size: 14.5px;
  color: var(--ink-soft);
}

.result-summary .highlight {
  color: var(--primary-strong);
  font-weight: 800;
  font-size: 16px;
  font-variant-numeric: tabular-nums;
}

.result-note {
  font-size: 12.5px !important;
  color: var(--ink-faint) !important;
  margin-left: 26px !important;
}

.chart-card,
.table-card {
  padding: 20px 22px;
}

.chart-card svg {
  width: 100%;
  height: auto;
  display: block;
}

.wide-table-card {
  overflow-x: auto;
}

.highlight-row td {
  background: var(--primary-soft) !important;
}

.highlight-row .highlight {
  color: var(--primary-strong);
  font-weight: 800;
}

.retired-section td {
  background: var(--inset);
}

td.muted,
.muted {
  color: var(--ink-faint);
  font-weight: 500;
}

/* ===================== 設定頁 ===================== */

/* 最多兩欄：四張小卡剛好 2×2；可用寬度不到兩張 300px 時自動收成一欄。
   同一排的卡片拉成等高，底邊才會對齊。 */
.settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(max(300px, calc((100% - 24px) / 2)), 1fr));
  gap: 24px;
  align-items: stretch;
}

.settings-card {
  padding: 22px 24px;
}

/* 內容比一般設定卡高很多的卡（外部連結、管理員）獨佔一整排，不去撐高隔壁卡。 */
.settings-card-wide {
  grid-column: 1 / -1;
}

/* 標題與右上角的圖示同一列。原本沒有 flex，窄卡片時圖示會掉到標題底下自成一行。 */
.settings-card-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s2);
  margin-bottom: var(--s2);
}

.settings-card-heading h2 {
  margin: 0;
  font-size: 17px;
}

.setting-rows {
  display: flex;
  flex-direction: column;
}

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}

.setting-row:last-child {
  border-bottom: 0;
}

.setting-row strong {
  display: block;
  font-size: 14px;
}

.setting-row small {
  display: block;
  color: var(--ink-faint);
  font-size: 12px;
  margin-top: 1px;
}

.setting-value {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  flex: none;
  font-variant-numeric: tabular-nums;
}

.setting-value.is-ok {
  color: var(--primary-strong);
}

.settings-footnote {
  margin: 14px 0 0;
  font-size: 12.5px;
  color: var(--ink-faint);
  line-height: 1.6;
}

.settings-footnote code {
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1px 6px;
  font-size: 12px;
  color: var(--primary-strong);
}

.settings-actions {
  display: flex;
  gap: 10px;
  margin-top: 16px;
  flex-wrap: wrap;
}

/* ===================== 行動版底部導覽 ===================== */

.mobile-nav {
  display: none;
}

/* ===================== 登入閘門 ===================== */

.auth-gate {
  position: fixed;
  inset: 0;
  z-index: 100;
  background:
    radial-gradient(1000px 500px at 85% -10%, color-mix(in srgb, var(--brand) 22%, transparent), transparent 60%),
    radial-gradient(800px 500px at -10% 110%, color-mix(in srgb, var(--blue) 14%, transparent), transparent 55%),
    var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.auth-card {
  width: 100%;
  max-width: 420px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: var(--shadow-lg);
  padding: 32px 34px;
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 22px;
}

.auth-brand strong {
  display: block;
  font-size: 17px;
}

.auth-brand small {
  display: block;
  color: var(--ink-faint);
  font-size: 12px;
}

.auth-card h1 {
  margin: 0 0 6px;
  font-size: 22px;
}

.auth-lead {
  margin: 0 0 18px;
  color: var(--ink-soft);
  font-size: 13.5px;
  line-height: 1.65;
}

.auth-tabs {
  display: flex;
  background: var(--bg-soft);
  border: 1px solid var(--line-strong);
  border-radius: 11px;
  padding: 4px;
  gap: 4px;
  margin-bottom: 18px;
}

.auth-tab {
  flex: 1;
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: 600;
  padding: 8px 0;
  border-radius: 8px;
}

.auth-tab.is-active {
  background: var(--card);
  color: var(--primary-strong);
  box-shadow: 0 1px 4px color-mix(in srgb, var(--nav) 10%, transparent);
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.form-field span {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-soft);
  margin-bottom: 5px;
}

.form-field input {
  width: 100%;
  min-height: var(--control-h);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font-size: 14.5px;
  background: var(--bg-soft);
  transition: border-color 0.15s ease, background 0.15s ease;
}

/* 邊框與底色兩種焦點都要；只有 outline: none 限縮到非鍵盤焦點，
   否則會把全站的 focus ring 一起殺掉。 */
.form-field input:focus:not(:focus-visible) {
  outline: none;
}

.form-field input:focus {
  border-color: var(--primary);
  background: var(--card);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 12%, transparent);
}

.auth-submit {
  margin-top: 6px;
  width: 100%;
  padding: 11px 0;
  font-size: 15px;
}

.auth-error {
  margin: 14px 0 0;
  min-height: 20px;
  color: var(--down);
  font-size: 13px;
  text-align: center;
}

/* ===================== Toast ===================== */

.toast {
  position: fixed;
  left: 50%;
  bottom: 34px;
  transform: translate(-50%, 16px);
  background: var(--nav);
  color: var(--nav-ink);
  font-size: 13.5px;
  padding: 10px 20px;
  border-radius: 999px;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease, transform 0.22s ease;
  z-index: 200;
  max-width: min(92vw, 520px);
  text-align: center;
}

.toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ===================== 好友週榜 & 模擬交易 樣式 ===================== */

.metrics-3-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.stat-card {
  padding: 20px 22px;
}

.stat-label {
  font-size: 13px;
  color: var(--ink-faint);
  margin-bottom: 6px;
}

.stat-value {
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 4px;
  font-variant-numeric: tabular-nums;
}

.stat-caption {
  font-size: 12.5px;
  color: var(--ink-faint);
  margin: 0;
}

.friend-actions-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  margin-bottom: 24px;
  gap: 16px;
  flex-wrap: wrap;
}

.inline-form {
  display: flex;
  gap: 10px;
  flex: 1;
  max-width: 460px;
}

.inline-form input {
  flex: 1;
  padding: 9px 14px;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  font-size: 14px;
}

.podium-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px;
  margin-bottom: 28px;
}

.podium-card {
  padding: 24px 20px;
  border-radius: 18px;
  text-align: center;
  position: relative;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.podium-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 24px rgba(58, 42, 20, 0.06);
}

.podium-1 {
  border: 2px solid var(--brand);
  background: linear-gradient(180deg, color-mix(in srgb, var(--brand) 8%, transparent) 0%, var(--card) 100%);
}

.podium-2 {
  border: 2px solid var(--line-strong);
  background: linear-gradient(180deg, color-mix(in srgb, var(--line-strong) 8%, transparent) 0%, var(--card) 100%);
}

.podium-3 {
  border: 2px solid color-mix(in srgb, var(--brand) 55%, var(--hairline));
  background: linear-gradient(180deg, color-mix(in srgb, var(--warn) 8%, transparent) 0%, var(--card) 100%);
}

.podium-rank-badge {
  display: inline-block;
  font-size: 28px;
  line-height: 1;
  margin-bottom: 8px;
}

.podium-username {
  font-size: 18px;
  font-weight: 700;
  margin: 0 0 8px;
}

.badge-roi {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.25;
  font-variant-numeric: tabular-nums;
}

.badge-roi.positive {
  background: color-mix(in srgb, var(--up) 12%, transparent);
  color: var(--up);
  border: 1px solid color-mix(in srgb, var(--up) 28%, transparent);
}

.badge-roi.negative {
  background: color-mix(in srgb, var(--down) 12%, transparent);
  color: var(--down);
  border: 1px solid color-mix(in srgb, var(--down) 28%, transparent);
}

.badge-roi.neutral {
  background: color-mix(in srgb, var(--line-strong) 12%, transparent);
  color: var(--ink-soft);
  border: 1px solid color-mix(in srgb, var(--line-strong) 28%, transparent);
}

/* 皇冠榮譽徽章 Crown Badge */
.crown-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 35%, transparent);
  color: var(--brand);
  font-size: 11.5px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 4px;
  margin-left: 6px;
  vertical-align: middle;
}

.crown-hall-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.crown-hall-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  box-shadow: var(--shadow);
}

.badge-sold {
  font-size: 12px;
  color: var(--ink-faint);
  margin-top: 6px;
}

.podium-meta {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  color: var(--ink-faint);
}

.trading-layout {
  display: grid;
  /* minmax(0, 1fr) 而不是 1fr：grid item 的 min-width 預設是 auto，
     裡面那張持倉表就會把整欄撐出容器外（1440px 下溢出 175px）。 */
  grid-template-columns: 380px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
  margin-bottom: 32px;
}

.market-selector {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin: 14px 0 16px;
}

.market-btn {
  padding: 9px 8px;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s ease;
}

.market-btn.is-active {
  background: var(--brand);
  color: var(--on-brass);
  border-color: var(--brand);
}

.quote-search-row {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
}

.quote-search-row input {
  flex: 1;
  padding: 9px 12px;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  font-size: 14px;
}

.quote-preview-box {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 14px;
  margin-bottom: 16px;
}

.quote-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.quote-sym-tag {
  display: inline-block;
  font-size: 11px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--line);
  color: var(--ink-faint);
  margin-left: 6px;
}

.quote-price {
  font-size: 18px;
  font-weight: 700;
}

.quote-change {
  font-size: 12.5px;
  font-weight: 600;
  margin-left: 6px;
}

.quote-prev-close {
  font-size: 11.5px;
  color: var(--ink-faint);
  margin-left: 6px;
  font-weight: normal;
  font-variant-numeric: tabular-nums;
}

.quote-footer {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  color: var(--ink-faint);
  border-top: 1px dashed var(--line);
  padding-top: 8px;
}

.quote-nav-note {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--ink-faint);
  line-height: 1.45;
}

.action-switch {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 16px;
}

.action-btn {
  padding: 10px;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  font-size: 13.5px;
  font-weight: 700;
  cursor: pointer;
  transition: all 0.15s ease;
}

.action-btn.is-buy.is-active {
  background: var(--up);
  color: var(--on-gain);
  border-color: var(--up);
}

.action-btn.is-sell.is-active {
  background: var(--down);
  color: var(--on-loss);
  border-color: var(--down);
}

.order-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 14px;
}

.order-preview-card {
  background: var(--bg);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 16px;
  font-size: 13px;
}

.preview-row {
  display: flex;
  justify-content: space-between;
  margin-bottom: 4px;
}

.preview-row:last-child {
  margin-bottom: 0;
}

.full-width {
  width: 100%;
}

.friend-modal-gate {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  padding: 16px;
  backdrop-filter: blur(4px);
}

.friend-modal-card {
  background: var(--card);
  border-radius: 20px;
  max-width: 640px;
  width: 100%;
  padding: 26px;
  box-shadow: 0 20px 40px rgba(58, 42, 20, 0.25);
  max-height: 90vh;
  overflow-y: auto;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 20px;
}

.modal-header h2 {
  margin: 6px 0 0;
  font-size: 20px;
}

.changelog-modal-card {
  max-width: 560px;
}

.changelog-content {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.changelog-release {
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--bg-soft);
}

.changelog-release.is-current {
  border-color: color-mix(in srgb, var(--brand) 35%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--brand) 12%, transparent);
}

.changelog-release-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}

.changelog-release-head strong {
  font-size: 16px;
  color: var(--ink);
}

.changelog-release-head time {
  font-size: 12px;
  color: var(--ink-faint);
}

.changelog-lead {
  margin: 0 0 10px;
  font-size: 13.5px;
  color: var(--ink-soft);
  line-height: 1.55;
}

.changelog-release ul {
  margin: 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.changelog-release li {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink);
}

.alloc-bar-wrap {
  height: 14px;
  border-radius: 7px;
  overflow: hidden;
  display: flex;
  /* 段與段之間留 2px 的頁底色當分隔：六色是同色相的明度階梯，相鄰只有 1.26–1.35:1，
     直接貼合時右半邊那幾段深棕在小尺寸下會連成一塊。加了分隔每段對分隔線 ≥ 3.26:1。 */
  gap: 2px;
  background: var(--overlay);
  margin: 12px 0 16px;
}

/* 顏色不得單獨承載語意（SC 1.4.1）：每段再疊一層 pattern，
   色弱、單色列印與夜場的低相鄰對比都還讀得出來。pattern 用 CSS 畫，不需要圖檔。 */
.alloc-seg-cash,
.alloc-seg-tw,
.alloc-seg-us,
.alloc-seg-uk,
.alloc-seg-crypto,
.alloc-seg-fund {
  transition: width var(--dur-3) var(--ease-out);
  background-repeat: repeat;
}

.alloc-seg-cash {
  background-color: var(--alloc-cash);
  background-image: repeating-linear-gradient(
    90deg,
    color-mix(in srgb, var(--canvas) 55%, transparent) 0 1px,
    transparent 1px 4px
  );
}

.alloc-seg-tw {
  background-color: var(--alloc-tw);
  background-image: repeating-linear-gradient(
    0deg,
    color-mix(in srgb, var(--canvas) 45%, transparent) 0 1px,
    transparent 1px 5px
  );
}

.alloc-seg-us {
  background-color: var(--alloc-us);
  background-image: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, var(--canvas) 40%, transparent) 0 2px,
    transparent 2px 6px
  );
}

.alloc-seg-uk {
  background-color: var(--alloc-uk);
  background-image:
    repeating-linear-gradient(45deg, color-mix(in srgb, var(--canvas) 34%, transparent) 0 1px, transparent 1px 5px),
    repeating-linear-gradient(-45deg, color-mix(in srgb, var(--canvas) 34%, transparent) 0 1px, transparent 1px 5px);
}

.alloc-seg-crypto {
  background-color: var(--alloc-crypto);
  background-image: radial-gradient(
    color-mix(in srgb, var(--ink) 38%, transparent) 1px,
    transparent 1px
  );
  background-size: 5px 5px;
}

.alloc-seg-fund {
  background-color: var(--alloc-fund);
  background-image: repeating-linear-gradient(
    45deg,
    color-mix(in srgb, var(--canvas) 38%, transparent) 0 2px,
    transparent 2px 7px
  );
}

.alloc-legend {
  display: flex;
  gap: 16px;
  font-size: 12.5px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.alloc-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 4px;
}

.alloc-dot-cash { background: var(--alloc-cash); }
.alloc-dot-tw { background: var(--alloc-tw); }
.alloc-dot-us { background: var(--alloc-us); }
.alloc-dot-uk { background: var(--alloc-uk); }
.alloc-dot-crypto { background: var(--alloc-crypto); }
.alloc-dot-fund { background: var(--alloc-fund); }

.alloc-chip-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* 全部持倉配置清單：股票名稱／占比／報酬三欄固定順序 */
.alloc-table-wrap {
  overflow-x: auto;
}

.alloc-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}

.alloc-table th {
  text-align: left;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-faint);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.alloc-table td {
  padding: 10px 12px;
  border-radius: 0;
  background: var(--bg);
  border-bottom: 2px solid var(--card);
}

.alloc-table td.alloc-col-name {
  border-top-left-radius: 10px;
  border-bottom-left-radius: 10px;
}

.alloc-table td.alloc-col-roi {
  border-top-right-radius: 10px;
  border-bottom-right-radius: 10px;
}

.alloc-table th.alloc-col-weight,
.alloc-table td.alloc-col-weight,
.alloc-table th.alloc-col-roi,
.alloc-table td.alloc-col-roi {
  text-align: right;
  white-space: nowrap;
}

.alloc-table td.alloc-col-weight {
  font-weight: 700;
}

.alloc-table .holding-company-name {
  margin-left: 6px;
  font-size: 12px;
  color: var(--ink-faint);
}

/* 玩家檔案的稱號牆 */
.profile-title-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.profile-title-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--chip-color, var(--brand));
  border: 1px solid color-mix(in srgb, var(--chip-color, var(--brand)) 35%, transparent);
  background: color-mix(in srgb, var(--chip-color, var(--brand)) 10%, transparent);
}

.profile-title-chip.is-equipped {
  border-width: 2px;
  box-shadow: 0 1px 3px rgba(58, 42, 20, 0.08);
}

.sold-best-box {
  margin-top: 20px;
  padding: 14px;
  border-radius: 12px;
  background: var(--brass-wash);
  border: 1px solid color-mix(in srgb, var(--brand) 40%, transparent);
  color: var(--primary-strong);
  font-size: 13.5px;
}



/* ===================== 定期定額 (DCA) 與 交易微調樣式 ===================== */

.dca-card {
  padding: 24px 28px;
  margin-bottom: 32px;
  border-radius: var(--radius);
}

.dca-top-row {
  margin-bottom: 18px;
}

.dca-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

.dca-fields input,
.dca-fields select {
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--card);
  font-size: 14px;
  min-height: 42px;
}

.dca-fields input {
  flex: 1 1 160px;
}

.dca-fields select {
  flex: 0 0 auto;
}

.dca-list-wrap {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 14px;
}

.dca-plan-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 18px;
  background: var(--bg);
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  font-size: 14px;
}

.dca-plan-info strong {
  font-size: 15px;
  color: var(--ink);
}

.dca-plan-info small {
  display: block;
  color: var(--ink-faint);
  margin-top: 2px;
}

.dca-plan-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* 微調彈窗樣式 */
.adjust-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.adjust-info-box {
  padding: 12px 16px;
  background: var(--bg);
  border-radius: var(--radius-sm);
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 600;
}

.adjust-fields-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.adjust-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 10px;
}

.cards-grid {
  gap: 20px;
  margin-bottom: 24px;
}

.stat-value {
  font-size: 26px;
  margin: 10px 0 6px;
}

.trading-layout {
  display: grid;
  grid-template-columns: 440px minmax(0, 1fr);
  gap: 28px;
  margin-bottom: 36px;
}

/* 1280px 以下下單面板與持倉表並排會把表格擠爆，改成上下堆疊讓表格拿到整個寬度。
   單欄一樣要寫 minmax(0, 1fr)：grid item 的 min-width 預設是 auto，寫 1fr 仍然
   會被裡面的寬表撐出容器外。 */
@media (max-width: 1279px) {
  .trading-layout {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* 這三張表的欄位語意都不可省略（數量／平均成本／現價／市值／損益／交易明細），
   1024–1279px 之間欄位會擠爆容器。body 有 overflow-x: hidden，不給捲動的話
   內容是被「切掉且拿不回來」，比捲動更糟。≥1280px 不會溢出所以不會出現捲軸；
   ≤860px 則已經轉成卡片清單（那裡有 overflow-x: visible !important 覆蓋）。 */
.holdings-table-wrap,
.trades-table-wrap,
.leaderboard-table-wrap {
  overflow-x: auto;
}

.order-card {
  padding: 26px 28px;
}

.holdings-card {
  padding: 26px 28px;
}

/* 持倉分類小計看板與市場損益標籤 */
.holdings-summary-bar {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 16px;
  padding: 14px 18px;
  border-radius: 12px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--brand) 7%, transparent) 0%, var(--bg-soft) 100%);
  border: 1px solid color-mix(in srgb, var(--brand) 25%, transparent);
}

.holdings-summary-main {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}

.holdings-summary-metrics {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

.holdings-metric-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.holdings-metric-item small {
  font-size: 11px;
  color: var(--ink-faint);
  font-weight: 600;
}

.holdings-metric-item strong {
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  font-weight: 750;
}

.holdings-subtotal-row {
  background: var(--bg-soft);
  font-weight: 700;
  border-top: 2px solid var(--line-strong) !important;
}

.holdings-subtotal-row td {
  font-weight: 700 !important;
  color: var(--ink) !important;
}

.trades-history-card {
  padding: 26px 28px;
}

.table-wrap table th,
.holdings-table-wrap table th,
.trades-table-wrap table th {
  padding: 12px 14px;
  font-size: 13.5px;
}

.table-wrap table td,
.holdings-table-wrap table td,
.trades-table-wrap table td {
  padding: 14px 14px;
  font-size: 14px;
}

.podium-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px;
  margin-bottom: 28px;
}

.podium-card {
  padding: 26px 22px;
  border-radius: 18px;
}

.btn-adjust {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  padding: 4px 8px;
  border-radius: 6px;
  border: 1px solid var(--line-strong);
  background: var(--card);
  color: var(--ink-soft);
  cursor: pointer;
  transition: all 0.15s ease;
}

.btn-adjust:hover {
  background: var(--bg);
  color: var(--primary);
  border-color: var(--primary);
}

.alloc-summary-card {
  padding: 24px 26px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.metrics-4-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin-bottom: 24px;
  padding-bottom: 0;
  border-bottom: 0;
}

.holdings-book-wrap {
  width: 100%;
  overflow-x: auto;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 8px 16px 12px;
}

.holdings-book {
  width: 100%;
  border-collapse: collapse;
}

.holdings-book th {
  font-size: 11px;
  color: var(--ink-faint);
  font-weight: 500;
  text-align: left;
  padding: 6px 8px 6px 0;
  border-bottom: 1px solid var(--hairline);
}

.holdings-book td {
  padding: 8px 8px 8px 0;
  border-bottom: 1px solid var(--hairline);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  vertical-align: baseline;
}

.holdings-book .num {
  text-align: right;
}

.market-tag {
  display: inline-block;
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-soft);
  border: 1px solid var(--hairline);
  padding: 1px 5px;
  border-radius: var(--radius-sm);
}

.leaderboard-table-wrap table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.leaderboard-table-wrap th {
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-faint);
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid var(--hairline);
}

.leaderboard-table-wrap td {
  padding: 8px;
  border-bottom: 1px solid var(--hairline);
  font-size: 13px;
}

/* 自己那一列改成左側黃銅直條，不再整列上底色 —— 原本的 --inset 底色與 hover
   的底色是同一個值，滑過別人那列會看起來像自己換了位置。 */
.leaderboard-table-wrap tr.is-self {
  background: transparent;
}

.leaderboard-table-wrap tr.is-self > td:first-child {
  box-shadow: inset 3px 0 0 var(--brand);
}

@media (max-width: 900px) {
  .metrics-4-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.btn-preset {
  background: var(--bg);
  border: 1px solid var(--line-strong);
  color: var(--ink-faint);
  padding: 3px 8px;
  border-radius: 4px;
  font-size: 11px;
  cursor: pointer;
  transition: all 0.15s ease;
}

.btn-preset:hover {
  background: var(--line);
  color: var(--ink);
  border-color: var(--brand);
}

/* 開關 Switch */
.switch {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 24px;
}

.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.toggle-slider {
  position: absolute;
  cursor: pointer;
  inset: 0;
  background-color: var(--line-strong);
  transition: .2s;
  border-radius: 24px;
}

.toggle-slider:before {
  position: absolute;
  content: "";
  height: 18px;
  width: 18px;
  left: 3px;
  bottom: 3px;
  background-color: white;
  transition: .2s;
  border-radius: 50%;
}

input:checked + .toggle-slider {
  background-color: var(--brand);
}

input:checked + .toggle-slider:before {
  transform: translateX(20px);
}

/* ===================== 排行榜與資料表格統一排版 ===================== */
.leaderboard-table-wrap table,
.champions-table-wrap table,
.friends-table-wrap table,
.holdings-table-wrap table,
.trades-table-wrap table,
.history-table table,
.admin-codes-table-wrap table,
.admin-users-table-wrap table,
.table-card table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font);
  font-size: 13.5px;
  line-height: 1.5;
  letter-spacing: -0.01em;
}

.leaderboard-table-wrap th,
.champions-table-wrap th,
.friends-table-wrap th,
.holdings-table-wrap th,
.trades-table-wrap th,
.admin-codes-table-wrap th,
.admin-users-table-wrap th {
  font-family: var(--font);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-faint);
  letter-spacing: 0.04em;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line-strong);
  white-space: nowrap;
  vertical-align: middle;
  /* 表頭對齊必須跟著該欄的資料走，數字欄的表頭靠左是最明顯的業餘感來源。 */
  text-align: left;
}

.leaderboard-table-wrap td,
.champions-table-wrap td,
.friends-table-wrap td,
.holdings-table-wrap td,
.trades-table-wrap td,
.admin-codes-table-wrap td,
.admin-users-table-wrap td {
  font-family: var(--font);
  font-size: 13.5px;
  font-weight: 400;
  color: var(--ink);
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
  vertical-align: middle;
  font-variant-numeric: tabular-nums;
}

@media (hover: hover) {
  .leaderboard-table-wrap tbody tr:hover,
  .champions-table-wrap tbody tr:hover,
  .friends-table-wrap tbody tr:hover,
  .holdings-table-wrap tbody tr:hover,
  .trades-table-wrap tbody tr:hover,
  .admin-codes-table-wrap tbody tr:hover,
  .admin-users-table-wrap tbody tr:hover {
    background: var(--inset);
  }
}

/* 數字欄一律靠右等寬，表頭跟著同一側；文字欄維持靠左。
   .num 由 app.js 在渲染時加在數字欄的 th/td 上。 */
.leaderboard-table-wrap th.num,
.champions-table-wrap th.num,
.friends-table-wrap th.num,
.holdings-table-wrap th.num,
.trades-table-wrap th.num,
.history-table th.num,
.admin-codes-table-wrap th.num,
.admin-users-table-wrap th.num,
.table-card th.num,
.leaderboard-table-wrap td.num,
.champions-table-wrap td.num,
.friends-table-wrap td.num,
.holdings-table-wrap td.num,
.trades-table-wrap td.num,
.history-table td.num,
.admin-codes-table-wrap td.num,
.admin-users-table-wrap td.num,
.table-card td.num,
.lb-num-cell {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* 表頭釘在「捲動容器」的頂端，top 必須是 0。
   這幾個 wrap 有 overflow-x: auto（1024–1280px 之間欄位會擠爆容器，不給捲動的話
   內容是被切掉且拿不回來），而 CSS 規定只要有一軸不是 visible，另一軸就會算成 auto
   —— 容器因此變成自己的捲動容器，sticky 是相對「它」而不是相對視窗。
   之前把 top 設成 command bar 的高度（63px），結果表頭往下掉 63px 直接蓋住前兩列資料。
   容器沒有限制高度、不會垂直捲動，所以 top: 0 等於表頭停在原位，不會蓋到任何東西。 */
.leaderboard-table-wrap thead th,
.holdings-table-wrap thead th,
.trades-table-wrap thead th,
.admin-users-table-wrap thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--canvas);
}

.lb-rank-cell {
  text-align: center;
  font-weight: 700;
  color: var(--ink-soft);
  font-size: 14px;
  width: 58px;
}

.lb-player-cell {
  text-align: left;
  font-size: 14px;
}

.lb-player-wrap {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  max-width: 100%;
}

.lb-player-name {
  font-weight: 700;
  color: var(--ink);
}

.lb-num-cell {
  text-align: right;
}

.lb-week-trades {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 4px;
  line-height: 1.2;
  max-width: 110px;
  margin: 0 auto;
}

.lb-trade-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.lb-trade-mark.is-buy {
  color: var(--up);
  background: color-mix(in srgb, var(--up) 12%, transparent);
}

.lb-trade-mark.is-sell {
  color: var(--down);
  background: color-mix(in srgb, var(--down) 12%, transparent);
}

.lb-trade-mark.is-none {
  color: var(--ink-faint);
  background: color-mix(in srgb, var(--line-strong) 16%, transparent);
  font-weight: 600;
}

.friend-period-trades {
  margin-bottom: 4px;
}

.friend-period-trades-summary {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}

.friend-period-trades-summary small {
  color: var(--ink-faint);
  font-size: 11px;
}

.friend-period-trades-table {
  overflow-x: auto;
  border: 1px solid color-mix(in srgb, var(--line-strong) 28%, transparent);
  border-radius: 12px;
}

.friend-period-trades-table table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.friend-period-trades-table th,
.friend-period-trades-table td {
  padding: 8px 10px;
  text-align: left;
  border-bottom: 1px solid color-mix(in srgb, var(--line-strong) 18%, transparent);
  white-space: nowrap;
}

.friend-period-trades-table th {
  font-size: 11px;
  color: var(--ink-faint);
  font-weight: 700;
  background: color-mix(in srgb, var(--line-strong) 8%, transparent);
}

.friend-period-trades-table tbody tr:last-child td {
  border-bottom: none;
}

.lb-center-cell {
  text-align: center;
}

/* ===================== 管理後台樣式 ===================== */
.admin-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin: 20px 0 24px;
}

.admin-stats-grid .stat-card {
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: var(--card);
}

.admin-stats-grid .stat-card h3 {
  font-size: 28px;
  font-weight: 700;
  margin: 0;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.admin-code-badge {
  font-family: monospace;
  font-weight: 700;
  font-size: 13.5px;
  padding: 4px 8px;
  border-radius: 6px;
  background: color-mix(in srgb, var(--brand) 8%, transparent);
  color: var(--primary-strong);
  border: 1px solid color-mix(in srgb, var(--brand) 20%, transparent);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  letter-spacing: 0.5px;
}

.admin-status-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 999px;
  font-weight: 600;
}

.admin-status-tag.is-active {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  color: var(--up);
}

.admin-status-tag.is-disabled {
  background: color-mix(in srgb, var(--ink-faint) 12%, transparent);
  color: var(--ink-faint);
}

.admin-status-tag.is-exhausted {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  color: var(--warn);
}

.admin-status-tag.is-expired {
  background: color-mix(in srgb, var(--down) 12%, transparent);
  color: var(--down);
}

.btn-icon-inline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 8px;
  font-size: 12px;
  border-radius: 6px;
  border: 1px solid var(--line-strong);
  background: var(--card);
  color: var(--ink-soft);
  cursor: pointer;
  transition: all 0.15s ease;
}

.btn-icon-inline:hover {
  background: var(--bg-soft);
  color: var(--ink);
  border-color: var(--line-strong);
}

/* ===================== 榮譽殿堂（競賽成就） ===================== */
.achievements-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
  margin-bottom: 32px;
}

.achievement-card {
  padding: 18px 20px;
  background: var(--card);
  border-radius: var(--radius);
  border: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
  position: relative;
  overflow: hidden;
}

.achievement-card.is-unlocked {
  border-color: color-mix(in srgb, var(--brand) 40%, transparent);
  background: linear-gradient(180deg, color-mix(in srgb, var(--brand) 4%, transparent) 0%, var(--card) 100%);
  box-shadow: 0 4px 16px color-mix(in srgb, var(--brand) 8%, transparent);
}

.achievement-card.is-unlocked:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 24px color-mix(in srgb, var(--brand) 16%, transparent);
  border-color: var(--brand);
}

.achievement-card.is-locked {
  opacity: 0.76;
  background: var(--bg-soft);
}

.achievement-card.is-locked:hover {
  opacity: 0.92;
  transform: translateY(-2px);
}

.ach-card-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 2px;
}

.ach-icon-box {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--bg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  border: 1px solid var(--line);
}

.achievement-card.is-unlocked .ach-icon-box {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  border-color: color-mix(in srgb, var(--brand) 30%, transparent);
}

.ach-badge-tag {
  font-size: 11.5px;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 999px;
}

.ach-badge-tag.unlocked {
  background: color-mix(in srgb, var(--brand) 15%, transparent);
  color: var(--brand);
  border: 1px solid color-mix(in srgb, var(--brand) 30%, transparent);
}

.ach-badge-tag.locked {
  background: color-mix(in srgb, var(--ink-faint) 10%, transparent);
  color: var(--ink-faint);
  border: 1px solid color-mix(in srgb, var(--ink-faint) 20%, transparent);
}

.ach-track-tag {
  font-size: 11px;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 999px;
  letter-spacing: 0.02em;
}

.ach-track-tag.is-long {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  color: var(--up);
  border: 1px solid color-mix(in srgb, var(--brand) 28%, transparent);
}

.ach-track-tag.is-short {
  background: color-mix(in srgb, var(--brand) 14%, transparent);
  color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--brand) 32%, transparent);
}

.ach-track-tag.is-any {
  background: color-mix(in srgb, var(--ink-faint) 10%, transparent);
  color: var(--ink-soft);
  border: 1px solid color-mix(in srgb, var(--ink-faint) 22%, transparent);
}

.ach-title {
  margin: 0;
  font-size: 15.5px;
  font-weight: 700;
  color: var(--ink);
}

.ach-desc {
  margin: 0;
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.45;
}

.ach-buff-box {
  padding: 6px 10px;
  background: color-mix(in srgb, var(--blue) 7%, transparent);
  border: 1px solid color-mix(in srgb, var(--blue) 20%, transparent);
  border-radius: 6px;
  font-size: 12px;
  color: var(--blue);
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 4px;
}

.ach-tier-bar-wrap {
  height: 6px;
  background: var(--line);
  border-radius: 3px;
  overflow: hidden;
  margin: 6px 0 2px;
}

.ach-tier-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--brand), var(--primary-strong));
  transition: width 0.3s ease;
}

.ach-foot {
  margin-top: 4px;
  padding-top: 6px;
  border-top: 1px dashed var(--line);
}

.ach-note {
  font-size: 11.5px;
  color: var(--ink-faint);
  font-weight: 600;
}

.achievement-card.is-unlocked .ach-note {
  color: var(--primary-strong);
}

/* ===================== 稱號商城樣式（操盤外號） ===================== */
.titles-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
  margin-bottom: 32px;
}

.title-shop-card {
  padding: 20px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
  position: relative;
}

.title-shop-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(58, 42, 20, 0.08);
}

.title-shop-card.is-equipped {
  border-color: var(--brand);
  background: linear-gradient(180deg, color-mix(in srgb, var(--brand) 6%, transparent) 0%, var(--card) 100%);
  box-shadow: 0 0 12px color-mix(in srgb, var(--brand) 15%, transparent);
}

.user-title-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--brand) 15%, transparent);
  color: var(--brand);
  border: 1px solid color-mix(in srgb, var(--brand) 35%, transparent);
  letter-spacing: 0.2px;
  margin-right: 4px;
  vertical-align: middle;
}

.user-title-badge.is-emperor {
  background: linear-gradient(135deg, color-mix(in srgb, var(--brand) 22%, transparent), color-mix(in srgb, var(--down) 16%, transparent));
  color: var(--primary-strong);
  border-color: color-mix(in srgb, var(--brand) 55%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--brand) 15%, transparent);
}

.title-shop-card.is-emperor {
  border-color: color-mix(in srgb, var(--brand) 45%, transparent);
  background: linear-gradient(180deg, color-mix(in srgb, var(--brand) 8%, transparent) 0%, var(--card) 100%);
}

.title-shop-card.is-emperor.is-equipped {
  border-color: var(--brand);
  box-shadow: 0 0 12px color-mix(in srgb, var(--brand) 22%, transparent);
}

.rarity-pill {
  font-size: 11px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 999px;
  text-transform: uppercase;
}

.rarity-pill.common { background: var(--inset); color: var(--ink-faint); }
.rarity-pill.rare { background: color-mix(in srgb, var(--ink-soft) 10%, transparent); color: var(--ink-soft); }
.rarity-pill.epic { background: color-mix(in srgb, var(--blue) 10%, transparent); color: var(--blue); }
.rarity-pill.legendary { background: var(--brass-wash); color: var(--brand); }
.rarity-pill.mythic { background: color-mix(in srgb, var(--warn) 12%, transparent); color: var(--warn); }
.rarity-pill.imperial { background: color-mix(in srgb, var(--brand) 20%, transparent); color: var(--primary-strong); }

/* ===================== 大亂鬥即時聊天室與願望清單樣式 ===================== */
.chat-room-card {
  border: 1px solid var(--line);
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.chat-quick-bar {
  padding: 8px 14px;
  border-top: 1px solid var(--line);
  background: var(--bg-soft);
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.chat-quick-label {
  color: var(--ink-faint);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

.chat-quick-bar .chat-quick-tags {
  flex: 1;
  min-width: 0;
}

.chat-phrase-manage-btn {
  flex: none;
  white-space: nowrap;
}

.chat-attach-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  min-height: 34px;
  padding: 5px 8px;
  border: 1px solid var(--line-strong);
  border-radius: 9px;
  background: var(--bg-soft);
  color: var(--ink-soft);
  font-size: 17px;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.chat-attach-button:hover {
  border-color: var(--brand);
  background: color-mix(in srgb, var(--blue) 10%, transparent);
  transform: translateY(-1px);
}

.visually-hidden-input {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.chat-image-preview,
.bug-image-preview {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px 10px;
  border-top: 1px solid var(--line);
  background: var(--card);
  color: var(--ink-soft);
  font-size: 12px;
}

.chat-image-preview img,
.bug-image-preview img {
  width: 52px;
  height: 52px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--line-strong);
}

.chat-image-preview span,
.bug-image-preview span {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-image-link {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
}

.chat-image {
  display: block;
  width: auto;
  max-width: min(280px, 100%);
  max-height: 240px;
  border: 1px solid color-mix(in srgb, var(--ink-faint) 25%, transparent);
  border-radius: 10px;
  object-fit: contain;
  background: rgba(255, 255, 255, 0.65);
}

.chat-text-content {
  display: block;
}

.community-modal-card {
  max-width: 560px;
}

.modal-help-text {
  margin: -8px 0 16px;
  color: var(--ink-faint);
  font-size: 13px;
  line-height: 1.5;
}

.chat-phrase-form {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
}

.chat-phrase-form input {
  flex: 1;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 9px;
  background: var(--bg);
}

.chat-phrase-list {
  display: flex;
  flex-direction: column;
  gap: 7px;
  max-height: 320px;
  overflow-y: auto;
  margin-bottom: 18px;
}

.chat-phrase-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 8px;
  padding: 9px 10px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--bg-soft);
}

.chat-phrase-item > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
}

.chat-phrase-item > small {
  color: var(--ink-faint);
  white-space: nowrap;
}

.chat-phrase-remove {
  width: 26px;
  height: 26px;
  color: var(--down);
}

.chat-msg-row {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  max-width: 82%;
}

.chat-msg-row.is-self {
  margin-left: auto;
  flex-direction: row-reverse;
}

.chat-msg-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--ink-soft);
  color: var(--overlay);
  font-size: 13px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.chat-msg-row.is-self .chat-msg-avatar {
  background: var(--brand);
}

.chat-msg-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.chat-msg-row.is-self .chat-msg-body {
  align-items: flex-end;
}

.chat-author-info {
  display: flex;
  gap: 6px;
  align-items: center;
  font-size: 11.5px;
  color: var(--ink-faint);
}

.chat-author-name {
  font-weight: 700;
  color: var(--ink-soft);
}

.chat-bubble {
  padding: 10px 14px;
  border-radius: 14px;
  font-size: 14px;
  line-height: 1.5;
  word-break: break-word;
  /* 保留換行：使用者本來就能打多行，更新公告也是一行一條重點。
     pre-wrap 不會影響單行訊息，但會讓連續空白照原樣顯示，所以送出前已由
     _normalize_chat_content trim 過。 */
  white-space: pre-wrap;
  background: var(--bg-soft);
  color: var(--ink);
  border: 1px solid var(--line);
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  touch-action: manipulation;
}

.chat-msg-row.is-self .chat-bubble {
  background: var(--brass-wash);
  color: var(--ink);
  border-color: var(--brand);
  border-bottom-right-radius: 2px;
}

.chat-msg-row.is-other .chat-bubble {
  border-bottom-left-radius: 2px;
}

.chat-msg-row.is-flash .chat-bubble {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 35%, transparent);
}

.chat-edited-tag {
  color: var(--ink-faint);
  font-size: 10.5px;
}

.chat-quote {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  max-width: 100%;
  padding: 6px 10px;
  border: 0;
  border-left: 3px solid var(--line-strong);
  border-radius: 8px;
  background: color-mix(in srgb, var(--blue) 8%, transparent);
  color: var(--ink-soft);
  font-size: 12px;
  text-align: left;
  cursor: pointer;
}

.chat-quote strong {
  font-size: 11px;
  color: var(--ink-soft);
}

.chat-quote span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 280px;
}

.chat-quote.is-missing {
  cursor: default;
  border-left-color: var(--line-strong);
  color: var(--ink-faint);
}

.chat-msg-row.is-self .chat-quote {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  border-left-color: var(--brand);
}

.chat-msg-row.is-self .chat-quote strong {
  color: var(--ink-soft);
}

.chat-msg-row.is-action-target .chat-bubble {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 28%, transparent);
}

.chat-reactions {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}

.chat-msg-row.is-self .chat-reactions {
  justify-content: flex-end;
}

.chat-action-overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: transparent;
}

.chat-action-menu {
  position: fixed;
  z-index: 81;
  min-width: 220px;
  max-width: calc(100vw - 16px);
  padding: 8px;
  border-radius: 16px;
  border: 1px solid var(--line-strong);
  background: var(--card);
  box-shadow: 0 12px 32px color-mix(in srgb, var(--nav) 18%, transparent);
}

.chat-action-emojis,
.chat-action-cmds {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

.chat-action-cmds {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}

.chat-action-menu .chat-react-btn {
  width: 36px;
  height: 36px;
  font-size: 18px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.chat-action-menu .chat-tool-btn {
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
}

.chat-tool-btn,
.chat-react-btn {
  border: 1px solid var(--line-strong);
  background: var(--bg);
  color: var(--ink-soft);
  border-radius: 999px;
  font-size: 11px;
  padding: 2px 8px;
  cursor: pointer;
  line-height: 1.4;
}

.chat-react-btn {
  padding: 2px 7px;
  font-size: 13px;
}

.chat-tool-btn:hover,
.chat-react-btn:hover {
  border-color: var(--line-strong);
  background: var(--bg-soft);
}

.chat-react-btn.is-reacted,
.chat-react-btn.has-count {
  background: color-mix(in srgb, var(--blue) 10%, transparent);
  border-color: color-mix(in srgb, var(--blue) 35%, transparent);
}

.chat-react-btn.is-reacted {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--blue) 25%, transparent);
}

.chat-compose-hint {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 8px 14px 0;
  background: var(--card);
  border-top: 1px solid var(--line);
}

.chat-compose-hint-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.chat-compose-hint-body small {
  color: var(--blue);
  font-weight: 700;
}

.chat-compose-hint-body span {
  font-size: 12px;
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Mention 標籤與高亮 */
.mention-tag {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  background: color-mix(in srgb, var(--blue) 12%, transparent);
  color: var(--blue);
  padding: 1px 6px;
  border-radius: 6px;
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--blue) 25%, transparent);
  transition: all 0.15s ease;
  vertical-align: baseline;
}

.mention-tag:hover {
  background: color-mix(in srgb, var(--blue) 22%, transparent);
}

.chat-msg-row.is-self .mention-tag {
  background: color-mix(in srgb, var(--brand) 18%, transparent);
  color: var(--ink);
  border-color: color-mix(in srgb, var(--brand) 45%, transparent);
}

.mention-tag.mention-me {
  background: color-mix(in srgb, var(--brand) 22%, transparent) !important;
  color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--brand) 45%, transparent) !important;
  box-shadow: 0 0 8px color-mix(in srgb, var(--brand) 25%, transparent);
}

.chat-msg-row.is-self .mention-tag.mention-me {
  color: var(--brand) !important;
}

.mention-tag.mention-item {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  color: var(--brand);
  border-color: color-mix(in srgb, var(--brand) 28%, transparent);
}

.mention-tag.mention-item:hover {
  background: color-mix(in srgb, var(--brand) 22%, transparent);
}

.chat-msg-row.is-self .mention-tag.mention-item {
  background: color-mix(in srgb, var(--brand) 18%, transparent);
  color: var(--ink);
  border-color: color-mix(in srgb, var(--brand) 45%, transparent);
}

.chat-mention-jump-banner {
  position: absolute;
  top: 54px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border-radius: 24px;
  background: var(--brand);
  color: var(--on-brass);
  font-size: 13px;
  font-weight: 600;
  box-shadow: 0 4px 16px color-mix(in srgb, var(--warn) 45%, transparent);
  animation: slideDownMentionAlert 0.25s ease-out;
  max-width: 90%;
  cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--on-brass) 30%, transparent);
}

.chat-mention-jump-banner strong {
  color: var(--on-brass);
  text-decoration: underline;
}

.btn-mention-jump {
  background: color-mix(in srgb, var(--on-brass) 25%, transparent);
  border: 1px solid color-mix(in srgb, var(--on-brass) 60%, transparent);
  color: var(--on-brass);
  border-radius: 12px;
  padding: 2px 10px;
  font-size: 11.5px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.15s ease;
}

.btn-mention-jump:hover {
  background: var(--overlay);
  color: var(--brand);
}

.btn-mention-close {
  background: none;
  border: none;
  color: color-mix(in srgb, var(--on-brass) 85%, transparent);
  font-size: 14px;
  cursor: pointer;
  padding: 0 2px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.btn-mention-close:hover {
  color: var(--on-brass);
}

@keyframes slideDownMentionAlert {
  from {
    opacity: 0;
    transform: translate(-50%, -12px);
  }
  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

.chat-msg-row.has-mention-me {
  background: color-mix(in srgb, var(--brand) 8%, transparent);
  border-radius: 12px;
  padding: 4px 8px;
  margin: -4px -8px;
  border-left: 3px solid var(--brand);
}

.chat-msg-row.has-mention-me .chat-bubble {
  border-color: var(--brand);
  box-shadow: 0 0 14px color-mix(in srgb, var(--brand) 25%, transparent);
  background: var(--brass-wash);
}

.chat-msg-row.is-self.has-mention-me .chat-bubble {
  background: var(--brass-wash);
  border-color: var(--brand);
}

.btn-mention-inline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1px 5px;
  font-size: 11px;
  font-weight: 700;
  border-radius: 4px;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  color: var(--ink-faint);
  cursor: pointer;
  line-height: 1.2;
  transition: all 0.15s ease;
  margin-left: 4px;
}

.btn-mention-inline:hover {
  background: color-mix(in srgb, var(--blue) 12%, transparent);
  color: var(--blue);
  border-color: var(--blue);
}

.mention-autocomplete-menu {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 14px;
  right: 14px;
  max-height: 180px;
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  box-shadow: 0 -4px 20px rgba(58, 42, 20, 0.15);
  z-index: 60;
  display: flex;
  flex-direction: column;
  padding: 4px;
  -webkit-overflow-scrolling: touch;
}

.mention-user-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  transition: background 0.12s ease;
}

.mention-user-item:hover,
.mention-user-item.is-selected {
  background: var(--bg-soft);
  color: var(--primary-strong);
}

.mention-user-item .mention-item-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--ink-soft);
  color: var(--overlay);
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.chat-command-item .mention-item-avatar {
  background: color-mix(in srgb, var(--brand) 14%, transparent);
  color: var(--brand);
  font-size: 14px;
}

.chat-command-copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.chat-command-copy > div,
.chat-command-copy > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-command-copy small,
.chat-command-copy > span {
  color: var(--ink-faint);
}

.chat-command-copy > span {
  font-size: 11px;
}

.mention-item-option {
  cursor: pointer;
}

.mention-item-option .mention-item-avatar {
  background: color-mix(in srgb, var(--brand) 15%, transparent);
  color: inherit;
  font-size: 13px;
}

.mention-group-title {
  padding: 5px 12px 3px;
  color: var(--ink-faint);
  font-size: 11px;
  font-weight: 700;
  cursor: default;
  pointer-events: none;
  user-select: none;
}

/* 願望清單樣式：單欄條列，方便快速掃描與操作 */
.wishlist-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 32px;
}

.wish-card {
  padding: 18px 20px;
  background: var(--card);
  border-radius: var(--radius);
  border: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
  position: relative;
}

.wish-list-item {
  display: grid;
  grid-template-columns: minmax(210px, 1.05fr) minmax(180px, 1.7fr) minmax(210px, auto);
  align-items: center;
  gap: 14px;
}

.wish-list-item .wish-note {
  min-width: 0;
}

.wish-list-item .wish-footer {
  grid-column: 3;
  grid-row: 1;
  flex-direction: column;
  align-items: flex-end;
  gap: 7px;
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.wish-list-item .wish-actions {
  justify-content: flex-end;
  flex-wrap: wrap;
}

.bug-board-card {
  padding: 22px 24px;
}

.bug-board-heading {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 14px;
}

.bug-board-heading h2 {
  margin: 4px 0 4px;
  font-size: 22px;
}

.bug-board-heading .page-subtitle {
  margin: 0;
}

.bug-status-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin-bottom: 16px;
  color: var(--ink-faint);
  font-size: 12px;
}

.bug-status-legend span,
.bug-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.bug-status-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--line-strong);
}

.bug-status-dot.open { background: var(--warn); }
.bug-status-dot.in-progress { background: var(--blue); }
.bug-status-dot.resolved { background: var(--up); }
.bug-status-dot.closed { background: var(--ink-faint); }

.bug-reports-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.bug-report-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  padding: 16px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--warn);
  border-radius: 12px;
  background: var(--bg-soft);
}

.bug-report-item.bug-status-in_progress { border-left-color: var(--blue); }
.bug-report-item.bug-status-resolved { border-left-color: var(--up); }
.bug-report-item.bug-status-closed { border-left-color: var(--ink-faint); }

.wish-card.is-flash {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 45%, transparent);
  border-color: var(--brand);
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.bug-report-item.is-flash {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 45%, transparent);
  border-top-color: var(--brand);
  border-right-color: var(--brand);
  border-bottom-color: var(--brand);
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.bug-report-title-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

.bug-report-title-row h3 {
  margin: 0;
  font-size: 15px;
  color: var(--ink);
}

.bug-status-badge {
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

.bug-status-badge.open { color: var(--warn); background: color-mix(in srgb, var(--warn) 12%, transparent); }
.bug-status-badge.in_progress { color: var(--blue); background: color-mix(in srgb, var(--blue) 12%, transparent); }
.bug-status-badge.resolved { color: var(--up); background: color-mix(in srgb, var(--up) 12%, transparent); }
.bug-status-badge.closed { color: var(--ink-soft); background: var(--inset); }

.bug-report-details {
  margin: 0 0 10px;
  color: var(--ink-soft);
  font-size: 13px;
  line-height: 1.6;
  word-break: break-word;
}

.bug-report-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 12px;
  color: var(--ink-faint);
  font-size: 11px;
}

.bug-admin-status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  color: var(--ink-faint);
  font-size: 11px;
}

.bug-admin-status select {
  padding: 5px 8px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--card);
  color: var(--ink);
  font-size: 12px;
}

.bug-report-attachment {
  display: flex;
  align-items: flex-start;
}

.bug-attachment-link img {
  display: block;
  width: 128px;
  max-height: 128px;
  object-fit: cover;
  border: 1px solid var(--line-strong);
  border-radius: 9px;
}

.bug-upload-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.bug-attach-label {
  align-self: flex-start;
  font-size: 13px;
}

.wish-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(58, 42, 20, 0.06);
}

.wish-card.is-completed {
  background: linear-gradient(180deg, color-mix(in srgb, var(--brand) 4%, transparent) 0%, var(--card) 100%);
  border-color: color-mix(in srgb, var(--brand) 35%, transparent);
}

.wish-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
}

.wish-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
}

.wish-card.is-completed .wish-title {
  text-decoration: line-through;
  color: var(--ink-soft);
}

.wish-status-badge {
  font-size: 11.5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-weight: 700;
  white-space: nowrap;
}

.wish-status-badge.pending {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--brand) 25%, transparent);
}

.wish-status-badge.completed {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  color: var(--up);
  border: 1px solid color-mix(in srgb, var(--brand) 25%, transparent);
}

.wish-target-val {
  font-size: 13.5px;
  color: var(--brand);
  font-weight: 700;
}

.wish-note {
  margin: 0;
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.5;
  flex: 1;
}

.wish-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
}

.wish-author {
  font-size: 11.5px;
  color: var(--ink-faint);
}

.wish-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

.btn-like {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  color: var(--ink-soft);
  font-size: 12px;
  cursor: pointer;
  transition:
    background var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out);
}

/* 已加油＝實心愛心。全套圖示都是 stroke-only，這是唯一需要 fill 變體的地方：
   愛心的「滿／空」本身就是狀態語意，只靠顏色會讓色弱使用者分不出來。 */
.btn-like.is-liked svg {
  fill: currentColor;
}

.btn-like.is-liked {
  background: color-mix(in srgb, var(--down) 10%, transparent);
  border-color: color-mix(in srgb, var(--down) 30%, transparent);
  color: var(--down);
  font-weight: 700;
}

.btn-like:hover {
  border-color: var(--down);
  color: var(--down);
}

/* ============================================================
   📱 行動裝置極致體驗與排版優化 (Mobile Responsive & Ergonomics)
   ============================================================ */

@media (max-width: 1080px) {
  .cards-grid {
    grid-template-columns: 1fr 1fr;
  }

  .fx-card {
    grid-column: 1 / -1;
  }

  .hero-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 860px) {
  /* 1. 防止 iOS Safari 聚焦時縮放畫面 */
  input,
  select,
  textarea {
    font-size: 16px !important;
  }

  .fx-chart-heading {
    flex-direction: column;
    gap: 12px;
  }

  .fx-chart-selector {
    width: 100%;
    min-width: 0;
  }

  .fx-chart-select {
    width: 100%;
  }

  .fx-chart-canvas {
    padding-left: 0;
  }

  .fx-chart-svg {
    min-height: 220px;
  }

  /* 2. 側邊欄抽屜 (Drawer) 與遮罩層 */
  .sidebar {
    transform: translateX(-100%);
    box-shadow: 0 0 36px rgba(58, 42, 20, 0.5);
    z-index: 120;
    transition: transform 0.26s cubic-bezier(0.16, 1, 0.3, 1);
  }

  .app-shell.sidebar-open .sidebar {
    transform: translateX(0);
  }

  .app-shell.sidebar-open::after {
    content: '';
    position: fixed;
    inset: 0;
    background: color-mix(in srgb, var(--nav) 65%, transparent);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    z-index: 110;
    animation: drawerFadeIn 0.2s ease-out;
  }

  @keyframes drawerFadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
  }

  .main-content {
    margin-left: 0 !important;
    min-height: 100vh;
  }

  .mobile-menu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 10px;
    background: var(--card);
    border: 1px solid var(--line);
    color: var(--ink);
    cursor: pointer;
  }

  .topbar {
    padding: 8px 14px;
    height: 48px;
    gap: 10px;
    min-width: 0;
  }

  .topbar-actions {
    min-width: 0;
    flex-shrink: 0;
  }

  .breadcrumb {
    display: none;
  }

  /* 3. 頁面內容排版與安全區域 (避開底部導覽列) */
  .page-content {
    padding: 14px 12px calc(78px + env(safe-area-inset-bottom, 12px)) !important;
    max-width: 100% !important;
  }

  html,
  body,
  .app-shell,
  .main-content,
  .page-content {
    overflow-x: hidden;
    max-width: 100%;
  }

  body {
    touch-action: pan-y pinch-zoom;
  }

  input,
  select,
  textarea,
  button {
    touch-action: manipulation;
  }

  /* 4. 現代玻璃擬態大亂鬥風格底部導覽列 */
  .mobile-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 100;
    display: flex;
    align-items: stretch;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
    touch-action: pan-x;
    background: color-mix(in srgb, var(--nav) 95%, transparent);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    box-shadow: 0 -4px 20px rgba(58, 42, 20, 0.25);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    height: calc(62px + env(safe-area-inset-bottom, 0px));
    min-height: calc(62px + env(safe-area-inset-bottom, 0px));
  }

  .mobile-nav::-webkit-scrollbar {
    display: none;
  }

  .mobile-nav-item {
    flex: 0 0 72px;
    width: 72px;
    min-width: 72px;
    border: 0;
    background: transparent;
    color: var(--nav-muted);
    padding: 7px 4px 5px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    cursor: pointer;
    transition: color 0.15s ease, transform 0.1s ease;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    scroll-snap-align: start;
  }

  .mobile-nav-item:active {
    transform: none;
  }

  .mobile-nav-item svg {
    width: 20px;
    height: 20px;
    transition: transform 0.15s ease;
  }

  .mobile-nav-item small {
    font-size: 10px;
    letter-spacing: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .mobile-nav-item.is-active {
    color: var(--brass-on-dark);
    font-weight: 700;
  }

  .mobile-nav-item.is-active svg {
    transform: translateY(-1px);
  }

  /* 5. 卡片與標題排版最佳化 */
  .card,
  .hero-card,
  .stat-card,
  .order-card,
  .holdings-card,
  .trades-history-card,
  .settings-card,
  .alloc-summary-card,
  .friends-list-card,
  .leaderboard-card,
  .create-code-card,
  .codes-list-card,
  .users-list-card,
  .ach-progress-card {
    padding: 16px 14px !important;
    border-radius: 14px !important;
  }

  .welcome-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 14px;
  }

  .welcome-row h1,
  .view-header h1 {
    font-size: 20px !important;
    line-height: 1.3;
  }

  .page-subtitle {
    font-size: 12.5px;
    line-height: 1.45;
  }

  .hero-grid {
    grid-template-columns: 1fr !important;
    gap: 14px;
  }

  .hero-value {
    font-size: clamp(26px, 7vw, 34px) !important;
    font-weight: 800;
  }

  .hero-foot {
    display: grid !important;
    grid-template-columns: repeat(3, 1fr) !important;
    gap: 8px !important;
    padding-top: 12px;
    margin-top: 14px;
    border-top: 1px solid var(--line);
  }

  .hero-foot > div {
    display: flex;
    flex-direction: column;
    gap: 2px;
  }

  .hero-foot span {
    font-size: 11px;
    color: var(--ink-faint);
  }

  .hero-foot strong {
    font-size: 13.5px;
  }

  /* 6. 指標 4 格與管理數據在手機上以 2x2 排列 */
  .metrics-4-grid {
    grid-template-columns: repeat(2, 1fr) !important;
    gap: 10px !important;
    margin-bottom: 16px !important;
  }

  .metrics-4-grid .stat-card {
    padding: 12px 14px !important;
  }

  .metrics-4-grid .stat-card h3 {
    font-size: 18px !important;
  }

  .admin-stats-grid {
    grid-template-columns: repeat(2, 1fr) !important;
    gap: 10px !important;
  }

  /* 7. 大亂鬥天梯與週榜競技 */
  .podium-grid {
    grid-template-columns: 1fr !important;
    gap: 12px !important;
    margin-bottom: 20px !important;
  }

  .podium-card {
    padding: 16px 16px 14px !important;
    border-radius: 14px !important;
  }

  .filter-tabs {
    display: flex;
    flex-wrap: wrap;
    width: 100%;
    max-width: 100%;
    gap: 4px;
    background: var(--bg-soft);
    padding: 3px;
    border-radius: 10px;
    border: 1px solid var(--line);
  }

  .filter-tab {
    flex: 1 1 calc(33.33% - 6px);
    min-width: 0;
    text-align: center;
    padding: 8px 6px;
    font-size: 12px;
    font-weight: 600;
    border-radius: 7px;
  }

  .period-toggle-wrap {
    gap: 6px;
  }

  .period-toggle-wrap .filter-tab {
    flex: 1 1 calc(33.33% - 6px);
    padding: 8px 4px;
    font-size: 12px;
  }

  .friend-actions-bar {
    padding: 12px 14px !important;
    margin-bottom: 16px !important;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }

  /* 8. 交易面板與市場切換按鈕 */
  .trading-layout {
    grid-template-columns: minmax(0, 1fr) !important;
    gap: 16px !important;
    margin-bottom: 24px !important;
  }

  .market-selector {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    width: 100%;
    gap: 6px;
  }

  .market-btn {
    min-height: 42px;
    padding: 8px 6px;
    font-size: 13px;
    font-weight: 600;
    text-align: center;
    border-radius: 9px;
  }

  .quote-search-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }

  .quote-search-row input {
    flex: 1 1 160px;
    min-width: 0;
    min-height: 42px;
  }

  .quote-search-row button {
    flex: 0 0 auto;
    min-height: 42px;
    padding: 0 16px;
    white-space: nowrap;
  }

  .order-fields {
    grid-template-columns: 1fr;
  }

  .cards-grid {
    grid-template-columns: 1fr !important;
  }

  .market-news-card {
    padding: 14px !important;
  }

  .market-news-toolbar {
    align-items: flex-start;
    flex-direction: column;
    gap: 10px;
  }

  .news-filter-tabs {
    width: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    padding-bottom: 2px;
  }

  .news-filter-tab {
    flex: 0 0 auto;
    min-height: 36px;
  }

  .market-news-item {
    grid-template-columns: 58px minmax(0, 1fr);
    gap: 10px;
    padding: 12px;
  }

  .news-source-link {
    grid-column: 2;
    align-self: start;
  }

  .news-score-block strong {
    font-size: 1.2rem;
  }

  .news-score-critical .news-item-title {
    font-size: 1.04rem;
  }

  /* 9. 寬表格改成直向卡片，不再左右滑 */
  .table-wrap,
  .leaderboard-table-wrap,
  .holdings-table-wrap,
  .trades-table-wrap,
  .admin-codes-table-wrap,
  .admin-users-table-wrap,
  .history-table,
  .table-card,
  .champions-table-wrap,
  .wide-table-card,
  .fx-table-wrap {
    overflow-x: visible !important;
    width: 100%;
    max-width: 100%;
  }

  .leaderboard-table-wrap table,
  .champions-table-wrap table,
  .holdings-table-wrap table,
  .trades-table-wrap table,
  .friend-period-trades-table table,
  .history-table table,
  .table-card table,
  .admin-codes-table-wrap table,
  .admin-users-table-wrap table,
  .wide-table-card table,
  .fx-table-wrap table {
    display: block;
    width: 100%;
  }

  .leaderboard-table-wrap thead,
  .champions-table-wrap thead,
  .holdings-table-wrap thead,
  .trades-table-wrap thead,
  .friend-period-trades-table thead,
  .history-table thead,
  .table-card thead,
  .admin-codes-table-wrap thead,
  .admin-users-table-wrap thead,
  .wide-table-card thead,
  .fx-table-wrap thead {
    display: none;
  }

  .leaderboard-table-wrap tbody,
  .champions-table-wrap tbody,
  .holdings-table-wrap tbody,
  .trades-table-wrap tbody,
  .friend-period-trades-table tbody,
  .history-table tbody,
  .table-card tbody,
  .admin-codes-table-wrap tbody,
  .admin-users-table-wrap tbody,
  .wide-table-card tbody,
  .fx-table-wrap tbody {
    display: block;
  }

  .leaderboard-table-wrap tbody tr,
  .champions-table-wrap tbody tr,
  .holdings-table-wrap tbody tr,
  .trades-table-wrap tbody tr,
  .friend-period-trades-table tbody tr,
  .history-table tbody tr,
  .table-card tbody tr,
  .admin-codes-table-wrap tbody tr,
  .admin-users-table-wrap tbody tr,
  .wide-table-card tbody tr,
  .fx-table-wrap tbody tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px 12px;
    width: 100%;
    margin: 0;
    padding: 12px 0;
    /* 手機上一列一張圓角卡正是「AI 卡片牆」的典型。改成連續清單：
       透明底 + 下方 hairline，跟已經做對的 .wishlist-list / .bug-reports-list 一致。 */
    border: 0;
    border-bottom: 1px solid var(--hairline);
    border-radius: 0;
    background: transparent;
    box-sizing: border-box;
  }

  .leaderboard-table-wrap tbody tr:hover,
  .holdings-table-wrap tbody tr:hover,
  .trades-table-wrap tbody tr:hover {
    background: transparent;
  }

  /* 卡片模式下數字仍要靠右：td 已經是 flex column，靠 align-items 收右緣。 */
  .leaderboard-table-wrap td.num,
  .holdings-table-wrap td.num,
  .trades-table-wrap td.num,
  .history-table td.num,
  .table-card td.num,
  .fx-table-wrap td.num,
  .lb-num-cell {
    align-items: flex-end;
    text-align: right;
  }

  .leaderboard-table-wrap td,
  .champions-table-wrap td,
  .holdings-table-wrap td,
  .trades-table-wrap td,
  .friend-period-trades-table td,
  .history-table td,
  .table-card td,
  .admin-codes-table-wrap td,
  .admin-users-table-wrap td,
  .wide-table-card td,
  .fx-table-wrap td,
  .leaderboard-table-wrap table td,
  .holdings-table-wrap table td,
  .trades-table-wrap table td {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-width: 0 !important;
    width: auto;
    padding: 0 !important;
    border-bottom: 0 !important;
    white-space: normal !important;
    text-align: left;
    font-size: 13px !important;
    overflow-wrap: anywhere;
  }

  .leaderboard-table-wrap td[data-label]::before,
  .champions-table-wrap td[data-label]::before,
  .holdings-table-wrap td[data-label]::before,
  .trades-table-wrap td[data-label]::before,
  .friend-period-trades-table td[data-label]::before,
  .history-table td[data-label]::before,
  .table-card td[data-label]::before,
  .admin-codes-table-wrap td[data-label]::before,
  .admin-users-table-wrap td[data-label]::before,
  .wide-table-card td[data-label]::before,
  .fx-table-wrap td[data-label]::before {
    content: attr(data-label);
    font-size: 11px;
    font-weight: 600;
    color: var(--ink-faint);
    letter-spacing: 0.02em;
  }

  .holdings-table-wrap td:first-child,
  .trades-table-wrap td:first-child,
  .leaderboard-table-wrap td.lb-player-cell,
  .admin-codes-table-wrap td:first-child,
  .admin-users-table-wrap td:nth-child(2),
  .table-card td:last-child {
    grid-column: 1 / -1;
  }

  .lb-rank-cell,
  .lb-num-cell,
  .lb-center-cell,
  .lb-player-cell {
    text-align: left;
    width: auto;
  }

  .alloc-bar-wrap {
    width: 100%;
  }

  .holdings-summary-main {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  .holdings-summary-metrics {
    width: 100%;
    justify-content: space-between;
  }

  .holdings-table-wrap tfoot,
  .trades-table-wrap tfoot {
    display: block;
  }

  .holdings-table-wrap tfoot tr.holdings-subtotal-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    margin: 12px 0 0;
    padding: 12px 0;
    border: 0;
    border-top: 1px solid var(--hairline);
    border-radius: 0;
    background: transparent;
  }

  .holdings-table-wrap tfoot tr.holdings-subtotal-row td {
    display: flex;
    justify-content: space-between;
    align-items: center;
    border: none !important;
    padding: 2px 0 !important;
  }

  /* 10. 彈窗 Bottom Sheet 模式 */
  .friend-modal-gate,
  .auth-gate {
    padding: 0 !important;
    align-items: flex-end !important;
  }

  .friend-modal-card {
    width: 100% !important;
    max-width: 100% !important;
    margin: 0 !important;
    border-radius: 22px 22px 0 0 !important;
    padding: 20px 18px calc(24px + env(safe-area-inset-bottom, 12px)) !important;
    max-height: 86vh !important;
    animation: slideUp 0.25s cubic-bezier(0.16, 1, 0.3, 1);
  }

  .auth-card {
    width: 100% !important;
    max-width: 100% !important;
    margin: 0 !important;
    border-radius: 22px 22px 0 0 !important;
    padding: 24px 20px calc(28px + env(safe-area-inset-bottom, 12px)) !important;
    max-height: 92vh !important;
    overflow-y: auto;
    animation: slideUp 0.25s cubic-bezier(0.16, 1, 0.3, 1);
  }

  @keyframes slideUp {
    from {
      transform: translateY(100%);
    }
    to {
      transform: translateY(0);
    }
  }

  .modal-header h2 {
    font-size: 18px;
  }

  /* 11. Toast 浮動位置調整至底部導覽列上方 */
  .toast {
    bottom: calc(118px + env(safe-area-inset-bottom, 10px)) !important;
    font-size: 13px;
    padding: 8px 16px;
    max-width: min(90vw, calc(100% - 24px));
  }

  /* 12. 定期定額與未來推演計算機排版 */
  .dca-fields {
    flex-direction: column;
    align-items: stretch;
  }
  .dca-fields input,
  .dca-fields select,
  .dca-fields button {
    width: 100% !important;
  }
  .dca-plan-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  .dca-plan-actions {
    width: 100%;
    justify-content: space-between;
  }

  .calc-layout {
    grid-template-columns: 1fr !important;
    gap: 16px;
  }

  .calc-form {
    position: static !important;
  }

  .settings-grid {
    grid-template-columns: 1fr !important;
  }

  .admin-layout {
    grid-template-columns: 1fr !important;
  }

  .rooms-explore-grid {
    grid-template-columns: 1fr !important;
  }

  .pass-perks-grid {
    grid-template-columns: 1fr !important;
  }

  .achievements-grid {
    grid-template-columns: 1fr !important;
    gap: 12px !important;
  }

  .titles-grid {
    grid-template-columns: 1fr !important;
    gap: 12px !important;
  }

  .wishlist-list {
    gap: 12px !important;
  }

  .wish-list-item {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .wish-list-item .wish-footer {
    grid-column: 1;
    grid-row: auto;
    width: 100%;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    padding-top: 10px;
    border-top: 1px dashed var(--line);
  }

  .chat-room-card {
    height: calc(100vh - 185px) !important;
    height: calc(100dvh - 185px) !important;
    max-height: calc(100vh - 185px) !important;
    max-height: calc(100dvh - 185px) !important;
    min-height: 380px;
  }

  .chat-header {
    padding: 10px 12px !important;
    gap: 8px;
  }

  .chat-header > div:first-child {
    min-width: 0;
    gap: 6px !important;
  }

  .chat-header > div:first-child small,
  .chat-header #chatSyncState {
    display: none;
  }

  .chat-header strong {
    font-size: 13px !important;
    line-height: 1.3;
  }

  .chat-quick-bar {
    align-items: center;
    flex-wrap: nowrap;
    overflow: hidden;
    padding: 7px 10px;
    gap: 6px;
  }

  .chat-quick-label {
    flex: none;
    font-size: 10.5px;
  }

  .chat-quick-tags {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    white-space: nowrap;
    scrollbar-width: none;
    padding-bottom: 2px;
  }

  .chat-quick-tags::-webkit-scrollbar {
    display: none;
  }

  .chat-quick-tags > .btn-preset {
    flex: 0 0 auto;
  }

  .chat-quick-bar .chat-quick-tags {
    flex: 1 1 auto;
    flex-basis: auto;
  }

  .chat-quick-bar .btn-preset,
  .chat-phrase-manage-btn {
    min-height: 32px;
    padding: 6px 9px;
    font-size: 12px;
  }

  .chat-phrase-manage-btn {
    flex: none;
    margin-left: 0;
  }

  .chat-messages-wrap {
    padding: 14px 10px !important;
    gap: 10px !important;
  }

  .chat-msg-row {
    max-width: 96% !important;
    gap: 7px;
  }

  .chat-msg-avatar {
    width: 30px;
    height: 30px;
    font-size: 12px;
  }

  .chat-bubble {
    padding: 9px 11px;
    font-size: 14px;
  }

  .chat-input-bar {
    padding: 8px 10px !important;
    gap: 7px !important;
  }

  .chat-input-bar #chatInputText {
    min-width: 0;
    min-height: 42px;
    padding: 10px 12px !important;
    font-size: 16px !important;
  }

  .chat-input-bar .primary-button {
    min-height: 42px;
  }

  .chat-input-bar .primary-button {
    padding: 8px 12px !important;
  }

  .bug-board-card {
    padding: 18px 14px;
  }

  .bug-board-heading {
    flex-direction: column;
  }

  .bug-board-heading .primary-button {
    width: 100%;
  }

  .bug-report-item {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .bug-report-attachment {
    order: -1;
  }

  .bug-attachment-link img {
    width: 100%;
    max-width: 220px;
  }

  /* 行動版觸控目標：交易紀錄的修改／刪除、聊天室表情、篩選分頁等主要操作
     在桌面版只有 20–28px，這裡統一拉到 40px（桌面版不受影響）。 */
  .btn-adjust,
  .btn-icon-inline,
  .filter-tab,
  .chat-react-btn {
    min-height: 40px;
    padding-block: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* .btn-preset 漏在上面那組觸控補丁之外：375px 下實測只有 24px
     （下單面板的「25%」「50%」「100% 全部現金」）。
     這條必須是獨立規則 —— 上面那組四個選擇器的換行格式被
     tests/test_frontend_hardening.py 的 regex 釘住了，不可以把它加進去。 */
  .btn-preset {
    min-height: 40px;
    padding-block: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .btn-icon-inline,
  .chat-react-btn {
    min-width: 40px;
  }

}

@media (max-width: 420px) {
  .hero-foot {
    grid-template-columns: 1fr 1fr !important;
    gap: 10px;
  }

  .metrics-4-grid {
    grid-template-columns: 1fr !important;
  }

  .admin-stats-grid {
    grid-template-columns: 1fr !important;
  }

  .fx-chart-summary {
    grid-template-columns: 1fr;
  }
}

/* 房間表單、Emoji 選擇器與成員管理樣式 */
.room-emoji-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 8px;
  margin-top: 6px;
}

.emoji-select-btn {
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  font-size: 22px;
  padding: 8px 4px;
  text-align: center;
  cursor: pointer;
  transition: all 0.15s ease;
  user-select: none;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.emoji-select-btn:hover {
  border-color: var(--brand);
  transform: translateY(-2px);
  box-shadow: var(--shadow-sm);
}

.emoji-select-btn.is-selected {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  border-color: var(--brand);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand) 25%, transparent);
  transform: scale(1.05);
}

.room-type-toggle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 12px;
}

.room-type-btn {
  padding: 9px 12px;
  border-radius: 8px;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: all 0.15s ease;
  color: var(--ink-soft);
}

.room-type-btn:hover {
  border-color: var(--line-strong);
  color: var(--ink);
}

.room-type-btn.is-active {
  background: color-mix(in srgb, var(--brand) 10%, transparent);
  border-color: var(--brand);
  color: var(--brand);
  font-weight: 700;
}

.room-members-manage-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 220px;
  overflow-y: auto;
  padding: 4px 2px;
  border-radius: 8px;
}

.room-member-manage-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
}



/* ============================== 房間制排位與通行證樣式 ============================== */

.room-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 20px;
  background: var(--bg);
  border: 1px solid var(--line-strong);
  color: var(--ink-soft);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: nowrap;
}

.room-tab:hover {
  border-color: var(--brand);
  color: var(--ink);
}

.room-tab.is-active {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--on-brass);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--brand) 25%, transparent);
}

.room-tab-badge {
  font-size: 11px;
  padding: 1px 6px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--ink) 8%, transparent);
}

.room-tab.is-active .room-tab-badge {
  background: color-mix(in srgb, var(--on-brass) 25%, transparent);
  color: var(--on-brass);
}

.nav-item-vip {
  color: var(--amber);
  background: color-mix(in srgb, var(--brand) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 25%, transparent);
  margin: 4px 0;
}

.nav-item-vip-icon {
  font-size: 16px;
}

.nav-item-vip-pill {
  font-size: 10px;
  padding: 1px 5px;
  margin-left: auto;
  background: color-mix(in srgb, var(--brand) 20%, transparent);
  color: var(--brass-on-dark);
}

.lb-grace-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--blue) 12%, transparent);
  color: var(--blue);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  vertical-align: middle;
}

.lb-spectator-notice {
  margin: 0 0 16px;
  padding: 12px 16px;
  border: 1px solid color-mix(in srgb, var(--blue) 22%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, var(--blue) 8%, transparent);
  color: var(--blue);
  font-size: 13px;
  line-height: 1.5;
}

.lb-spectators {
  margin-top: 12px;
  color: var(--ink-soft);
  font-size: 12px;
}

.lb-spectators summary {
  cursor: pointer;
  font-weight: 600;
}

.lb-spectators ul {
  margin: 8px 0 0;
  padding-left: 20px;
}

.lb-spectators li {
  margin: 4px 0;
}

.lb-spectators small {
  color: var(--ink-faint);
  margin-left: 4px;
}

.vip-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--brand) 20%, transparent) 0%, color-mix(in srgb, var(--warn) 20%, transparent) 100%);
  border: 1px solid color-mix(in srgb, var(--brand) 45%, transparent);
  color: var(--brand);
  font-size: 11px;
  font-weight: 750;
  padding: 1px 6px;
  border-radius: 4px;
  margin-left: 6px;
  vertical-align: middle;
}

.rooms-explore-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
  max-height: 480px;
  overflow-y: auto;
  padding: 4px 2px;
}

.room-explore-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 10px;
  transition: all 0.2s ease;
}

.room-explore-card:hover {
  border-color: var(--brand);
  box-shadow: var(--shadow-sm);
}

.room-explore-card.is-member {
  border-color: color-mix(in srgb, var(--brand) 40%, transparent);
  background: linear-gradient(180deg, color-mix(in srgb, var(--brand) 4%, transparent) 0%, var(--card) 100%);
}

.sponsorship-order-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--bg);
  border: 1px solid var(--line);
  margin-bottom: 8px;
}

/* 排行榜玩家名稱：點下去看玩家檔案（成就／稱號／持倉總報酬） */
.player-name-button {
  display: inline;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.player-name-button:hover {
  text-decoration: underline;
}

/* 折線圖的軸標與最後一點數值：SVG 用 viewBox 等比縮小，字級要比一般 .axis-label 大 */
.roi-axis-label {
  fill: var(--ink-faint);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.roi-last-value {
  /* 描邊墊在字底下，萬一數值落在折線或格線上仍然讀得到 */
  paint-order: stroke;
  stroke: var(--card);
  stroke-width: 4px;
  stroke-linejoin: round;
  font-variant-numeric: tabular-nums;
}

/* 持倉一覽內嵌的每日報酬率折線圖 */
.roi-series-inline {
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
}

.roi-series-body svg {
  display: block;
  width: 100%;
  height: auto;
}

.roi-series-legend {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.roi-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-faint);
  cursor: pointer;
  transition: all 0.15s ease;
}

.roi-legend-item::before {
  content: '';
  display: inline-block;
  width: 12px;
  height: 4px;
  border-radius: 2px;
  background: var(--ink-faint); /* 次線灰 */
}

.roi-legend-item.is-active {
  color: var(--ink);
  border-color: var(--brand);
  background: var(--card);
  font-weight: 600;
  box-shadow: 0 1px 3px rgba(58, 42, 20, 0.08);
}

.roi-legend-item.is-active::before {
  background: var(--brand); /* 主線 brand */
}

.roi-positive {
  color: var(--down);
  fill: var(--down);
}

.roi-negative {
  color: var(--up);
  fill: var(--up);
}

.grid-line.zero-line {
  stroke: var(--ink-faint);
  stroke-width: 1.5;
  stroke-dasharray: none;
}

/* ===================== 介面風格切換 ===================== */

.theme-picker {
  display: grid;
  /* auto-fit：兩段（主題）排成兩欄、三段（動效強度）排成三欄，
     不會出現「第三個選項孤零零掉到第二排」。 */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--s3);
  margin-top: var(--s3);
}

.theme-option {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  text-align: left;
  padding: 12px 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-soft);
  color: var(--ink);
  cursor: pointer;
}

.theme-option strong {
  font-size: 14px;
}

.theme-option small {
  font-size: 12px;
  color: var(--ink-soft);
  line-height: 1.45;
}

.theme-option.is-active {
  border-color: var(--primary);
  background: var(--primary-soft);
  box-shadow: inset 0 0 0 1px var(--primary);
}

.theme-studio-mark {
  display: none;
}

@media (max-width: 860px) {
  .theme-picker {
    grid-template-columns: 1fr;
  }
}

/* 盤房夜場：同一套設計語言的暗房變體，由設定切換。
   暗底上陰影不可見，所以 elevation 改用「surface 提亮 + 描邊」表達高度。 */
html[data-theme="studio"] {
  --paper: #12110f;
  --paper-sunk: #0c0b0a;
  --sheet: #1b1916;
  --sheet-raised: #221f1a;
  --sheet-top: #2b2721;
  --rule-hair: #2c2823;
  --rule-strong: #6d6457;
  --ink-1: #eae4d8;
  --ink-2: #a69d8b;
  --ink-3: #8a8271;
  --brass: #d9a425;
  --brass-deep: #f0bc46;
  --brass-wash: #2a2317;
  /* 夜場黃銅底一律配近黑字：白字對 #D9A425 只有 2.26:1。 */
  --on-brass: #12110f;
  --gain: #3fae84;
  --loss: #e06a5e;
  --caution: #e5923f;
  --info: #5fa8c9;
  --on-gain: #12110f;
  --on-loss: #12110f;
  --masthead: #0f0e0c;
  --masthead-ink: #cfc7b7;
  --masthead-muted: #8b8372;

  /* 舊版把 --card 綁成 var(--canvas)，卡片與頁底完全同色，等於沒有卡片；
     也把 --brand 綁成 var(--ink)，夜場等於沒有品牌色。兩個都在這裡修掉。 */
  --card: var(--overlay);
  --sidebar-bg: var(--nav);

  --alloc-crypto: #dac281;
  --alloc-tw: #d8a28a;
  --alloc-cash: #a69884;
  --alloc-fund: #808d4c;
  --alloc-us: #9a6d3f;
  --alloc-uk: #a24b45;

  --radius: 3px;
  --radius-sm: 2px;
  --radius-overlay: 4px;

  --surface-1: var(--sheet);
  --surface-2: var(--sheet-raised);
  --surface-3: var(--sheet-top);
  --elev-1: 0 0 0 1px var(--hairline);
  --elev-2: 0 0 0 1px var(--line-strong);
  --elev-3: 0 0 0 1px var(--line-strong), 0 24px 48px rgba(0, 0, 0, 0.62);

}

/* ============================================================
   輕鬆競賽（classic）：v1.0.39 的圓潤綠意介面，保留給習慣舊版的使用者。
   只覆寫語意層，相容層（--canvas / --card / --primary …）自動跟著換。

   色值取自 v1.0.39 的 `:root`（commit aa0b95d），只有七個值做了「同色相、
   最小幅度加深」的無障礙修正 —— 舊版那幾個值實測不過 WCAG，原樣搬回來等於
   把剛修好的對比問題再裝一次。修正前→後與實測值：
     --ink-faint   #8aa094 → #617169   2.50 → 4.62
     --up          #0d9c5a → #0a7f49   3.18 → 4.54
     --down        #d2453f → #c5403b   4.04 → 4.52
     --amber       #d97706 → #a75b04   2.86 → 4.55
     --primary     #168a52 → #147e4b   3.93 → 4.58（白字在它上面也從 4.38 → 5.10）
     --line-strong #d3e0d8 → #848d88   1.22 → 3.06（控制項邊界）
   其餘色值與 v1.0.39 完全相同。
   ============================================================ */
html[data-theme="classic"] {
  --paper: #eef4f0;
  /* 舊版的 --bg-soft 比 --bg 更亮（不是更暗），這裡照搬以維持原本的層次感 */
  --paper-sunk: #f7faf8;
  --sheet: #ffffff;
  --sheet-raised: #ffffff;
  --sheet-top: #ffffff;
  --rule-hair: #e3ece6;
  --rule-strong: #848d88;
  --ink-1: #17251d;
  --ink-2: #4d6157;
  --ink-3: #617169;
  --brass: #147e4b;
  --brass-deep: #0f6e40;
  --brass-wash: #e6f4ec;
  --on-brass: #ffffff;
  --gain: #0a7f49;
  --loss: #c5403b;
  --caution: #a75b04;
  --info: #0e7490;
  --on-gain: #ffffff;
  --on-loss: #ffffff;
  --masthead: #0c2a1c;
  --masthead-ink: #dcebe2;
  --masthead-muted: #9fc4ae;
  /* 深墨綠側欄上的強調色：品牌綠在它上面看不見，用舊版的亮綠 */
  --brass-on-dark: #3ddc90;

  --sidebar-bg: linear-gradient(180deg, #14402c 0%, #0c2a1c 100%);

  /* 舊版的六色彩虹配置條。色相彼此可分辨，但對背景只有 1.9–3.8:1，
     所以 pattern 疊層與圖例文字一律保留（見 .alloc-seg-*）。 */
  --alloc-cash: #10b981;
  --alloc-tw: #3b82f6;
  --alloc-us: #8b5cf6;
  --alloc-uk: #ef4444;
  --alloc-crypto: #f59e0b;
  --alloc-fund: #06b6d4;

  --radius: 14px;
  --radius-sm: 9px;
  --radius-overlay: 18px;

  --surface-1: var(--sheet);
  --surface-2: var(--sheet-raised);
  --surface-3: var(--sheet-top);
  --elev-1: 0 1px 3px rgba(18, 48, 32, 0.06), 0 4px 16px rgba(18, 48, 32, 0.06);
  --elev-2: var(--elev-1);
  --elev-3: 0 8px 30px rgba(18, 48, 32, 0.14);

  /* 字體不覆寫：三套主題共用 :root 的 IBM Plex Sans + 系統中文字。
     v1.0.39 原本是純系統字體堆疊，換回去會讓字母寬度與行高跟另外兩套差一點點
     （實測 nav-item 42px vs 43px、章節標題 58px vs 59px、表格欄寬差 1–2px），
     而「三套只差顏色與風格、尺寸完全一致」是比字體懷舊更重要的約束。 */
}

/* 下面這幾條是把「盤房改版時寫死掉的外觀」在 classic 底下還原回 v1.0.39。
   它們不是 token 能表達的（圓形 vs 方形、有沒有漸層、有沒有陰影）。 */

/* 卡片回到有陰影的浮起感 */
html[data-theme="classic"] .card {
  box-shadow: var(--elev-1);
}

html[data-theme="classic"] .asset-card:hover {
  border-color: var(--line-strong);
  box-shadow: var(--elev-3);
}

/* 圓形圖示鈕 */
html[data-theme="classic"] .icon-button {
  border-radius: 50%;
}

html[data-theme="classic"] .icon-button:hover {
  background: var(--primary-soft);
  color: var(--primary);
  border-color: var(--brand);
}

/* 主要按鈕的綠色漸層與光暈 */
html[data-theme="classic"] .primary-button {
  background: linear-gradient(135deg, #1c9c61, #127a49);
  color: #ffffff;
  box-shadow: 0 4px 14px rgba(18, 122, 73, 0.28);
}

html[data-theme="classic"] .primary-button:hover {
  background: linear-gradient(135deg, #178c56, #0f6e40);
}

/* 側欄 active 的綠色漸層藥丸（盤房版是銅色直條） */
html[data-theme="classic"] .primary-nav::after {
  background: linear-gradient(135deg, #1f9c63, #14804d);
  box-shadow: 0 4px 14px rgba(20, 128, 77, 0.35);
  border-radius: var(--radius-sm);
}

html[data-theme="classic"] .nav-item.is-active {
  color: #ffffff;
}

/* 品牌標記回到實心圓角塊 */
html[data-theme="classic"] .brand-mark {
  background: linear-gradient(135deg, #2fbf7a, #147e4b);
  border-color: transparent;
  border-radius: 12px;
  color: #ffffff;
  box-shadow: 0 4px 12px rgba(47, 191, 122, 0.35);
}

/* 頭像回到綠色漸層 */
html[data-theme="classic"] .avatar {
  background: linear-gradient(135deg, #2fbf7a, #0f6e40);
  color: #ffffff;
}

/* 章節標題在舊版沒有規尺線。只拿掉線，內距留著——三套主題的垂直節奏要一致。 */
html[data-theme="classic"] .section-heading {
  border-bottom-color: transparent;
}

/* 舊版的分頁籤是實心綠膠囊，指示器沿用但換色 */
html[data-theme="classic"] .filter-tabs::after {
  background: var(--primary);
}

html[data-theme="studio"] .theme-fun {
  display: none !important;
}

/* 三套主題的字級、行高與所有尺寸一律相同，只差在顏色與形狀。
   （夜場原本是「桌機高密度」：--fs-body 15px、行高 1.5、控制項 32px、側欄 220px…
   切過去整個版面會縮一圈，讀起來像換了一套 app 而不是換了個配色。） */
html[data-theme="studio"] body {
  background: var(--canvas);
}

html[data-theme="studio"] .sidebar {
  background: var(--nav);
  color: var(--nav-ink);
}

html[data-theme="studio"] .brand-mark {
  border-radius: 2px;
  background: var(--brand);
  color: var(--on-brass);
  box-shadow: none;
}

html[data-theme="studio"] .nav-item {
  border-radius: 0;
  color: var(--nav-ink);
}

html[data-theme="studio"] .nav-item:hover {
  background: transparent;
  color: var(--nav-ink);
}

html[data-theme="studio"] .nav-item.is-active {
  background: transparent;
  color: var(--brass-on-dark);
  box-shadow: none;
}

/* 左側直條現在由 .primary-nav::after 那顆滑動藥丸的 inset box-shadow 提供，
   夜場不需要再畫第二根（畫了會變成兩條且不會跟著滑）。 */
html[data-theme="studio"] .nav-item.is-active::before {
  display: none;
}

html[data-theme="studio"] .nav-unread-badge {
  background: var(--down);
  color: var(--on-loss);
  box-shadow: none;
  animation: none;
}

html[data-theme="studio"] .workspace-head {
  background: var(--canvas);
  backdrop-filter: none;
}

html[data-theme="studio"] .topbar {
  background: var(--canvas);
}

html[data-theme="studio"] .sync-state {
  background: transparent;
  /* 用透明邊框而不是 border: 0 —— 少一條邊框就少 2px 寬高，
     三套主題的幾何就對不齊了。扁平是風格，尺寸不能跟著變。 */
  border-color: transparent;
  border-radius: 0;
}

html[data-theme="studio"] .icon-button {
  border-radius: 2px;
  background: transparent;
}

html[data-theme="studio"] .avatar {
  border-radius: 2px;
  background: var(--brand);
  color: var(--on-brass);
  box-shadow: none;
}

html:not([data-theme="studio"]) .theme-studio-only {
  display: none !important;
}

html[data-theme="studio"] .primary-button {
  background: var(--brand);
  color: var(--on-brass);
  box-shadow: none;
}

html[data-theme="studio"] .primary-button:hover {
  background: var(--primary-strong);
}

html[data-theme="studio"] .filter-tabs,
html[data-theme="studio"] .news-filter-tab {
  border-radius: 0;
}

html[data-theme="studio"] .filter-tab {
  border-radius: 0;
}

html[data-theme="studio"] .filter-tab.is-active,
html[data-theme="studio"] .news-filter-tab.is-active {
  background: var(--inset);
  color: var(--ink);
  border-color: var(--hairline);
}

html[data-theme="studio"] .card,
html[data-theme="studio"] .holdings-book-wrap {
  background: transparent;
  border-color: transparent;
  border-radius: 0;
  box-shadow: none;
}

html[data-theme="studio"] .status-pill {
  color: var(--ink-faint);
  background: transparent;
  border-color: transparent;
  border-radius: 0;
}

html[data-theme="studio"] .status-dot {
  background: var(--ink-faint);
  box-shadow: none;
}

html[data-theme="studio"] .badge-roi {
  border-radius: 0;
  background: transparent;
  border-color: transparent;
}

html[data-theme="studio"] .badge-roi.positive { color: var(--up); }
html[data-theme="studio"] .badge-roi.negative { color: var(--down); }
html[data-theme="studio"] .badge-roi.neutral { color: var(--ink-faint); }

html[data-theme="studio"] .market-btn,
html[data-theme="studio"] .action-btn {
  border-radius: 0;
}

html[data-theme="studio"] .market-btn.is-active {
  background: var(--brand);
  color: var(--on-brass);
  border-color: var(--brand);
}

html[data-theme="studio"] .auth-gate {
  background: var(--canvas);
}

html[data-theme="studio"] .auth-card,
html[data-theme="studio"] .friend-modal-card {
  border-radius: 6px;
  box-shadow: var(--shadow-lg);
  background: var(--overlay);
}

html[data-theme="studio"] .toast {
  background: var(--overlay);
  color: var(--ink);
  border: 1px solid var(--hairline);
  border-radius: 6px;
}

html[data-theme="studio"] .theme-option.is-active {
  background: var(--brass-wash);
  border-color: var(--brand);
  box-shadow: inset 0 0 0 1px var(--brand);
}

@media (max-width: 860px) {
  html[data-theme="studio"] .mobile-nav-item.is-active {
    color: var(--brass-on-dark);
  }

}

/* 漲跌／警示色在表格裡要贏過 `.holdings-table-wrap td { color: var(--ink) }`。
   兩者特異性相同 (0,1,1)，所以靠「後寫的贏」—— 這組必須留在所有表格規則之後。
   （沒有這一段的話，日漲跌欄的紅綠完全不會顯示。） */
td.is-up,
th.is-up {
  color: var(--up);
}

td.is-down,
th.is-down {
  color: var(--down);
}

td.is-warn,
th.is-warn {
  color: var(--warn);
}

.broker-overlap-list { list-style: none; padding: 0; margin: 8px 0; font-size: 13px; }
.broker-overlap-list li { padding: 6px 0; border-bottom: 1px dashed var(--line); }
.broker-overlap-list:empty { display: none; }

/* 外部連結卡：多個連結項目直排，項目之間用細線分隔；新增券商只要多一個 .integration-item。
   卡片夠寬（整排寬的桌機版）時改成並排，分隔線改成直的。 */
#integrationsCard { container-type: inline-size; }
.integration-list { display: flex; flex-direction: column; margin-top: 8px; }
.integration-item { padding: 16px 0 18px; border-top: 1px solid var(--line); min-width: 0; }
.integration-item:first-child { border-top: 0; padding-top: 10px; }
.integration-item:last-child { padding-bottom: 4px; }

@container (min-width: 640px) {
  .integration-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 28px;
  }
  .integration-item,
  .integration-item:first-child,
  .integration-item:last-child { border-top: 0; padding: 10px 0 4px; }
  .integration-item:nth-child(2n) { border-left: 1px solid var(--line); padding-left: 28px; }
  .integration-item:nth-child(n + 3) { border-top: 1px solid var(--line); margin-top: 12px; padding-top: 18px; }
  /* 停用提示在直排時有 34px 上下留白，並排後會讓兩欄高度差太多 */
  .integration-item .empty-hint { padding: 18px 0; }
}

/* 網域搬家：舊網址 retire.piea.uk 才顯示（橫幅常駐 + 每次開啟的彈窗） */
.domain-notice {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 30px;
  background: color-mix(in srgb, var(--warn) 16%, var(--card));
  border-bottom: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
  color: var(--ink);
  font-size: 13.5px;
  line-height: 1.5;
}
.domain-notice[hidden] { display: none; }
.domain-notice > .inline-icon { flex: 0 0 auto; color: var(--warn); }
.domain-notice p { margin: 0; flex: 1; min-width: 0; }
.domain-notice strong { margin-right: 8px; }
.domain-notice-link { color: var(--brand); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
.domain-notice-go {
  flex: 0 0 auto;
  border: 1px solid color-mix(in srgb, var(--warn) 55%, transparent);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font-size: 12.5px;
  font-weight: 600;
  padding: 4px 10px;
  text-decoration: none;
  white-space: nowrap;
}
.domain-notice-go:hover { background: color-mix(in srgb, var(--warn) 14%, transparent); }
.domain-move-card { max-width: 480px; }
.domain-move-deadline {
  margin: 4px 0 12px;
  padding: 10px 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--warn) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.55;
}
.domain-move-deadline strong { color: var(--warn); font-size: 15px; }
.domain-move-list { margin: 0 0 16px; padding-left: 20px; font-size: 13.5px; line-height: 1.65; color: var(--ink-soft); }
.domain-move-list strong { color: var(--ink); }
.domain-move-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.domain-move-actions .primary-button { text-decoration: none; display: inline-flex; align-items: center; justify-content: center; flex: 1 1 auto; }
.auth-domain-notice {
  margin: 0 0 14px;
  padding: 8px 12px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--brand) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 25%, transparent);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-soft);
}
.auth-domain-notice[hidden] { display: none; }
.auth-domain-notice strong { color: var(--ink); margin-right: 6px; }
@media (max-width: 860px) {
  .domain-notice { padding: 8px 14px; font-size: 12.5px; align-items: flex-start; }
}
.integration-head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 12px; }
.integration-head .inline-icon { flex: 0 0 auto; margin-top: 2px; }
.integration-head h3 { margin: 0; font-size: 15px; }
.integration-head p { margin: 4px 0 0; font-size: 13px; color: var(--ink-soft); line-height: 1.5; }

/* ============================== 程式化交易 API 金鑰 ============================== */
.api-key-current {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.api-key-value {
  display: block;
  word-break: break-all;
  font-family: monospace;
  font-size: 13px;
  user-select: all;
  padding: 8px 10px;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--ink);
  width: 100%;
  box-sizing: border-box;
}

.api-key-snippet {
  white-space: pre-wrap;
  font-size: 12px;
  overflow-x: auto;
  padding: 10px 12px;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font-family: monospace;
  margin: 8px 0;
}

/* ============================================================
   動效關閉：系統的 prefers-reduced-motion 與使用者自選的 data-motion="off"
   走同一組規則。全站只有這一處能關動效，不要在別的地方再寫第二份。

   關掉的是「動的過程」，不是功能與終態——所有動畫都壓成 1ms 而不是 none，
   這樣 animationend / Animation.finished 仍然會觸發，靠動畫結束來收尾的邏輯
   （關 modal、移除進場 class）不會卡死。這是「動畫關閉時功能一律不得失效」
   的成本必須付的地方。
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html:not([data-motion="full"]) *,
  html:not([data-motion="full"]) *::before,
  html:not([data-motion="full"]) *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
}

html[data-motion="off"] *,
html[data-motion="off"] *::before,
html[data-motion="off"] *::after {
  animation-duration: 1ms !important;
  animation-delay: 0ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 1ms !important;
  transition-delay: 0ms !important;
  scroll-behavior: auto !important;
}

/* 「輕微」：保留淡入淡出，關掉所有位移、縮放與 stagger。
   位移與 scale 是造成前庭不適的主因，純 opacity 幾乎不會。 */
html[data-motion="lite"] {
  --stagger: 0ms;
  --dur-3: var(--dur-2);
  --ease-spring: var(--ease-out);
}

html[data-motion="lite"] .page-view.is-page-enter {
  animation-name: fade-only;
}

/* View Transitions 的偽元素掛在根元素身上，不是它的後代——中間有空格的
   `html[data-motion="lite"] ::view-transition-new(...)` 永遠不會 match。
   v1.0.40 起 lite 的換頁一直照樣帶著位移，就是漏在這個空格上。
   退場也要一起換：page-exit 帶 translateY(-4px)。 */
html[data-motion="lite"]::view-transition-new(page-stage) {
  animation-name: fade-only;
}

html[data-motion="lite"]::view-transition-old(page-stage) {
  animation-name: fade-out-only;
}

html[data-motion="lite"] .page-view.is-entering.stagger-in > *:not(.skel),
html[data-motion="lite"] .page-view.is-entering .stagger-in > *:not(.skel) {
  animation-name: fade-only;
  animation-delay: 0ms;
}

/* 常駐的無限動畫在 lite 直接停掉：它們是裝飾，不帶資訊。
   骨架本身仍然顯示（它是載入狀態的資訊），只是不掃描、不淡入。 */
html[data-motion="lite"] .skel {
  animation: none;
  opacity: 1;
}

/* 指示器的滑動在 lite 保留但縮短：它帶著「現在選中哪個」的空間資訊，
   關掉會退回瞬間硬切，反而少了訊息。 */
html[data-motion="lite"] .primary-nav::after,
html[data-motion="lite"] .filter-tabs::after {
  transition-duration: var(--dur-1);
}

html[data-motion="lite"] .card:hover,
html[data-motion="lite"] .room-explore-card:hover,
html[data-motion="lite"] button:active {
  transform: none !important;
}

@keyframes fade-only {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fade-out-only {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* off 時骨架也要看得到（它是狀態，不是動效），上面的 1ms 規則會讓它直接到終態。 */
html[data-motion="off"] .skel {
  opacity: 1;
}

/* ============================================================
   切換主題的那一幀：把 transition 全部關掉。
   換主題會讓全站每個 color / background / border-color 的宣告都變值，而全站有
   350+ 個元素掛著顏色類 transition —— 不擋的話一次切換會同時起 40 條以上的
   transition（實測排位榜 43 條），每條都要重繪一塊區域，使用者看到的就是「頓一下」。
   只關 transition 不關 animation：animation 的收尾（Animation.finished）有程式在等，
   而 transition 沒有任何程式依賴 transitionend（已全檔確認 0 處）。
   這個 class 由 swapThemeAttribute() 掛上，下一幀就移除。
   ============================================================ */
html.is-theme-swapping *,
html.is-theme-swapping *::before,
html.is-theme-swapping *::after {
  transition: none !important;
}
