Files
arcrun-collector/cmd/arcrun-app/frontend/src/style.css
T

497 lines
25 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Arcrun 桌面 App — **版面**樣式(t193
*
* 🔴 色票/字體/紙張紋理**不在這裡**——那些在 `arcrun-cis.css`(唯一真相源
* InkStoneCo/arcrun-cis/css/arcrun-cis.cssportallandinginstall 共用同一份)。
* leo 08-04:「不會這裡又寫了一個新的 CSS?前面剛剛才說過**不要創造新的**?」
* ⇒ 本檔**只准出現版面與元件**,一律用 var(--...)**不准寫任何 hex 色碼**。
*
* 版面(leo 08-04 指定,附 Google Drive 截圖):
* 「可以完全模仿 gdrive,**左方側邊欄,在右方替換頁面**,
* 你現在做成在底下產生 nav bar,幾乎沒看過這種 nav bar 在下方的,會令人十分不習慣」
*/
html, body { overflow: hidden; height: 100%; }
/* ── 骨架:左欄固定、右側換頁 ── */
#app { display: flex; height: 100vh; }
#side {
width: 216px; flex: none; /* 同 portal #sidenav */
display: flex; flex-direction: column;
padding: 22px 0 14px;
border-right: 2px solid rgba(var(--amber-rgb), .35); /* portal #sidenav 同款 */
}
/* 🔴 lockupCISleo 三次點名)——**用裁淨版**,且**不要底板**:
① 官方原始 PNG1840x560**只有 32% 高度是實際字形**,上下大量留白
⇒ 同樣 height 看起來字很小,且留白會露出底板=leo 看到的白底。
portal 早就改用**裁淨版**986x176,比例 5.602,四邊裁到字腔邊緣)。
⇒ 直接用 portal 那兩張(從它的 base64 抽出,存在 arcrun-cis/trimmed/)。
② 兩張裁淨版**都是透明底** ⇒ 深色模式**不需要**也**不可以**再墊 Ink 底板。
③ 尺寸/切換規則逐字照 portal 的 #sidenav .logo。 */
/* 🔴 leo:「這是 Logo 旁邊**大量空白**」——圖本身已裁淨(實測四邊留白 0),
空白來自**版面**:側欄 216px 扣 padding 剩 152px,而 logo 高 24px 時只有 134px。
⇒ 讓 lockup **填滿可用寬度**(高度由 5.602 的比例自動決定,約 27px),
並照 CIS「clear space = one chevron height」在下方留呼吸空間。 */
#side .brand { display: flex; color: var(--ink); padding: 0 32px 22px; }
#side .brand img { width: 100%; height: auto; display: block; }
#side .brand .wm-paper { display: none; }
:root[data-theme="dark"] #side .brand .wm-ink { display: none; }
:root[data-theme="dark"] #side .brand .wm-paper { display: block; }
/* 側邊欄選中態:**逐字照 portal 的 #sidenav .nav.on**
(leo:「參考現在 Portal 的格式⋯⋯這個比現在膠囊反紅精緻,
重點是**跟 portal 的形象符合**」)
= 不是膠囊實心,而是:amber 字色 + 8% amber 底 右側 2px amber 邊。 */
#side nav { display: flex; flex-direction: column; gap: 4px; }
#side .nav {
display: flex; align-items: center; gap: 10px;
padding: 13px 24px; font-size: 15px; letter-spacing: .08em;
color: rgba(var(--ink-rgb), .6);
border-right: 2px solid transparent;
cursor: pointer; user-select: none;
}
#side .nav:hover { color: var(--ink); }
#side .nav.on {
color: var(--amber);
background: rgba(var(--amber-rgb), .08);
border-right-color: var(--amber);
font-weight: 600;
}
#side .nav .ic { width: 17px; text-align: center; font-size: 14px; opacity: .85; }
#side .nav .cnt { margin-left: auto; font-size: 11.5px; opacity: .7; font-family: ui-monospace, Menlo, monospace; }
#side .nav .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#side .side-foot { margin-top: auto; padding: 12px 22px 0; }
#side .ver { font-size: 12px; color: rgba(var(--ink-rgb), .35); font-family: ui-monospace, Menlo, monospace; }
#content { flex: 1; min-width: 0; display: flex; flex-direction: column; }
header {
padding: 22px 28px 16px;
display: flex; align-items: flex-start; gap: 18px;
border-bottom: 1px solid rgba(var(--ink-rgb), .1);
}
.status { flex: 1; min-width: 0; }
.status .big { font-size: 18px; font-weight: 600; letter-spacing: .02em; }
.status .sub { margin-top: 5px; font-size: 13.5px; color: rgba(var(--ink-rgb), .5); }
/* 同步中會呼吸——「看得出來在動」(issue #17) */
.status .big.syncing::after {
content: ""; display: inline-block; width: 7px; height: 7px; margin-left: 9px;
border-radius: 50%; background: var(--amber); vertical-align: middle;
animation: pulse 1.1s ease-in-out infinite;
}
@keyframes pulse { 0%,100% { opacity: .25 } 50% { opacity: 1 } }
main { flex: 1; overflow-y: auto; padding: 20px 28px 28px; }
/* ── 元件:規格**逐字對齊 portal**(leo:「網頁的按鈕比較精緻,跟現有的差異較大」)──
portal: .btn { padding:13px; font-size:16px; font-weight:600; border-radius:10px; border:none; background:var(--amber) }
.btn3 { padding:11px 16px; font-size:15px; border-radius:10px; border:1px solid rgba(ink,.25); background:none }
這裡只把 padding 依桌面視窗略收(網頁是手機優先、桌面不需要那麼大的點擊區)。 */
button {
padding: 10px 16px; font-size: 14.5px; border-radius: 10px;
border: 1px solid rgba(var(--ink-rgb), .25);
background: none; color: rgba(var(--ink-rgb), .7);
cursor: pointer; transition: background .12s, color .12s, border-color .12s;
}
button:hover { background: var(--well); color: var(--ink); }
button:disabled { opacity: .45; cursor: default; }
button.primary {
border: none; background: var(--amber); color: var(--knob); font-weight: 600;
}
button.primary:hover { filter: brightness(1.06); background: var(--amber); }
button.ghost {
border-color: transparent; background: none;
color: rgba(var(--ink-rgb), .45); padding: 7px 10px; font-size: 13px;
}
button.ghost:hover { color: var(--err); background: transparent; }
/* 主題切換(portal 有,daemon 也要有——leo:「它有淺色佈景?」
⇒ 是,portal **預設淺色**,深色由使用者切換並存 localStorage。 */
#themeBtn { padding: 7px 11px; font-size: 13px; }
.card {
background: var(--well); border-radius: 12px;
padding: 18px 20px; margin-bottom: 14px;
}
.card h3 { margin: 0 0 4px; font-size: 15px; }
.card .d { font-size: 13.5px; color: rgba(var(--ink-rgb), .55); line-height: 1.8; }
.card .row { display: flex; align-items: center; gap: 12px; }
.card .row .g { flex: 1; min-width: 0; }
/* 「這些檔案還讀不了」清單(G-6.2)。刻意**不用紅色/錯誤色**:
這不是使用者做錯了什麼,是我們還沒支援——語氣要是告知,不是指責。 */
.skiplist { margin: 10px 0 0; padding: 0; list-style: none; }
.skiplist li {
font-size: 13.5px; padding: 6px 0;
border-top: 1px solid rgba(var(--ink-rgb), .08);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.skiplist li.more { color: rgba(var(--ink-rgb), .45); }
.acct { padding: 4px 2px 8px; display: flex; align-items: baseline; gap: 10px; }
.acct .name { font-size: 14.5px; font-weight: 600; }
.acct .host { font-size: 12px; color: rgba(var(--ink-rgb), .4); font-family: ui-monospace, Menlo, monospace; }
.folder {
padding: 11px 15px; margin-bottom: 7px;
background: var(--well); border-radius: 10px;
display: flex; align-items: center; gap: 12px;
}
.folder .path { flex: 1; min-width: 0; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.folder .tag { font-size: 12px; color: var(--ok); white-space: nowrap; }
/* arcrun-rag#46:收回中=進行中的狀態,不是「一切正常」,所以不用綠色。 */
.folder .tag.retiring { color: rgba(var(--ink-rgb), .5); }
.folder-note { margin: -3px 0 9px; padding: 0 15px; font-size: 12.5px; }
.big-num { font-size: 26px; font-weight: 600; letter-spacing: .01em; }
.kv { display: flex; gap: 26px; margin-top: 4px; }
.kv .k { font-size: 12.5px; color: rgba(var(--ink-rgb), .45); }
.empty { padding: 52px 24px; text-align: center; }
.empty .t { font-size: 17px; font-weight: 600; margin-bottom: 10px; }
.empty .d { font-size: 14px; color: rgba(var(--ink-rgb), .55); line-height: 1.9; margin-bottom: 20px; }
/* ── 首次啟動精靈(issue #23):兩步,讓人隨時知道「我做到哪了」──
步驟點沿用首頁「狀態時間軸」同一套配色邏輯(done=--ok、on=--amber),
不另外發明一組顏色。 */
.ob { max-width: 520px; margin: 0 auto; padding-top: 36px; }
.obdots {
display: flex; align-items: center; justify-content: center;
gap: 8px; margin-bottom: 18px;
}
.obdot {
width: 26px; height: 26px; border-radius: 50%; flex: none;
display: flex; align-items: center; justify-content: center;
font-size: 12.5px; font-weight: 600; font-family: ui-monospace, Menlo, monospace;
background: rgba(var(--ink-rgb), .1); color: rgba(var(--ink-rgb), .45);
}
.obdot.on { background: var(--amber); color: var(--knob); }
.obdot.done { background: var(--ok); color: var(--knob); }
.obline { width: 40px; height: 2px; background: rgba(var(--ink-rgb), .12); }
.obcap {
font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
color: rgba(var(--ink-rgb), .4); margin-bottom: 14px;
}
.obintro { text-align: left; max-width: 420px; margin: 0 auto 24px; }
.obintro p { margin: 0 0 10px; }
.obchoice {
display: flex; gap: 14px; margin-top: 22px; text-align: left;
flex-wrap: wrap; justify-content: center;
}
.obcard {
flex: 1 1 200px; max-width: 240px;
background: var(--well); border-radius: 12px; padding: 16px 18px;
display: flex; flex-direction: column; gap: 8px;
}
.obcard .obh { font-size: 14.5px; font-weight: 600; }
.obcard .d { margin-bottom: 4px; }
.obcard button { margin-top: auto; }
label.radio { display: flex; align-items: flex-start; gap: 10px; margin: 12px 0; font-size: 14px; cursor: pointer; }
label.radio input { margin-top: 3px; }
input[type=text], input[type=password] {
width: 100%; box-sizing: border-box; padding: 9px 12px; font-size: 14px;
border: 1px solid rgba(var(--ink-rgb), .18); border-radius: 8px;
background: var(--paper-b); color: var(--ink);
}
.field { margin: 14px 0; }
.field .lb { font-size: 13px; margin-bottom: 6px; color: rgba(var(--ink-rgb), .6); }
.err { color: var(--err); font-size: 13px; margin-top: 10px; }
.acts { display: flex; gap: 8px; margin-top: 18px; }
/* 覆蓋層:只給「確認刪除」這類必須打斷的動作,設定頁一律走右側換頁 */
.overlay {
position: fixed; inset: 0; background: rgba(0,0,0,.42);
display: flex; align-items: center; justify-content: center;
opacity: 0; pointer-events: none; transition: opacity .14s;
}
.overlay.on { opacity: 1; pointer-events: auto; }
.sheet {
width: min(460px, calc(100vw - 64px));
background: var(--paper-a); color: var(--ink);
border: 1px solid rgba(var(--ink-rgb), .12);
border-radius: 14px; padding: 22px 24px;
box-shadow: 0 18px 50px rgba(0,0,0,.28);
}
.sheet h2 { margin: 0 0 6px; font-size: 16.5px; }
.sheet p { margin: 0 0 4px; font-size: 14px; color: rgba(var(--ink-rgb), .55); line-height: 1.7; }
.sheet .acts { justify-content: flex-end; }
/* ── 每個知識庫一個獨立分頁(leo 08-04)──
「同步資料夾那個頁面如果有 2 個庫,每個庫有 30 個同步資料夾,**放得下嗎**?
應該**一個庫有一個頁簽**或是其他方法可以切換。」
「『加入資料夾』按下後**會加在哪個帳號**?**有必要每個帳號有獨立的一個頁面**。」
⇒ 側邊欄直接列出每個知識庫;點進去就是那個庫的頁,動作全部作用在它身上,不會加錯。 */
#side .sec {
padding: 16px 26px 6px; font-size: 11.5px; letter-spacing: .08em;
color: rgba(var(--ink-rgb), .35);
}
#side .nav .cnt {
margin-left: auto; font-size: 11.5px; opacity: .7;
font-family: ui-monospace, Menlo, monospace;
}
#side .nav .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 每個庫的頁首:庫名+網址+「開啟知識庫網頁」(leo:不該放首頁,要在各庫上方) */
.libhead {
display: flex; align-items: center; gap: 14px;
padding-bottom: 14px; margin-bottom: 14px;
border-bottom: 1px solid rgba(var(--ink-rgb), .1);
}
.libhead .g { flex: 1; min-width: 0; }
.libhead .nm { font-size: 16px; font-weight: 600; }
.libhead .host {
font-size: 12px; color: rgba(var(--ink-rgb), .4);
font-family: ui-monospace, Menlo, monospace;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 狀態時間軸(leo:「如果看守、發現變化、萃取、上傳… 不同 status 在哪裡顯示?」) */
.steps { display: flex; flex-direction: column; gap: 2px; margin-top: 12px; }
.step { display: flex; align-items: center; gap: 11px; padding: 7px 0; font-size: 14px; }
.step .dot {
width: 9px; height: 9px; border-radius: 50%; flex: none;
background: rgba(var(--ink-rgb), .18);
}
.step.done .dot { background: var(--ok); }
.step.now .dot { background: var(--amber); animation: pulse 1.1s ease-in-out infinite; }
.step.now { font-weight: 600; }
.step .t { flex: 1; }
.step .m { font-size: 12.5px; color: rgba(var(--ink-rgb), .45); }
/* 展開收合的細節區塊(<details>,原為 leo 2026-08-06 逐檔失敗卡所寫:
「顯示沒通過的名稱,旁邊有個三角形,點擊看到失敗細節,default 摺疊起來」)。
t2102026-08-08)沿用同一套三角形樣式,改包「送不上去」的分類統計。 */
.fail { border-top: 1px solid rgba(var(--ink-rgb), .10); }
.fail:first-child { border-top: 0; }
.fail > summary {
cursor: pointer;
padding: 10px 2px;
font-size: 14px;
line-height: 1.5;
word-break: break-word;
list-style: revert; /* 保留原生三角形 */
}
.fail > summary::marker { color: var(--amber); }
.fail[open] > summary { font-weight: 600; }
/* 「送不上去」展開後的分類清單:只有分類名稱與份數兩欄,不逐檔列名
t210 leo 08-08:「不解釋細節……想看細節才展開」——展開後也只到分類為止)。 */
.breaklist { margin: 8px 0 0; padding: 0; list-style: none; }
.breaklist li {
display: flex; justify-content: space-between; gap: 12px;
font-size: 13.5px; padding: 6px 2px;
border-top: 1px solid rgba(var(--ink-rgb), .08);
}
.breaklist li:first-child { border-top: 0; }
.breaklist li span:last-child { color: rgba(var(--ink-rgb), .55); white-space: nowrap; }
/* t2152026-08-08leo:「在每個知識庫上顯示是否要更新」)——首頁「知識庫版本」卡、
各庫頁版本列、側邊欄警示點,三處共用同一組顏色:落後=--err(同 .err 那個紅),
不是額外發明一個「警告色」。 */
.kblist { display: flex; flex-direction: column; gap: 2px; margin-top: 10px; }
.kbrow {
display: flex; align-items: center; justify-content: space-between; gap: 12px;
padding: 9px 0; border-top: 1px solid rgba(var(--ink-rgb), .08);
}
.kbrow:first-child { border-top: 0; }
.kbrow .nm { font-size: 14px; font-weight: 600; flex: none; }
.kbrow .right { display: flex; align-items: center; gap: 10px; font-size: 13px; }
.kbver { margin-bottom: 14px; font-size: 13.5px; display: flex; align-items: center; gap: 10px; }
.warn { color: var(--err); font-size: 13px; }
#side .nav .dot.warn {
width: 7px; height: 7px; border-radius: 50%; flex: none;
background: var(--err); margin-left: 4px;
}
/* ══════════════════════════════════════════════════════════════════════════
App 啟動器(arcrun-rag#137
leo 2026-08-24:「所有的 App 需要有一個類似 Android/iOS 的**九宮格啟動界面**
每個 App 有一個 icon,這會運行在 portal 及 daemon。」
🔴 尺寸/圓角/間距逐項照 leo 已核准的設計稿(Launcher-Desktop.dc.html):
磁磚 88x88、圓角 22、格線 gap 32/24、hover 上浮 2px、標籤 14px 置中。
🔴 顏色**一個 hex 都不准出現**——全部走 arcrun-cis.css 的變數(本檔開頭那條規矩)。
══════════════════════════════════════════════════════════════════════════ */
/* 頁首:知識庫名 + 幾個 App + 重新整理(同 .libhead 的結構,不另發明一種頁首) */
.apphead {
display: flex; align-items: center; gap: 14px;
padding-bottom: 18px; margin-bottom: 26px;
border-bottom: 2px solid rgba(var(--amber-rgb), .35); /* 設計稿的 accentSoft 分隔線 */
}
.apphead .g { flex: 1; min-width: 0; }
.apphead .t { font-size: 22px; font-weight: 600; letter-spacing: .04em; }
.apphead .s { margin-top: 5px; font-size: 13.5px; color: rgba(var(--ink-rgb), .55); }
/* 多個知識庫時才出現的切換器(只有一個庫時畫面上不該有這排噪音) */
.appswitch { display: flex; gap: 8px; margin-bottom: 20px; flex-wrap: wrap; }
/* 圓角用 10px(同 button),刻意**不用**膠囊——check-cis.sh 明文擋膠囊選中態
(leo 08-04 否決過),而且這排切換器與按鈕本來就該是同一種形狀語彙。 */
.appswitch .chip {
padding: 6px 13px; font-size: 13px; border-radius: 10px;
border: 1px solid rgba(var(--ink-rgb), .18);
color: rgba(var(--ink-rgb), .6); cursor: pointer; user-select: none;
}
.appswitch .chip.on {
border-color: var(--amber); color: var(--amber);
background: rgba(var(--amber-rgb), .08); font-weight: 600;
}
/* 九宮格本體。auto-fill 而不是固定 4 欄:桌面視窗是可以被拉窄的(min 820px),
固定欄數會在窄視窗把磁磚擠變形。 */
.appgrid {
display: grid; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr));
gap: 32px 24px;
}
.appcell { display: flex; flex-direction: column; align-items: center; gap: 11px; }
.apptile {
width: 88px; height: 88px; border-radius: 22px;
display: flex; align-items: center; justify-content: center;
font-size: 38px; line-height: 1;
background: var(--well); border: 1px solid rgba(var(--ink-rgb), .1);
cursor: pointer; user-select: none;
transition: border-color .12s, background .12s, transform .12s;
}
.apptile:hover {
transform: translateY(-2px);
border-color: var(--amber);
background: rgba(var(--amber-rgb), .08);
}
/* 「加裝 App」——設計稿是虛線框+加號,語意是「這一格還沒有東西」 */
.apptile.add {
background: none; border: 1.5px dashed rgba(var(--ink-rgb), .22);
font-size: 28px; color: rgba(var(--ink-rgb), .45);
}
.appcell .nm {
font-size: 14px; text-align: center; line-height: 1.4;
max-width: 116px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.appcell .nm.dim { color: rgba(var(--ink-rgb), .55); }
/* App 頁 */
.appview { display: flex; flex-direction: column; }
.appview .head {
display: flex; align-items: center; gap: 12px;
padding-bottom: 14px; margin-bottom: 16px;
border-bottom: 1px solid rgba(var(--ink-rgb), .1);
}
.appview .head .ico { font-size: 24px; line-height: 1; }
.appview .head .nm { font-size: 17px; font-weight: 600; }
.appview .head .vr {
font-size: 12px; color: rgba(var(--ink-rgb), .4);
font-family: ui-monospace, Menlo, monospace;
}
.appview .head .sp { flex: 1; }
/* App 自帶畫面:**關在 sandbox iframe 裡**(見 main.js mountAppUI 的理由)。
高度吃滿剩下的版面,讓 App 自己決定要怎麼排。 */
/* 高度用 calc 而不是 flex:1height:100%#page 是 flex item 自帶 padding
百分比高度在那裡會多算出一段 padding 而長出一條假捲軸。
250px=頁首(約 90) + main padding(48) + App 頁首(約 60) + 呼吸。 */
.appframe {
width: 100%; height: calc(100vh - 250px); min-height: 420px;
border: 1px solid rgba(var(--ink-rgb), .1); border-radius: 12px;
background: var(--paper-a);
}
/* 沒有自帶畫面的 App=列出它的工作流,一條一顆「現在執行」
(與 Portal 的系統預設畫面同一套呈現,不另立第二種) */
.wfitem {
background: var(--well); border-radius: 12px;
padding: 15px 18px; margin-bottom: 10px;
}
.wfitem .top { display: flex; align-items: baseline; gap: 12px; }
.wfitem .nm { font-size: 15px; font-weight: 600; flex: 1; min-width: 0; }
.wfitem .d { margin-top: 7px; font-size: 13.5px; color: rgba(var(--ink-rgb), .55); line-height: 1.7; }
.wfitem .out {
margin-top: 8px; font-size: 12.5px; line-height: 1.6;
font-family: ui-monospace, Menlo, monospace;
color: rgba(var(--ink-rgb), .55);
word-break: break-all; white-space: pre-wrap;
}
.wfitem .out.bad { color: var(--err); }
/* ══════════════════════════════════════════════════════════════════════════
資料夾結構樹(`inkstone/InkStoneCo#44` 桌面那半;形狀規格 `inkstone/Arcrun#144`
leo 2026-08-19(驗 1.4.49 的 markmap 之後打回):
「我的需求是**向右向下**,類似 terminal 的 tree**一列一列向下往後退縮**,
緊湊但可點擊展開,**模擬 Windows 的檔案總管的 tree**⋯⋯
可以用滑鼠輕易操作,**不會佔用大面積**。」
⇒ 這一段的每個數字都在服務那句話:
· 一列 = 一個 flex row,靠 padding-left 退縮(縮排 16px/層,同檔案總管量級)
· 行高壓到 20px 上下、字級 13px ⇒ 1080p 一個畫面塞得下數十列
· 三角形+資料夾 icon 在最左,數字與原因往右排,掃視時眼睛只走一條直線
🔴 顏色一個 hex 都不准出現(本檔開頭那條規矩)——全部走 arcrun-cis.css 的變數。
══════════════════════════════════════════════════════════════════════════ */
.ftbox {
margin: -3px 0 9px; padding: 8px 10px 6px;
background: var(--well); border-radius: 10px;
}
.fthead {
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
padding-bottom: 7px; margin-bottom: 5px;
border-bottom: 1px solid rgba(var(--ink-rgb), .08);
}
.fthead button { padding: 4px 9px; font-size: 12px; }
/* 樹本體:檔案總管那種「緊湊但點得到」的密度。
overflow-x 讓很深的樹自己捲,不去撐破右側版面。 */
.ftbody { overflow-x: auto; padding: 1px 0; }
.ftrow {
display: flex; align-items: baseline; gap: 7px;
padding: 2px 4px 2px 0; font-size: 13px; line-height: 1.5;
white-space: nowrap; border-radius: 5px;
}
/* 有子資料夾的那幾列才可點——整列都是點擊區(三角形只有 12px,滑鼠不好瞄)。 */
.ftrow.has { cursor: pointer; user-select: none; }
.ftrow.has:hover { background: rgba(var(--amber-rgb), .08); }
.ftrow.has:focus-visible { outline: 2px solid var(--amber); outline-offset: -2px; }
/* 三角形:**用 CSS 畫,不用字元**。
leo 2026-08-19 打回 markmap 的其中一條理由就是「**展開字很小**⋯⋯
用戶要擁有觸控板,否則很難閱讀」——▸▾ 這兩個字在不同平台的中文字型裡
大小與位置都不一樣(Windows 常被當全形處理),畫出來的則到處一致。 */
.ftrow .tw {
width: 14px; flex: none; align-self: center;
display: inline-flex; align-items: center; justify-content: center;
}
.ftrow .tw i {
display: block; width: 0; height: 0;
border-left: 5px solid rgba(var(--ink-rgb), .5);
border-top: 4px solid transparent; border-bottom: 4px solid transparent;
transition: transform .12s;
}
.ftrow.open .tw i { transform: rotate(90deg); }
.ftrow.has:hover .tw i { border-left-color: var(--amber); }
.ftrow .ic { flex: none; font-size: 12.5px; }
.ftrow .nm { font-weight: 500; }
.ftrow .num {
font-family: ui-monospace, Menlo, monospace; font-size: 12px;
color: rgba(var(--ink-rgb), .55);
}
/* 全部同步完=這一格沒有待辦,用完整墨色讓它從灰階裡浮出來(不另發明「成功色」)。 */
.ftrow .num.full { color: var(--ink); }
/* 🔴 選擇器**不要**綁在 .ftrow 底下:頁首那句「為什麼只收這些」也用同一個 class,
綁死就只有樹裡面吃得到樣式、頁首那句會掉回 16px 的內文級——實撞過一次,
畫面上那句話比整棵樹都大聲,喧賓奪主。 */
/* 「為什麼沒上去」是次要資訊:**它可以被截斷,資料夾名字不行**。
(整棵未收的理由是一整句話,不截的話一列會長到把樹推出畫面外。)
截掉的部分留在 title 裡,滑鼠停著就看得到全文。 */
.ftbox .why {
font-size: 12px; color: rgba(var(--ink-rgb), .45);
flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
}
.fthead .why { flex: 1; min-width: 0; line-height: 1.6; }
/* 整棵沒走進去:語氣是告知不是錯誤,所以不用 --err。 */
.ftrow .skip {
font-size: 11.5px; color: rgba(var(--ink-rgb), .5);
border: 1px solid rgba(var(--ink-rgb), .18); border-radius: 5px; padding: 0 5px;
}
.ftmsg {
padding: 6px 2px 2px; font-size: 12px; line-height: 1.65;
color: rgba(var(--ink-rgb), .45);
}