/* shell.css — 官網的「殼」：左欄＋右正文的版面、側欄元件、主題鈕、滑鼠亮點。
 *
 * 出身（2026-09-09 [Mate-2]）：Strider 看完 v3 上線的官網說「點進其他分頁，
 * 電腦版跟手機版都會直接強制轉成手機版的解析度」。實際量出來是 25 個子頁
 * 一頁都沒有首頁那層殼：notes 那 20 頁在 1440 螢幕上主欄只有 512px（佔 36%）。
 *
 * 這份是從 index.html 的內嵌 <style> **用程式抽出來的**，不是手抄，
 * 所以值跟首頁一模一樣、不會有第二套數字。
 *
 * 🔑 為什麼不用自己帶色票：實查過 25 個子頁，--bg／--text／--text-2／--text-meta／
 *    --line／--accent／--surface 這七個變數**每一頁都有**（同名、各頁自己的值），
 *    所以殼直接吃各頁的色票就會對，深淺兩模式也跟著各頁走。
 *
 * ⚠️ 待辦（下一刀）：首頁目前還是吃自己內嵌的那份、沒改吃這支 ⇒ 同一件事兩份來源。
 *    這一輪先讓子頁有殼可用；首頁換吃這支要連同前後對照一起驗，不在同一刀做。
 */

/* ── 殼自己的後備色票（2026-09-09 [Mate-2]）──────────────────────────────
 * 實查 25 個子頁：--bg／--text／--text-2／--text-meta／--line／--accent／--surface
 * 每頁都有；但殼還用到另外三個，多數子頁沒有：
 *   --shadow-2（主題鈕的陰影・25 頁缺）／--accent-border（21 頁缺）／--red（2 頁缺）
 * 🔑 治法是「殼自己帶預設」，不是要 25 頁各自去加一行 —— 殼不該要求頁面配合。
 * 值直接取自 index.html 的深淺兩套，不是我另外挑的。
 * ⚠️ 這一段只有在 <link rel="stylesheet" href="/assets/shell.css"> **放在該頁自己的
 *    <style> 之前** 才會被頁面正確覆蓋（同特異性、後宣告者勝）。套殼腳本會保證這個順序。
 * ⓘ --mx／--my 不在這裡：那兩個是滑鼠亮點的座標、由 JS 執行時寫進去，
 *   CSS 端本來就寫成 var(--mx,50%) 有預設值（首頁自己也「沒宣告」）。
 */
:root{
  --shadow-2:0 3px 8px rgba(0,0,0,.45);
  --accent-border:rgba(158,193,232,0.45);
  --red:#D93B1A;
}


.layout{ max-width:1280px; margin:0 auto; padding:40px 26px 120px; }
.avatar{ width:84px; height:84px; border-radius:50%; object-fit:cover; object-position:50% 38%; border:2px solid rgba(255,255,255,0.92); flex-shrink:0; }
.cat-avatar{ width:48px; height:48px; border-radius:50%; object-fit:cover; object-position:50% 35%; border:2px solid rgba(255,255,255,0.92); flex-shrink:0; }
.portrait-row{ display:flex; align-items:center; gap:12px; }
.side-top{ display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
.nav{ display:none; }
.side-bottom{ display:none; }
.enrole{ font-size:12px; letter-spacing:0.24em; color:var(--text-meta); text-transform:uppercase; margin-top:9px; }
/* 主題切換鈕（右上、固定） */
  .theme-btn{ position:fixed; top:14px; right:14px; z-index:98; width:40px; height:40px; border-radius:50%; border:1px solid var(--line); background:var(--surface); cursor:pointer; display:flex; align-items:center; justify-content:center; box-shadow:var(--shadow-2); padding:0; }
.theme-btn svg{ width:18px; height:18px; fill:none; stroke:var(--text-2); stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round; }
.theme-btn .ic-moon{ display:none; }


body, .demo, .db.bot, .board, .cmpc, .fbox, .fstep, .theme-btn{ transition:background-color .35s ease, color .35s ease, border-color .35s ease; }
/* 捲動進度線（v34/v40 progress bar → 頂端 2px 朱紅髮絲線） */
  .progress-top{ position:fixed; top:0; left:0; height:2px; width:0; background:var(--red); z-index:99; }
/* 小標籤：對標 13/17 = 1.31 */
.nav-link{ line-height:1.43; }
/* ── ④ 互動元素字重 500（對標唯一的強調手段就是字重，不用顏色不用底線）── */
.nav-link,.cta,.fab-line,a.ln,.side-line{ font-weight:500; }
.side-line{ border-radius:8px; padding:8px 20px; }
/* 按鈕不該斷行；焊詞 span 掉進 flex+gap 會被推出假間隙，所以按鈕內不焊詞、改由容器 nowrap */
/* 🔴 只有「短按鈕」才 nowrap。.cta 在內頁是長文案按鈕（一整句話），
   nowrap 會把它撐出視窗＝手機左右滑（2026-08-24 實撞：390px 溢出 450px）。 */
.fab-line,.side-line,.nav-link{ white-space:nowrap; }
＝為了讓內容疊在 ambient 之上。
      但 body 底下有三個 position:fixed（.progress-top z99／.theme-btn z98／.fab-line z60），
      被這條 blanket 規則一起蓋成 relative ⇒ 捲到 scrollY=2000 三個全離開畫面。
      實測 WebKit 390：.fab-line fixed/top776 → relative/top4417＝**手機唯一的主要 CTA 直接消失**。
   ② 改成 .amb{ z-index:-1 }
按鈕救回來了，但 body 底色是不透明的 rgb(10,10,10)
      ⇒ ambient 被壓到背景後面、整層看不見（v8 的重點就沒了）。截圖確認過。
   ✅ 正解＝**只抬內容那一個容器**：全站內容都在單一 .layout 裡，三個 fixed 各自有 z-index
      （60/98/99 都 > 1）所以不受影響。不要對 body>* 下全稱規則。 */
.layout{ position:relative;z-index:1 }

/* ══ 2026-09-09 [Mate-2] 左欄底部社群圖示（對標第二件）══
     對標 brittanychiang.com 的做法：左欄最底一排單色圖示、hover 才亮。
     我們原本只有頁尾的三個文字連結——那三個是 4號 的 SEO sameAs、**原封不動**，
     這裡是「加一排圖示」不是「把文字換掉」。
     圖示＝office 🎨 SVG 素材庫/simple-icons（官方品牌單色 path、24×24）。 */
  .side-social{ display:flex; gap:16px; margin-top:16px; }
.side-social a{ display:inline-flex; color:var(--text-meta); transition:color .18s ease, transform .18s ease; }
.side-social a:hover{ color:var(--accent); transform:translateY(-2px); }
.side-social svg{ fill:currentColor; display:block; }
.side-social a:focus-visible{ outline:2px solid var(--accent); outline-offset:4px; border-radius:3px; }

/* ══ 2026-09-09 [Mate-2] 導覽收成四項（對標第四件）══
     實測對標 brittanychiang.com 只有三個分類（About／Experience／Projects）——
     他「分得好」不是名字取得好，是**只有三個**：三個一眼看完，八個要用讀的。
     0號 裁：四項＝關於我／服務與費用／案例／聯絡。

     🔴 我這一輪**只改導覽、沒有搬動任何區塊**：
        0號 原本的做法還包含「適合對象併進開頭一小段、常見問題收成段尾折疊」，
        那會動到錨點、GSAP 觸發器與 #notes 邊界（4號 的）。
        先讓他看四項導覽的效果——如果光是四項就解決了「分類太多」的感覺，
        區塊根本不用搬。搬區塊是不可逆的大動作，不該在他還沒看到效果前先做。

     被拿掉的三個入口都還在、只是不佔導覽：
       適合對象 #why、常見問題 #faq ＝ 捲動就會經過（區塊原地不動）
       筆記 #notes ＝ 改成左欄底部一個小連結「技術文章 →」 */
  .side-notes{ display:inline-block; align-self:flex-start; width:fit-content; margin-top:18px; font-size:14px;
    color:var(--text-2); letter-spacing:.02em; border-bottom:1px solid var(--line);
    padding-bottom:2px; transition:color .18s ease, border-color .18s ease; }
.side-notes:hover{ color:var(--accent); border-color:var(--accent-border); }

@media (min-width:1080px) {
  .layout{ display:grid; grid-template-columns:320px minmax(0,1fr); gap:80px; padding:96px 48px; align-items:start; }
  .sidebar{ position:sticky; top:0; height:100vh; padding:8px 0; display:flex; flex-direction:column; justify-content:space-between; }
  .side-top{ display:block; }
  .avatar{ width:120px; height:120px; border:3px solid rgba(255,255,255,0.92); box-shadow:0 0 0 1px rgba(0,0,0,0.45), 0 14px 34px rgba(0,0,0,0.55); }
  .cat-avatar{ width:64px; height:64px; border:3px solid rgba(255,255,255,0.92); box-shadow:0 0 0 1px rgba(0,0,0,0.45), 0 14px 34px rgba(0,0,0,0.55); }
  .portrait-row{ margin-bottom:26px; gap:16px; }
  .nav{ display:flex; flex-direction:column; gap:14px; }
  .nav-link{ display:flex; align-items:center; gap:12px; color:var(--text-2); font-size:14px; letter-spacing:0.06em; transition:color .2s ease; }
  .nav-link .ln{ width:24px; height:1px; background:var(--text-2); transition:width .2s ease,background .2s ease; }
  .nav-link:hover, .nav-link.active{ color:var(--text); }
  .nav-link:hover .ln, .nav-link.active .ln{ width:48px; background:var(--text); }
  .side-bottom{ display:block; }
  .side-line{ display:inline-flex; align-items:center; gap:8px; background:transparent; border:1px solid rgba(6,199,85,.55); color:#06C755; font-size:14px; font-weight:600; padding:10px 20px; border-radius:26px; }
  .sidebar{ height:calc(100vh - 96px); }
}

@media (max-width:1079px) {
  .enrole{ display:none; }
  .theme-btn{ top:40px; right:26px; }
  .side-social{ margin-bottom:40px; }

  /* 🔴 2026-09-11 [Mate-2]：返回鈕是 position:fixed（top:14 left:14），
   *    桌機時側欄在它下方沒事；手機側欄堆到最上面，**實測它壓在大頭貼上 70×16px**
   *    （返回鈕 14→56、頭像 40→124，390px 下 kefu-how／kefu-tech 都中）。
   *    治法＝手機版把側欄整個往下推到返回鈕下面，不是把返回鈕改小或改位置
   *    （那顆是全站一致的返回入口，位置不該因頁面而異）。
   *    56 ＝ 返回鈕底緣，再留 14px＝跟它上緣的邊距對稱。 */
  /*    ⚠️ 只推「這一頁真的有返回鈕」的：notes 沒有 .home-link，
   *       無條件推的話那是白加的 70px 留白（第一版就這樣，量出來才發現）。 */
  .layout:has(.home-link) > .sidebar{ padding-top:70px; }
}

@media (prefers-reduced-motion:reduce) {
  .progress-top{ display:none; }
  .spot{ display:none !important; }
}

@media (hover:hover) and (pointer:fine) {
  .spot.on{ opacity:1; }
}

/* ── 子頁的正文容器交出寬度控制（2026-09-09 [Mate-2]）───────────────────
 * 套上殼之後量到的事：外框變寬了，正文沒有。
 * notes 的 <article class="wrap"> 自己鎖 max-width:512px，所以段落還是 468px、
 * 平均 21 字/行 —— 看起來還是那個「手機版塞在電腦上」。
 * ⇒ 進了殼的 .wrap 一律交出寬度，改由殼統一決定閱讀欄寬。
 * 閱讀欄寬用 ch 不用 px：ch 跟著字級走，字級改了行長不會跟著失控。
 */
.layout .content > .wrap{ max-width:none; width:auto; margin:0; }
/* 桌機下把各頁自己的左右內距交出來，改由 .content 統一決定閱讀寬。
   出身：同樣吃 36em，kefu-how 是 33 字/行、notes 只有 24 字 —— 差在 notes 的
   .wrap 自己還有左右 22px 內距，等於同一個 max-width 底下兩頁的實際文字寬不同。
   ⚠️ 只在桌機做：窄螢幕要留各頁自己的內距（不然貼齊螢幕邊），那是另一個坑、已修過。 */
@media (min-width:1080px){
  .layout .content > .wrap{ padding-left:0; padding-right:0; }
}
.layout .content{ max-width:36em; }
/* 🔴 36em 不是 42em（2026-09-09 [Mate-2] 量出來改的）：
   42em 是照英文習慣設的，但**中文一個字就是 1em** ⇒ 42em 等於一行 42 個字。
   業界的 65–75 字元是英文的尺度，換算中文約 33–38 字。
   實測：42em 時 kefu-how 是 38 字/行（超出舒適區 25–35），notes 是 31 字（剛好，
   因為它自己的容器還有左右 22px 內距）。改 36em 之後兩頁都落在區間內。 */
@media (max-width:1079px){ .layout .content{ max-width:none; } }

/* ── 側欄的名字（2026-09-09 [Mate-2]）─────────────────────────────────
 * 首頁那條規則是**裸的 h1{}**，所以抽殼時抽不到（選擇器裡沒有殼的 class），
 * 而且也不能照抄 —— 裸 h1 帶到子頁會把人家的文章標題一起改掉。
 * 實測首頁側欄 h1 的 computed style 是 29px／500／Newsreader Latin／行高 1.1／字距 -0.01em，
 * 套殼後的 notes 量到 34px／900／Noto Serif TC ＝ 被該頁自己的 h1 樣式接管了。
 * ⇒ 這裡限定側欄裡那一個。
 * 🔄 2026-09-09 19:5x：子頁的站名從 <h1> 改成 <div class="side-name">
 *    （4號 抓到：殼把站名放頁首又用 h1 ⇒ 24 個子頁各有兩個 h1，第一個變成站名、
 *      把「這一頁在講什麼」的訊號稀釋掉。一頁一個 h1、且是頁面主題，是慣例）。
 *    選擇器寫成 :is(h1,.side-name) 兩種都吃 —— 首頁側欄那個仍是 h1（首頁的主題
 *    本來就是他的名字，那個是對的、不改），將來首頁改吃這支也不會掉樣式。
 */
.sidebar :is(h1,.side-name){
  font-family:'Newsreader Latin','Noto Serif TC',serif;
  font-size:clamp(25px,6vw,29px);
  font-weight:500;
  line-height:1.1;
  letter-spacing:-0.01em;
  margin:0;
}
.sidebar :is(h1,.side-name) a{ color:inherit; text-decoration:none; }
.sidebar :is(h1,.side-name) a:hover{ color:var(--accent); }

/* ── 孤兒字（2026-09-09 [Mate-2]）─────────────────────────────────────
 * 套殼把欄寬改了，斷行位置就跟著變 —— kefu-tech 因此冒出兩個孤兒字
 * （末行只剩「因。」「說：」），線上舊版量過是 0 個，所以是這一刀造成的。
 * 那頁只有給標題的 text-wrap:balance，段落沒有 pretty。
 * 🔑 用排版屬性解，不改正文一個字（改字是最後手段，而且正文不是我的）。
 */
.layout .content :is(p,li,dd,dt,summary,blockquote,figcaption,.q,.d,.answer,.bio,.a){ text-wrap:pretty; }
/* 標題用 balance 不是 pretty：pretty 只保證「最後一行不要太短」，
   標題要的是「每一行長度接近」，那是 balance 的事。
   實測：25 頁逐頁跑完，剩下的 5 個孤兒字有 4 個在 h1／h3、1 個在 .q。 */
.layout .content :is(h1,h2,h3,h4){ text-wrap:balance; }

/* ── 手機不要雙重內距（2026-09-09 [Mate-2]）───────────────────────────
 * 量出來：390 下舊版正文容器 390px（自己 padding 22），套殼後變成
 * layout(padding 26) → content 338 → wrap 又 padding 22 ⇒ 實際內容只剩 294px，
 * **比套殼前窄了 52px**。窄到 kefu-tech 那個 .rag-gap 一行只排得下四五個字。
 * ⇒ 窄螢幕時殼交出左右內距，讓各頁原本的 padding 生效（桌機不動）。
 */
@media (max-width:1079px){
  .layout{ padding-left:0; padding-right:0; }
  /* 🔴 2026-09-12 [Mate-2]：上面那條「殼交出左右內距」漏了側欄。
   *    正文有 `.wrap` 自己的 22px 接手，**側欄不在那條路徑上就沒人給它內距**
   *    ⇒ 390px 下大頭貼與「技術文章 →」左緣 0px 貼死螢幕邊，
   *    而同一頁的正文第一個字在 22px、返回鈕在 14px（實測四個子頁全中：
   *    kefu-how／kefu-tech／notes 索引／notes 內頁；首頁不吃這份 css 所以側欄是 26px、沒事）。
   *    ⇒ 補回 22px，跟同一頁正文的左緣對齊（不是把 .layout 的 26px 加回去，
   *      那會讓正文又變回 294px 寬，正是上面那條規則要解決的事）。 */
  .layout > .sidebar{ padding-left:22px; padding-right:22px; }
}

/* ── 文章標題的字級（2026-09-09 [Mate-2]）─────────────────────────────
 * 套殼把正文欄寬定在 42em 之後，44px 的文章標題在 628px 裡每行只排得下 14 個字，
 * 26 字的標題就會斷成三行、末行只剩一個字（實測 text-wrap:balance 有生效、
 * 但 Chrome 對中文的平衡救不了這種比例）。
 * 🔑 44px 是首頁那句 hero 的尺寸，文章標題本來就不需要那麼大。
 *    縮到 38px 之後每行 16 字，同一個標題排成兩行、沒有孤兒字。
 * 只動殼裡的標題大小，不動任何一個字。
 */
.layout .content h1{ font-size:clamp(28px,3.4vw,38px); }

/* ── 🔴 補回被抽漏的 .spot 基礎規則（2026-09-09 [Mate-2]）─────────────
 * 這條在 index.html 裡好好的，但我的抽取器沒抽到 ⇒ shell.css 只有三條衍生規則
 * （light 版／reduced-motion／.on），**沒有基礎定義**。
 * 後果（線上實測）：子頁的亮點層 opacity 預設 1、一直亮著，而且沒有 position:fixed。
 * 首頁不受影響（它吃自己內嵌那份）⇒ 首頁 opacity 0、子頁 1，兩邊不一致。
 * 根因：抽取器的 regex 是 `([^{}@]+)\{([^{}]*)\}`，
 *      而這條規則前面的註解裡有 `@media (hover:hover)` ⇒ 含 `@` 就匹配失敗、
 *      指標逐字前進，整條規則被跳過。**漏抽不會報錯，這是最難發現的一種。**
 * 下面這段是用程式從 index.html 原文抽出來的，不是手抄。
 */
.spot{ position:fixed; inset:0; z-index:30; pointer-events:none; opacity:0;
    transition:opacity .35s ease;
    mix-blend-mode:screen;
    background:radial-gradient(600px at var(--mx,50%) var(--my,50%),
      rgba(158,193,232,0.10), rgba(0,0,0,0) 78%); }

/* ── 背景網格紋理（2026-09-09 [Mate-2]）─────────────────────────────────
 * Strider：「筆記區域或其他機器人教學區域，背景圖跟主頁我剛剛看有一點深淺的差別。」
 * 量出來：首頁亮度 23.87、notes 22.88、kefu-how／privacy／404 只有 22.74。
 * 🔴 真因不是紋理畫得不一樣，是**多數頁根本沒有紋理**：
 *    好幾頁的 body 寫著 `background-image:var(--grid-img)`，
 *    但它們的 :root **從來沒有定義過 --grid-img** ⇒ 引用一個不存在的變數
 *    在 CSS 裡是靜靜失效、不報錯，所以沒人發現。只有 index.html 定義了它。
 * ⇒ 定義搬到殼裡，25 頁共用一份。
 * 順便把紋理的顏色從暖白 %23F4F1EA 換成冷白 %23E6EBF2（跟 --text 同值），
 * 原本那個是舊暖色系留下來的。
 */
:root{ --grid-img:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56'%3E%3Cpath d='M56 .5H.5V56' fill='none' stroke='%23E6EBF2' stroke-opacity='.055' stroke-dasharray='2 6'/%3E%3C/svg%3E"); }
/* 🔴 選擇器要用 html body（特異性 0,0,2）不是 body（0,0,1）：
   kefu-how／kefu-tech／privacy／404 的 body 用的是 `background:var(--bg)` **簡寫**，
   簡寫會把 background-image 一起重置成 none ⇒ 同特異性時後宣告者贏、紋理就沒了。
   實測：只寫 body{} 那四頁量出來仍是「背景圖＝無」。 */
html body{ background-image:var(--grid-img); background-attachment:fixed; }
