/* Pikmin Log — 行動優先，戶外單手操作為主 */

:root {
  --bg: #0f1419;
  --surface: #182029;
  --surface-2: #212c37;
  --line: #2e3b48;
  --text: #e8eef4;
  --muted: #93a4b5;
  --accent: #4ade80;
  --accent-ink: #062412;
  --danger: #f87171;
  --warn: #fbbf24;
  --radius: 12px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: "Noto Sans TC", "Microsoft JhengHei", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

.wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 16px 16px calc(32px + env(safe-area-inset-bottom));
}

/* 固定貼上面板的收合高度。fixed 讓它離開文件流，底下的內容會被蓋住，
   得由 #app-view 的 padding-top 讓開；釘在它下方的排序／選取列也靠這個值定位。
   這是「面板本身」的高度，不含任何額外留白——需要貼齊面板底緣的元素直接用它，
   中間才不會留下一道縫讓捲動的卡片穿過去。

   2026-08-27 實測 129px：上下 padding 各 14 + 第一列 40 + gap 10 + 輸入列 50 + 下緣線 1。
   （沿革：2026-08-25 標題還在文件流、面板只有輸入列時是 79px；
     同日標題搬進面板、與排序搜尋分列時是 116px；
     同日三者併成一列、圖示鈕還是 50px 時是 139px。）

   改動下列任一項都要回來重量：面板 padding、兩列之間的 gap、--icon-btn-h（決定第一列
   的高度）、--control-h（決定輸入列的高度）、輸入框 rows 或字級。
   登出鈕不影響這個值：它目前隱藏（本站未設通行碼，app.js 在公開模式會藏它），
   出現時是 44px（通用 button 的觸控最小值），會把第一列從 40 撐到 44，屆時要 +4。 */
:root { --paste-panel-h: 129px; }

#app-view {
  /* 讓開頂部那兩層固定元素：貼上列，以及釘在它下方的排序／選取列。
     底部留白沿用 .wrap 原本的值，這裡不覆寫。 */
  padding-top: calc(var(--paste-panel-h) + var(--control-h) + 16px + env(safe-area-inset-top));
}

/* 編輯面板用 scrollIntoView 捲進視野，而視窗頂端正是固定貼上列所在——
   沒有這個 margin，捲過去的面板會有一截躲在列子底下。
   #app-msg 不需要：入庫後改用 window.scrollTo(0, 0)，而 #app-view 的 padding-top
   已經讓開了固定列，捲到 0 提示自然落在列子下方。 */
#editor { scroll-margin-top: calc(var(--paste-panel-h) + var(--control-h) + 24px); }

[hidden] { display: none !important; }

/* ── 頭部 ────────────────────────────────────────────────── */

/* 固定面板的第一列：標題 + 排序 + 搜尋（使用者 2026-08-27 指定三者同一列）。
   原本標題列與工具列是兩塊、分處文件流的上下方，現在合成這一條。
   面板本身有下緣線，這裡不再畫 border-bottom，否則變雙線。

   align-items: stretch 讓這列的控制項自動齊高：input 與 select 的預設行高算法不同
   （實測 48 vs 50），靠 center 對齊會差 2px；stretch 讓沒有明示高度的都長到列高。
   放大鏡鈕有明示 height（要正方形），explicit height 勝過 stretch，故由它決定列高。 */
.bar {
  display: flex;
  align-items: stretch;
  gap: 8px;
  margin-bottom: 10px;
}

.brand {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: .02em;
  margin: 0;
  flex: 1;
  /* 這一列是 align-items: stretch，標題會被拉成整列高。用 align-self 置中，
     **不要**改成 display: flex——flex 會把純文字變成匿名 flex item 並去掉它前後的
     空白，「Pikmin Log」會被擠成「PikminLog」。舊名「78Pikmin」本來就沒空格，
     所以這個問題直到 2026-08-27 改名才浮出來。
     white-space: nowrap 是為了不讓標題在窄螢幕折成兩行把列撐高。 */
  align-self: center;
  white-space: nowrap;
}

/* 搜尋展開時標題讓位：手機寬度容不下「標題 + 搜尋框 + 排序 + 放大鏡」並存，
   硬擠的話搜尋框只剩幾十 px。標題是裝飾性的，收起搜尋就回來。
   隱藏的是 h1（非互動元素），不是按鈕——藏按鈕會讓 click 產生不出來，
   那個坑記在 .paste-row textarea 上方的註解裡。 */
.bar.searching .brand { display: none; }

/* 收起後仍在篩選時，讓放大鏡看得出來是作用中的——否則清單被篩過卻沒有明顯線索。
   （計數列的「符合 N 筆 / 共 M 筆」是另一個線索，這裡是視覺上更快的那個。） */
.bar.has-query .icon-btn { border-color: var(--accent); color: var(--accent); }

.brand span { color: var(--accent); }

/* ── 按鈕 ────────────────────────────────────────────────── */

button {
  font: inherit;
  font-size: 15px;
  line-height: 1.4;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  border-radius: var(--radius);
  padding: 10px 14px;
  cursor: pointer;
  min-height: 44px;           /* 觸控最小命中區 */
}

button:disabled { opacity: .5; cursor: not-allowed; }

button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
}

button.ghost { background: transparent; }
button.danger { color: var(--danger); }

button.big {
  width: 100%;
  min-height: 64px;
  font-size: 18px;
  font-weight: 700;
  margin-bottom: 10px;
}


/* 並排按鈕一律等寬、等高、同 padding / font-size / radius（ui-consistency） */
.row-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.row-2 > button { width: 100%; min-height: 48px; padding: 10px 14px; font-size: 15px; border-radius: var(--radius); }

/* ── 確認對話框 ──────────────────────────────────────────
 * <dialog> 自己會置中（showModal 時 margin: auto）並疊在 top layer，
 * 這裡只負責外觀：外層去掉瀏覽器預設的白底與邊框，內層用既有的 .panel。
 * 按鈕不另寫樣式，沿用 .row-2 —— 與編輯面板的儲存／取消完全一致。 */
.dialog {
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text);
  width: calc(100% - 32px);
  max-width: 400px;
}
.dialog::backdrop { background: rgba(0, 0, 0, .6); }
.dialog-box { margin-bottom: 0; }
/* 內容通常只有一個名稱（刪除確認），置中才像是刻意的排版而不是一句被截斷的話。
   登出那個確認是完整句子，置中一樣讀得順，故不分兩套。 */
.dialog-text { margin: 0 0 16px; font-size: 16px; line-height: 1.6; text-align: center; overflow-wrap: anywhere; }
/* 刪除鈕的紅框，與卡片上的刪除鈕同一個處理方式，不引入新色碼 */
.dialog-box .row-2 button.danger { border-color: var(--danger); }

/* ── 表單 ────────────────────────────────────────────────── */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px;
  margin-bottom: 16px;
}

.panel h2 {
  margin: 0 0 12px;
  font-size: 15px;
  color: var(--muted);
  font-weight: 600;
}

label {
  display: block;
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 4px;
}

input[type="text"],
input[type="password"],
input[type="search"],
textarea,
select {
  width: 100%;
  font: inherit;
  font-size: 16px;             /* < 16px 會讓 iOS Safari 自動放大頁面 */
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 11px 12px;
  margin-bottom: 12px;
  min-height: 44px;
}

textarea { resize: vertical; min-height: 72px; }

input:focus, textarea:focus, select:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 10px; }

.hint { font-size: 12px; color: var(--muted); margin: -6px 0 12px; }

.msg {
  font-size: 14px;
  padding: 10px 12px;
  border-radius: 10px;
  margin-bottom: 12px;
}
.msg.error { background: rgba(248,113,113,.12); color: var(--danger); border: 1px solid rgba(248,113,113,.35); }
.msg.info  { background: rgba(74,222,128,.10); color: var(--accent); border: 1px solid rgba(74,222,128,.30); }

/* ── 工具列 ──────────────────────────────────────────────── */

/* 標題靠 flex: 1 把後面的控制項推到右邊；搜尋展開時標題消失，改由搜尋框吃掉空間。
   min-width: 0 不可省：flex 項目的預設 min-width 是 auto，窄螢幕下輸入框不肯縮，
   會把排序與放大鏡擠出面板外。 */
.bar input[type="search"] { margin-bottom: 0; flex: 1; min-width: 0; }
/* ── 釘在固定面板下方的那一列 ────────────────────────────
 * 兩種狀態共用：一般狀態是「排序 + 選取」，選取模式是「已選 N 筆 + 全選 + ✕」。
 *
 * 使用者 2026-08-27 回報：清單一長，往下捲就看不到這一列，得先捲回頂端才能操作。
 * 先只釘了選取模式那一列，後來要求一般狀態也一起釘。
 *
 * 用 fixed 而不是 sticky，理由與貼上列相同：sticky 的成立有前提（正確的
 * containing block、祖先不能有 overflow / transform），部分 WebView——例如從 LINE
 * 開啟時的內建瀏覽器——實作不完整，一失效就退化成普通元素、跟著捲走。
 * 2026-08-25 貼上列就是為此從 sticky 改成 fixed，同一個坑不踩第二次。
 *
 * top 直接用面板高度貼齊它的底緣，中間不留縫——留了縫，捲動的卡片會從縫裡穿過去
 * （2026-08-27 實測見過，截圖裡露出一截時間戳）。
 *
 * min-height 讓兩種狀態等高：不統一的話（排序列 50、選取列 40）一進出選取模式
 * 底下的內容就會上下跳 10px。
 *
 * z-index 4 低於貼上列的 5：輸入框聚焦長高時應該蓋過這一列，而不是被它切掉。
 * 左右比照 .paste-panel 補回 .wrap 的置中、最大寬度與 16px 內距——fixed 之後
 * 這些都不再繼承。 */
.sortbar {
  position: fixed;
  top: calc(var(--paste-panel-h) + env(safe-area-inset-top));
  left: 0;
  right: 0;
  z-index: 4;
  max-width: 720px;
  margin: 0 auto;
  padding: 8px 16px;
  min-height: calc(var(--control-h) + 16px);
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}

/* ── 選取模式的操作列：釘在貼上列正下方 ──────────────────
 * 使用者 2026-08-27 回報：清單一長，往下捲就看不到「已選 N 筆」與刪除鈕，
 * 得先捲回頂端才能操作。
 *
 * 用 fixed 而不是 sticky，理由與貼上列相同：sticky 的成立有前提（正確的
 * containing block、祖先不能有 overflow / transform），部分 WebView——例如從 LINE
 * 開啟時的內建瀏覽器——實作不完整，一失效就退化成普通元素、跟著捲走。
 * 2026-08-25 貼上列就是為此從 sticky 改成 fixed，同一個坑不踩第二次。
 *
 * z-index 低於貼上列的 5：兩者不會重疊，但輸入框聚焦長高時應該蓋過操作列，
 * 而不是被它切掉。
 * 左右比照 .paste-panel 補回 .wrap 的置中、最大寬度與 16px 內距——fixed 之後
 * 這些都不再繼承。 */
/* fixed 的那一列離開文件流，底下的卡片會被蓋住，由 #app-view 的 padding-top 讓開。
   面板 129 + 這一列 (8 + 50 + 8) = 195。改動 --control-h、--paste-panel-h 或
   .sortbar 的 padding 時要回來重算。 */
.sortbar select { margin-bottom: 0; width: auto; }

/* ── 多選刪除 ────────────────────────────────────────────── */

/* 選取列：筆數靠左（margin-right: auto 把按鈕推到右邊，沿用 .sortbar 的 flex-end）。 */
.select-count { margin-right: auto; align-self: center; font-size: 14px; color: var(--muted); }

/* 勾選框放在卡片右上角。top/right 各 14px，讓 20px 的方框中心落在距角落 24px 處，
   與卡片的內距（12px 14px）看起來協調。

   不吃點擊：整張卡片才是觸控目標（手機上 20px 的方框點不準）。事件全部落到卡片上，
   也省掉「原生切換 + 委派切換」互相抵銷的問題。 */
/* 操作列上的全選勾選框。與卡片上的同一套視覺語言，同樣不吃點擊——
   外層 .icon-btn 有 50px 的命中區，直接點那顆 20px 的方框在手機上點不準。 */
/* 合併後的 ✕：有勾選時整顆變紅，表示這一下會刪東西而不是離開。
   紅色沿用卡片刪除鈕的處理方式（文字與邊框都用 --danger），不引入新色碼。 */
#select-action.danger { color: var(--danger); border-color: var(--danger); }

.master-check {
  pointer-events: none;
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--accent);
}

.card-check {
  pointer-events: none;
  position: absolute;
  top: 14px;
  right: 14px;
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--accent);
}

/* 選取模式下藏掉卡片自己的操作鈕：這時整張卡片是一個大按鈕，
   留著地圖／複製／編輯只會讓人誤觸。用 class 控制而不是 :focus-within——
   後者會在點擊過程中把元素抽掉，理由見 .paste-row textarea 上方的註解。 */
.list.selecting .card-actions { display: none; }

/* 卡片沒有常駐的刪除鈕：每一格都掛一顆 × 視覺太吵（使用者 2026-08-27 決定）。
   刪除有兩條路：左滑露出刪除鈕，或選取模式批次刪。
   標題的右內距只在選取模式下才需要——正常模式右上角是空的，長名稱可以用滿整行。 */
.list.selecting .card-head { padding-right: 32px; }

/* ── 左滑刪除 ────────────────────────────────────────────
 * .card 是定位基準與裁切框，實際位移的是 .card-body；刪除鈕壓在它後面的右側。
 * overflow: hidden 讓沒滑開時的刪除鈕被裁掉，不必另外藏。 */
.card {
  position: relative;
  overflow: hidden;
}

.card-body {
  position: relative;
  z-index: 1;                 /* 疊在刪除鈕之上，沒滑開時完全遮住它 */
  background: var(--surface);
  padding: 12px 14px;
  /* 先跟瀏覽器講好：垂直捲動歸它、水平歸我們。有了這行就不必在 pointermove 裡
     preventDefault 跟捲動搶控制權（那條路要非 passive 監聽，還容易把頁面卡住）。 */
  touch-action: pan-y;
}

/* 手指按著時關掉過場，卡片才會貼著手指走；放開才用動畫收合或彈開 */
@media (prefers-reduced-motion: no-preference) {
  .card-body { transition: transform .18s ease; }
  .card.swiping .card-body { transition: none; }
}

.card.swiped .card-body { transform: translateX(-88px); }

.card-swipe-del {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 88px;
  min-height: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  background: var(--danger);
  color: var(--accent-ink);    /* 深色字壓在紅底上，沿用既有色票 */
  font-weight: 700;
}

/* 選取模式下不能左滑：那時整張卡片是勾選目標，兩種手勢會打架 */
.list.selecting .card-body { touch-action: auto; transform: none; }
.list.selecting .card-swipe-del { display: none; }
.list.selecting .card { cursor: pointer; }
.card.selected { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }

/* 復原鈕長在提示訊息裡，做成文字連結的樣子，不搶提示本身的注意力 */
.link-btn {
  min-height: 0;
  padding: 2px 6px;
  margin-left: 8px;
  font-size: inherit;
  background: transparent;
  border-color: currentColor;
  color: inherit;
}


/* 只放一個字元的方形鈕：padding 用左右相等的值，否則圖示不會在正中央。
   寬度等於 button 的 min-height，看起來才是正方形而不是短橫條。 */
/* 圖示鈕（🔍 / ✕ / 全選勾選框）比一般表單控制項小一號。
   跟輸入框、下拉同高（--control-h 50px）時視覺太重、整排都是方塊
   （使用者 2026-08-27 回報）。40px 仍在可接受的觸控範圍內，
   而且它們旁邊本來就沒有非得對齊的同高元件——排序已經移到清單上方了。
   align-self: center 是必要的：這些鈕住在 align-items: stretch 的列裡，
   有了明示高度就不再被拉伸，不置中的話會貼齊列的頂端。 */
.icon-btn {
  flex: none;
  align-self: center;
  /* 內容可能是一個字元（🔍 / ✕）或一顆勾選框，都要置中 */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-btn-h);
  height: var(--icon-btn-h);
  /* 通用 button 規則有 min-height: 44px（觸控最小命中區），min-height 恆勝過較小的
     height，不歸零的話這裡設 40px 也還是 44px。這幾顆是圖示鈕、面積夠辨識，
     刻意讓它低於 44。 */
  min-height: 0;
  padding: 0;
  text-align: center;
  line-height: 1;
  font-size: 16px;
}

.count { font-size: 13px; color: var(--muted); margin-bottom: 8px; }

/* ── 清單 ────────────────────────────────────────────────── */

.list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }

/* 內距不在這裡，在 .card-body：左滑時位移的是 body，卡片本身要當裁切框。
   內距若留在卡片上，滑動時會先露出一截卡片自己的底色，看起來像破圖。
   背景也交給 .card-body——這裡留著只是萬一 body 沒撐滿時的墊底。 */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.card.pending { border-color: var(--warn); }

.card-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.card-name { font-weight: 700; font-size: 16px; }
.card-name.untitled { color: var(--muted); font-weight: 400; }

.tag {
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--muted);
  border: 1px solid var(--line);
}
.tag.pending { color: var(--warn); border-color: var(--warn); }

.card-meta { font-size: 13px; color: var(--muted); margin-top: 6px; }
.coord { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: 13px; }
.card-note { margin-top: 6px; font-size: 14px; white-space: pre-wrap; overflow-wrap: anywhere; }

.card-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.card-actions button, .card-actions a {
  font-size: 13px;
  min-height: 38px;
  padding: 7px 12px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}

/* ── 按鈕狀態：必須放在所有基礎按鈕規則之後 ────────────────────────
 * 這兩條原本寫在檔案上半部的 button 區塊裡，優先級都是 (0,1,1)，
 * 和後面的 .card-actions button (0,1,1) 與 button.primary (0,1,1) 平手，
 * 於是由「誰在後面」決勝——結果雙雙被壓掉：
 *   · 刪除鈕的紅色被 .card-actions button 的 color: var(--text) 蓋掉，
 *     破壞性動作與「複製」「編輯」外觀完全相同，沒有任何警示
 *   · hover 的框線色被 .card-actions button 的 border 簡寫與 button.primary
 *     的 border-color 蓋掉，只剩登出鈕和取消鈕還有回饋
 * 搬到後面即可，不需要 !important。 */
button:hover,
.card-actions button:hover,
.card-actions a:hover { border-color: var(--muted); }

button.primary:hover { filter: brightness(1.08); }

.card-actions button.danger { color: var(--danger); border-color: var(--danger); }

.empty { text-align: center; color: var(--muted); padding: 32px 16px; }

/* ── 登入 ────────────────────────────────────────────────── */

#login-view .panel { max-width: 380px; margin: 12vh auto 0; }
#login-view .brand { text-align: center; font-size: 24px; margin-bottom: 4px; }
#login-view .hint { text-align: center; margin: 0 0 18px; }

@media (prefers-reduced-motion: no-preference) {
  .card { transition: border-color .15s ease; }
}

/* ── 貼上區 ──────────────────────────────────────────────── */

textarea#paste {
  /* 這裡刻意「不寫」min-height——高度全部交給不帶 id 的選擇器與 JS 處理：
     一行的收合高度由 .paste-row textarea 的 min-height: 0 加上 rows="1" 決定（實測 50px），
     有內容時的高度由 JS 的 growPaste() 依內容設 inline height，
     上限見 .paste-row textarea 的 max-height，失焦收回由 collapsePaste() 清掉 inline height。
     「聚焦就撐成兩行」那條規則已於 2026-08-27 移除（使用者要求點擊維持單行視覺）。

     歷史教訓仍然適用：別在這裡寫 min-height。曾經為了壓過通用 textarea 的 72px
     而寫在這，結果因為帶了 id（優先級 1,0,1）把當時的 focus-within 規則（0,2,1）
     一起壓掉，展開整個失效，而面板裡的說明文字會在聚焦時出現、把面板撐高，
     讓人誤以為展開正常。 */
  /* 必須 ≥16px：低於 16px 時 iOS Safari 一聚焦就自動放大頁面。
     這個框是貼上的主要落點，原本的 15px 會讓 iPhone 每次貼上都先縮放一次。 */
  font-size: 16px;
  font-family: ui-monospace, "Cascadia Mono", Consolas, "Microsoft JhengHei", monospace;
  line-height: 1.6;
}

/* ── 固定在視窗頂部的貼上列 ──────────────────────────────
 * 用 fixed 而非 sticky。sticky 曾經在這裡用過，Chromium 桌面與手機尺寸實測都正常，
 * 但 2026-08-25 有真實使用者回報「每次都要拉到最下方才能填」——sticky 的成立有前提
 * （正確的 containing block、祖先不能有 overflow / transform），部分 WebView
 *（例如從 LINE 開啟時的內建瀏覽器）實作不完整，一失效就退化成普通元素、掉回文件流。
 * fixed 直接相對視窗定位，沒有這些前提，不存在那個失效模式。
 *
 * 代價是元素離開文件流：底下的內容會被蓋住，由 #app-view 的 padding-top 讓開；
 * 也失去 .wrap 的置中與最大寬度，得自己補回來。
 * 左右 padding 用 16px 對齊 .wrap，讓面板內容寬度與卡片一致。
 * 頂部 padding 加 safe-area：加到主畫面全螢幕開啟時，瀏海會蓋住最上面那幾 px。
 */
.paste-panel {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  z-index: 5;
  max-width: 720px;          /* 對齊 .wrap 的 max-width */
  margin: 0 auto;
  border-radius: 0;          /* 貼齊視窗邊緣，圓角會露出底下的內容 */
  /* 只留下緣的線。.panel 原本四周都有 1px 邊框，那 1px 會把內容往內推，
     使輸入框左緣落在 17px、與清單的 16px 差一格。去掉左右邊框後
     內容起點 = 0 + padding 16px，與清單精確對齊；視覺上也才像貼在頂部的工具列。 */
  border: none;
  border-bottom: 1px solid var(--line);
  padding: calc(14px + env(safe-area-inset-top)) 16px 14px;
  box-shadow: 0 10px 24px rgba(0, 0, 0, .5);
}

/* 聊天輸入列：輸入框佔滿剩餘寬度，送出鈕靠右固定寬。
 *
 * align-items 曾經是 stretch，讓送出鈕與輸入框永遠等高（ui-consistency：並排元件
 * 尺寸要一致）。輸入框只有一行、聚焦才長到 132px 時那樣沒問題。
 * 2026-08-26 改成「貼上的內容留在框裡編輯」之後，框會跟著內容長到 40vh，
 * stretch 會連帶生出一顆將近 350px 高的送出鈕——那不是「尺寸一致」要的東西。
 *
 * 改為 flex-end：按鈕固定一列高、貼齊輸入框底部，跟最後一行文字齊平。
 * 這也是 LINE 與各家聊天 app 的做法。收合時兩者仍然等高（見下方 min-height），
 * 也就是使用者當初要求「輸入框和功能鍵一樣大」時看到的那個狀態。 */
.paste-row {
  display: flex;
  gap: 10px;
  align-items: flex-end;
}

/* 一行表單控制項的高度：border 1+1 + padding 11+11 + 一行文字 16px×1.6 ≈ 50px。
   通用 input / textarea / select 規則算出來就是這個值，所以凡是要跟它們並排的
   按鈕都拿這個當高度，才不會差幾 px（ui-consistency：並排元件尺寸要一致）。
   目前兩處在用：貼上列的送出鈕、工具列的放大鏡鈕。 */
:root {
  --control-h: 50px;
  --icon-btn-h: 40px;   /* 圖示鈕小一號，見 .icon-btn */
}
/* 沒有內容時是一行的視覺（rows="1"），有內容才由 growPaste() 長高。
   min-height: 0 是為了壓過通用 textarea 的 72px，否則一行的高度撐不下來。

   刻意用不帶 id 的 .paste-row textarea（0,1,1）而不是 textarea#paste（1,0,1）：
   高度相關的規則全部維持低優先級，才不會壓掉日後加進來的狀態規則。
   2026-08-25 就是把 min-height 寫在帶 id 的選擇器上，連當時的 focus-within 規則
   一起壓掉、展開整個失效，而且被說明文字的高度遮住沒發現。
   （那條 focus-within 規則已於 2026-08-27 移除，但這個優先級紀律仍然有效。）

   絕不用 :focus-within 藏「按鈕」：真實點擊的順序是 mousedown → 焦點轉移 →
   mouseup → click，若 mousedown 讓輸入框失焦而焦點沒落回面板內，按鈕會在 mouseup
   之前就 display: none，那一下點擊便無從產生（2026-08-23「解析框內文字」鈕就是
   這樣掛掉的）。送出鈕因此永遠可見。

   resize: none：一行高的輸入框留著拖曳把手很突兀，且高度本來就自動跟著內容。 */
.paste-row textarea {
  flex: 1;
  min-width: 0;
  margin-bottom: 0;
  min-height: 0;
  resize: none;
  /* 貼上的內容會留在框裡編輯，框由 JS 的 growPaste() 跟著內容長高。這裡收上限：
     超過就停止長高、改由 textarea 自己捲動，否則貼一段長訊息會把整個畫面吃光。
     40vh 是抓「約螢幕四成」——手機上還看得到底下幾張卡片，確認得了剛才記了什麼。
     JS 只寫 height，上下限全部留在 CSS：height 小於 min-height 時 min-height 勝出，
     大於 max-height 時 max-height 勝出，兩邊都不必在 JS 裡複製一份數值。 */
  max-height: 40vh;
  overflow-y: auto;
}
.paste-row button { flex: none; min-height: var(--control-h); }


.card-addr { font-size: 13px; color: var(--muted); margin-top: 4px; overflow-wrap: anywhere; }

/* execCommand 複製備援用的暫時元素；CSP 是 style-src 'self'，故用 class 不用 inline style */
.copy-helper {
  position: fixed;
  top: -1000px;
  left: -1000px;
  opacity: 0;
  pointer-events: none;
}
