/* ================================================================
   Jackle Blog — 共用外殼樣式
   數值全部取自 https://jackle.pro 線上渲染 CSS 的實測值
   ================================================================ */

/* ---------- 語意色（shadcn 命名，淺色） ---------- */
:root {
  --background: #ffffff;
  --foreground: #27272a;
  --muted-fg: #71717b;
  --grid-stroke: #d1d5dc;
  --pill-bg: rgb(255 255 255 / .9);
  --pill-fg: #27272a;
  --pill-ring: #18181b0d;
  --accent: #00bba7;         /* teal-500 */
  --accent-strong: #009689;  /* teal-600 */
  --accent-deep: #00786f;    /* teal-700 */
  /* 小字用的強調色。品牌色 #00bba7 在白底只有 2.4:1，
     14px 的「前往網站」「Read article」這種字用它會糊掉。
     深色模式底色夠暗，品牌色本身就有 11:1，不用換。 */
  --accent-text: #00786f;    /* teal-700，白底 5.4:1 */
  --divider: #f4f4f5;
  /* 文章視覺元件的不透明底。存在理由：背景是固定的網格層，
     元件只要底色帶透明度，網格就會直接穿到卡片裡的文字後面。
     所有帶色調的元件都要疊在這個底上，不能只用半透明色當唯一背景。 */
  --surface: #ffffff;
  --popover: #ffffff;
  --popover-fg: #27272a;
  --border: #e4e4e7;
}
.dark {
  --background: #000000;
  --foreground: #e4e4e7;
  --muted-fg: #9f9fa9;
  /* 點陣底紋。不沿用線網格時代的 #364153：那個值在純黑底上的明度差約 28，
     是淺色模式（白底 #d1d5dc，明度差約 15）的兩倍，換成圓點後更明顯。
     #27272a 讓兩個模式的底紋輕重對得起來，順便去掉原本的偏藍。 */
  --grid-stroke: #27272a;
  --pill-bg: rgb(39 39 42 / .9);
  --pill-fg: #e4e4e7;
  --pill-ring: #ffffff1a;
  --accent: #00d5be;         /* teal-400 */
  --accent-text: #00d5be;    /* 黑底 11.3:1，直接用品牌色 */
  --accent-strong: #00d5be;
  --divider: rgb(63 63 70 / .4);
  --surface: #18181b;
  --popover: #18181b;
  --popover-fg: #e4e4e7;
  --border: #27272a;
}

/* ---------- 固定滿版背景層 ----------
   兩層：底下是點陣底紋，上面是一張左右淡出的「紙」。
   為什麼不用有邊框的底板：舊版那塊灰底板有一條硬邊，內容剛好壓在上面，
   而且深色模式下那條線幾乎看不見，兩層的層次感就消失了。
   改成紙之後沒有邊可以貼，層次靠「中間是純色、兩側透出點陣」自己成立。 */
.bg-layer {
  position: fixed; inset: 0;
  display: flex; justify-content: center;
  background-color: var(--background);
  transition: background-color .5s;
}
@media (min-width: 40rem) { .bg-layer { padding-inline: 2rem; } }

/* 點陣底紋。手機沒有多餘的兩側可以露出底紋，直接不畫，省得跟內容打架。 */
.bg-grid { display: none; }
@media (min-width: 64rem) {
  .bg-grid {
    display: block;
    position: absolute; top: 0; left: 0;
    height: 100%; width: 100%; z-index: -10;
    background-image: radial-gradient(circle at center, var(--grid-stroke) 1.1px, transparent 1.1px);
    background-size: 22px 22px;
  }
}

.bg-column { display: flex; width: 100%; max-width: 80rem; }
@media (min-width: 64rem) { .bg-column { padding-inline: 2rem; } }

/* 這張「紙」就是內容底下的那層純色。
   手機與平板整片鋪滿、不做淡出，因為兩側沒有空間可以露出底紋，
   淡出只會讓靠邊的文字坐在半透明區上。 */
.bg-paper {
  width: 100%;
  background-color: var(--background);
  transition: background-color .5s;
}
@media (min-width: 64rem) {
  .bg-paper {
    /* 用固定長度不用百分比：內容離紙緣是固定的 80 px，
       淡出區必須比它短，否則正文左右兩側會坐在半透明的紙上、底紋透出來。
       4.5rem = 72 px，剛好留 8 px 餘裕。 */
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 4.5rem, #000 calc(100% - 4.5rem), transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 4.5rem, #000 calc(100% - 4.5rem), transparent 100%);
  }
}

/* ---------- 前景容器 ---------- */
.shell { position: relative; width: 100%; }
.site-main { min-height: 90vh; }

/* ---------- 頁首（不 sticky，跟著捲走） ---------- */
.site-header { position: relative; z-index: 50; display: flex; width: 100%; flex: none; flex-direction: column; }
.header-outer { height: 4rem; padding-top: 1.5rem; }
@media (min-width: 40rem) { .header-mid { padding-inline: 2rem; } }
.header-inner { max-width: 80rem; margin-inline: auto; }
/* 跟 .footer-inner 同一個道理：7rem = 2rem 版心 + 5rem 間距。
   原本 2rem + 3rem 只有 80 px，logo 跟深淺色按鈕會落在紙的淡出區裡 ——
   1024 px 實測整條頁首比紙的實心區左右各寬 24 px。 */
@media (min-width: 64rem) { .header-inner { padding-inline: 7rem; } }
.header-pad { position: relative; padding-inline: 1rem; }
@media (min-width: 40rem) { .header-pad { padding-inline: 2rem; } }
@media (min-width: 64rem) { .header-pad { padding-inline: 0; } }
.header-col { max-width: 42rem; margin-inline: auto; }
@media (min-width: 64rem) { .header-col { max-width: 64rem; } }
.header-row { position: relative; display: flex; gap: 1rem; }

.hdr-left { display: flex; flex: 1 1 0%; align-items: center; }
.logo-link { display: block; color: #3f3f46; }
.dark .logo-link { color: #e4e4e7; }
.logo-link svg { width: 6rem; height: auto; display: block; }
@media (min-width: 48rem) { .logo-link svg { width: 7rem; } }
@media (min-width: 64rem) { .logo-link svg { width: 9rem; } }

.hdr-center { display: flex; flex: 1 1 0%; justify-content: flex-end; }
@media (min-width: 48rem) { .hdr-center { justify-content: center; } }
.hdr-right { display: flex; justify-content: flex-end; gap: 1rem; }
@media (min-width: 48rem) { .hdr-right { flex: 1 1 0%; } }

/* ---------- 膠囊（導覽與手機選單鈕共用外觀） ---------- */
.nav-pill {
  display: flex; align-items: center; height: 100%;
  border-radius: 9999px;
  background: var(--pill-bg);
  padding-inline: .75rem;
  font-size: .875rem; font-weight: 500; line-height: 1.42857;
  color: var(--pill-fg);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: 0 0 0 1px var(--pill-ring), 0 10px 15px -3px #27272a0d, 0 4px 6px -4px #27272a0d;
  border: 0; font-family: inherit; letter-spacing: inherit;
}
.desktop-nav { display: none; }
@media (min-width: 48rem) {
  .desktop-nav { display: flex; }
  .menu-btn { display: none; }
}
.menu-btn { padding: .5rem 1rem; cursor: pointer; }
.menu-caret { width: 1em; height: 1em; margin-left: .75rem; color: #71717b; }
.menu-btn:hover .menu-caret { color: #3f3f46; }
.dark .menu-btn:hover .menu-caret { color: #9f9fa9; }

.desktop-nav > a, .nav-dd-trigger {
  padding: .5rem .75rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: color .15s cubic-bezier(.4,0,.2,1);
  background: none; border: 0; cursor: pointer;
  font: inherit; letter-spacing: inherit; color: inherit;
}
.desktop-nav > a:hover, .nav-dd-trigger:hover { color: var(--accent-text); }

/* ---------- 好用工具下拉 ---------- */
.nav-dd { position: relative; display: flex; align-items: center; }
.nav-dd-panel {
  position: absolute; top: calc(100% + 1px); left: 0; z-index: 50;
  min-width: 8rem;
  display: none; flex-direction: column;
  background: var(--popover); color: var(--popover-fg);
  border: 1px solid var(--border); border-radius: .5rem; padding: .25rem;
  box-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);
}
.nav-dd[data-open="true"] .nav-dd-panel { display: flex; }
.nav-dd-panel a {
  display: flex; align-items: center; gap: .5rem;
  border-radius: .375rem; padding: .5rem .75rem;
  font-size: .875rem; white-space: nowrap;
  transition: color .15s, background-color .15s;
}
.nav-dd-panel a:hover { background: var(--divider); color: var(--accent-text); }

/* ---------- 深淺色切換鈕（沒有 backdrop-blur） ---------- */
.theme-btn {
  display: flex; align-items: center; height: 100%;
  border-radius: 9999px; border: 0; cursor: pointer;
  background: var(--pill-bg);
  padding: .5rem;                 /* 實測舊站按鈕寬 40px = 24px icon + 8px×2 */
  box-shadow: 0 0 0 1px var(--pill-ring), 0 10px 15px -3px #27272a0d, 0 4px 6px -4px #27272a0d;
  transition: box-shadow .15s;
}
.theme-btn svg { width: 1.5rem; height: 1.5rem; }
.icon-sun  { color: var(--accent-text); }
.icon-moon { color: #71717b; }
.theme-btn:hover .icon-sun  { color: var(--accent-strong); }
.theme-btn:hover .icon-moon { color: #00d5be; }
.icon-moon { display: none; }
.dark .icon-sun { display: none; }
.dark .icon-moon { display: block; }

/* ---------- 手機選單 ---------- */
.mobile-menu { position: fixed; inset: 0; z-index: 60; }
.mobile-menu[hidden] { display: none; }
.mm-backdrop {
  height: 100%; width: 100%;
  background: rgb(39 39 42 / .5);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  animation: blur-in .3s cubic-bezier(.165,.84,.44,1) forwards;
}
.dark .mm-backdrop { background: rgb(0 0 0 / .7); }
@keyframes blur-in { from { opacity: 0; } to { opacity: 1; } }
.mm-panel {
  position: fixed; left: 0; right: 0; top: 0;
  margin-inline: 1rem; margin-top: 2rem;
  border-radius: 1.5rem; padding: 2rem;
  background: #fff; box-shadow: 0 0 0 1px #18181b0d;
}
.dark .mm-panel { background: #18181b; box-shadow: 0 0 0 1px #27272a; }
.mm-top { display: flex; flex-direction: row-reverse; align-items: center; justify-content: space-between; }
.mm-close { margin: -.25rem; padding: .25rem; background: none; border: 0; cursor: pointer; color: #71717b; }
.dark .mm-close { color: #9f9fa9; }
.mm-close svg { width: 1.5rem; height: 1.5rem; }
.mm-label { font-size: .875rem; font-weight: 500; color: #52525c; }
.dark .mm-label { color: #9f9fa9; }
.mm-nav { margin-top: 1.5rem; }
.mm-nav ul { margin-block: -.5rem; list-style: none; padding: 0; }
.mm-nav li + li { border-top: 1px solid #f4f4f5; }
.dark .mm-nav li + li { border-top-color: #f4f4f50d; }
.mm-nav a { display: block; padding-block: .5rem; font-size: 1rem; color: #27272a; }
.dark .mm-nav a { color: #d4d4d8; }
@media (min-width: 48rem) { .mobile-menu { display: none; } }

/* ---------- 頁尾（/tools/ 路由不顯示） ---------- */
.site-footer { margin-top: 2.5rem; }
@media (min-width: 40rem) { .footer-outer { padding-inline: 2rem; } }
.footer-inner { max-width: 80rem; margin-inline: auto; }
/* 7rem 而不是 2rem：頁尾那條分隔線畫在 .footer-pad 的上邊框，
   線的長度就等於 .footer-pad 的外框。只留 2rem 的話線會剛好等於紙的寬度，
   兩端落在紙的淡出區裡、變成兩個懸在點陣上的硬切口 —— 正是這次改版要消掉的東西。
   推到 7rem（2rem 版心 + 5rem 間距）之後，線跟內容欄同寬，兩端都在紙的實心區內。 */
@media (min-width: 64rem) { .footer-inner { padding-inline: 7rem; } }
.footer-pad {
  border-top: 1px solid var(--divider);
  padding-block: 1.5rem;
  position: relative;
  padding-inline: 1rem;
}
@media (min-width: 40rem) { .footer-pad { padding-inline: 2rem; } }
/* 內縮已經由 .footer-inner 負責，這層再加就會離線的兩端更遠、跟內容對不齊 */
@media (min-width: 64rem) { .footer-pad { padding-inline: 0; } }
.footer-col { max-width: 42rem; margin-inline: auto; }
@media (min-width: 64rem) { .footer-col { max-width: 64rem; } }
.footer-row {
  display: flex; flex-direction: column;
  align-items: center; justify-content: space-between; gap: 1.5rem;
}
@media (min-width: 40rem) { .footer-row { flex-direction: row; } }
.footer-links {
  display: flex; flex-wrap: wrap; justify-content: center;
  column-gap: 1.5rem; row-gap: .25rem;
  font-size: .875rem; font-weight: 500; color: var(--foreground);
}
.footer-links a { transition: color .15s; }
.footer-links a:hover { color: var(--accent-text); }
/* 舊站這裡是 zinc-400，白底只有 2.6:1。降一階到 zinc-500 才過 AA，視覺上一樣是灰的。 */
.footer-copy { font-size: .875rem; color: var(--muted-fg); }

/* ---------- 無障礙 ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ================================================================
   頁面共用容器（首頁 / 列表 / 關於我）
   ================================================================ */
.page { margin-top: 4rem; }
@media (min-width: 40rem) { .page { margin-top: 8rem; padding-inline: 2rem; } }
.page-outer { max-width: 80rem; margin-inline: auto; }
@media (min-width: 64rem) { .page-outer { padding-inline: 2rem; } }
.page-pad { padding-inline: 1rem; }
@media (min-width: 40rem) { .page-pad { padding-inline: 2rem; } }
/* 跟 .article-grid 同一個道理，補到 5rem 讓內容離版心邊界 80 px */
@media (min-width: 64rem) { .page-pad { padding-inline: 5rem; } }
.page-col { max-width: 42rem; margin-inline: auto; }
@media (min-width: 64rem) { .page-col { max-width: 64rem; } }

.page-title { max-width: 42rem; }
.page-title h1 {
  font-size: 1.875rem; line-height: 1.2; font-weight: 700;
  letter-spacing: .025em; color: var(--foreground);
}
@media (min-width: 64rem) { .page-title h1 { font-size: 2.25rem; line-height: 1.11111; } }
.page-title p { margin-top: 1.5rem; font-size: 1rem; color: #52525c; }
.dark .page-title p { color: #9f9fa9; }
/* 打字機游標 */
#typed::after {
  content: "|"; margin-left: .5rem;
  animation: caret 1s steps(1) infinite;
}
@keyframes caret { 0% { visibility: hidden } 50% { visibility: visible } 100% { visibility: hidden } }

/* ---------- 列表頁兩欄 ---------- */
.list-wrap { margin-top: 4rem; display: flex; flex-direction: column-reverse; }
@media (min-width: 40rem) { .list-wrap { margin-top: 5rem; } }
@media (min-width: 48rem) { .list-wrap { flex-direction: row; } }
.list-main { margin-top: 4rem; width: 100%; }
@media (min-width: 48rem) {
  .list-main { margin-top: 0; max-width: 42rem; border-left: 1px solid #f4f4f5; padding-left: 1.5rem; }
  .dark .list-main { border-left-color: rgb(63 63 70 / .4); }
}
.list-main ul { display: flex; flex-direction: column; gap: 4rem; list-style: none; padding: 0; margin: 0; }
@media (min-width: 64rem) { .list-main ul { padding-right: 2.5rem; padding-left: .5rem; } }

.art-card { position: relative; display: flex; flex-direction: column; align-items: flex-start; }
.art-card .glow {
  position: absolute; left: -1rem; right: -1rem; top: -1.5rem; bottom: -1.5rem; z-index: 0;
  transform: scale(.95); background: #fafafa; opacity: 0;
  transition: transform .2s, opacity .2s;
}
@media (min-width: 40rem) { .art-card .glow { left: -1.5rem; right: -1.5rem; border-radius: 1rem; } }
.dark .art-card .glow { background: rgb(39 39 42 / .5); }
.art-card:hover .glow { transform: scale(1); opacity: 1; }
.art-card time {
  position: relative; z-index: 10; order: -1; margin-bottom: .75rem;
  display: flex; align-items: center; padding-left: .875rem;
  font-size: .875rem; color: #71717b;
}
.dark .art-card time { color: #9f9fa9; }
.art-card time .tick {
  position: absolute; left: 0; top: 0; bottom: 0; display: flex; align-items: center;
}
.art-card time .tick i {
  display: block; height: 1rem; width: 2px; border-radius: 9999px; background: #e4e4e7;
}
.dark .art-card time .tick i { background: #3f3f46; }
.art-card h2 {
  font-size: 1rem; line-height: 1.5; font-weight: 600; letter-spacing: .025em;
  color: var(--foreground); margin: 0;
}
.art-card h2 a { position: relative; z-index: 10; }
/* 整張卡都可以點。原本這塊感應區是放在 <a> 裡面的，
   而 <a> 自己是 position:relative，所以它的定位基準是「標題那一行」而不是整張卡 ——
   結果只有標題附近點得到，卡片其他地方點了沒反應。
   改成 .art-card 的直接子元素，基準才是整張卡。
   它是給滑鼠用的：aria-hidden + tabindex="-1"，鍵盤與螢幕閱讀器仍走上面那個標題連結，
   不會讀到兩次同一篇。 */
.art-card .hit {
  position: absolute; left: -1rem; right: -1rem; top: -1.5rem; bottom: -1.5rem; z-index: 20;
}
@media (min-width: 40rem) { .art-card .hit { left: -1.5rem; right: -1.5rem; border-radius: 1rem; } }
.art-card .desc {
  position: relative; z-index: 10; margin-top: .5rem;
  font-size: .875rem; line-height: 1.6; color: #52525c;
}
.dark .art-card .desc { color: #9f9fa9; }
.art-card .more {
  position: relative; z-index: 10; margin-top: 1rem;
  display: flex; align-items: center; gap: .25rem;
  font-size: .875rem; font-weight: 500; color: var(--accent-text);
}
.art-card .more svg { width: .875rem; height: .875rem; transition: transform .15s; }
.art-card:hover .more svg { transform: translateX(3px); }

/* ---------- 標籤側欄 ---------- */
.list-side { height: fit-content; flex: 1 1 0%; padding-left: 0; }
@media (min-width: 48rem) { .list-side { position: sticky; top: 1.5rem; margin-top: 0; padding-left: 2.5rem; } }
.list-side .rule { margin-block: 1rem; border-top: 1px solid #e4e4e7; }
.dark .list-side .rule { border-top-color: rgb(63 63 70 / .6); }
.list-side nav { display: flex; flex-direction: column; gap: .5rem; }
.tag-btn {
  border-radius: .5rem; padding: .5rem .75rem; text-align: left;
  font-size: .875rem; color: #52525c; background: none; border: 0; cursor: pointer;
  font-family: inherit; letter-spacing: inherit; transition: all .3s;
}
.dark .tag-btn { color: #9f9fa9; }
.tag-btn:hover { background: #fafafa; color: #18181b; }
.dark .tag-btn:hover { background: rgb(39 39 42 / .5); color: #e4e4e7; }
.tag-btn[aria-pressed="true"] { background: #f4f4f5; font-weight: 500; color: #18181b; }
.dark .tag-btn[aria-pressed="true"] { background: #27272a; color: #f4f4f5; }
.tag-btn .n { margin-left: .25rem; font-size: .75rem; opacity: .6; }
li[hidden] { display: none !important; }

/* 進場動畫 */
@keyframes fade-up { from { opacity: 0; transform: translateY(20px) } to { opacity: 1; transform: none } }
.anim { animation: fade-up .6s cubic-bezier(.16,1,.3,1) both; }

/* ================================================================
   首頁
   ================================================================ */
.hero { margin-top: 3.25rem; }
.hero-avatar { width: 4rem; height: 4rem; border-radius: 9999px; object-fit: cover; display: block; }
.hero-body { margin-top: 2.25rem; max-width: 42rem; }
.hero-body h1 {
  font-size: 1.875rem; line-height: 1.2; font-weight: 700;
  letter-spacing: .025em; color: var(--foreground);
}
@media (min-width: 64rem) { .hero-body h1 { font-size: 3rem; line-height: 1; } }
.hero-body p { margin-top: 1.5rem; font-size: 1rem; color: #52525c; }
.dark .hero-body p { color: #9f9fa9; }
.socials { margin-top: 1.5rem; display: flex; gap: 1.5rem; }
.socials a { color: #71717b; transition: color .15s; display: block; }
.dark .socials a { color: #9f9fa9; }
.socials a:hover { color: #52525c; }
.dark .socials a:hover { color: #d4d4d8; }
.socials svg { width: 1.5rem; height: 1.5rem; display: block; }

.section-head { margin-bottom: 3rem; }
@media (min-width: 64rem) { .section-head { padding-inline: 3rem; } }
.section-head h2 {
  margin: 0 0 1rem; font-size: 1.875rem; font-weight: 700;
  color: #18181b; letter-spacing: normal;
}
.dark .section-head h2 { color: #fff; }
.section-head p { max-width: 42rem; font-size: 1.125rem; color: #52525c; margin: 0; }
.dark .section-head p { color: #d4d4d8; }

/* 五張卡拆成兩列：上面兩張大的（他自己在「關於我」說的那兩個 side project）、
   下面三張小的。原本五張擠在三欄裡會變成 3+2、右下角缺一格，
   而且前三張 622 px、後兩張 444 px 高度不齊，看起來像排壞了。 */
.projects { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2rem; }
@media (min-width: 48rem) {
  .projects.feat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .projects.rest-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 64rem) {
  .projects { padding-inline: 3rem; }
  .projects.rest-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.projects.rest-row { margin-top: 2rem; }
.proj {
  display: flex; flex-direction: column;
  border-radius: .75rem; overflow: hidden;
  /* 深色模式原本是 rgb(0 0 0 / .3)，疊在純黑的紙上等於沒有底色，
     卡片邊界整個消失（陰影在黑底上也看不見）。改用 --surface，兩個模式都看得出是一張卡。 */
  background: var(--surface);
  box-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);
  transition: transform .3s, box-shadow .3s;
}
.dark .proj { box-shadow: 0 0 0 1px var(--border); }
.proj:hover { transform: translateY(-4px); box-shadow: 0 25px 50px -12px rgb(0 0 0 / .25); }
.proj .thumb { aspect-ratio: 16 / 9; width: 100%; overflow: hidden; background: #e5e7eb; }
.dark .proj .thumb { background: #364153; }
.proj .thumb img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .5s; }
.proj:hover .thumb img { transform: scale(1.05); }
.proj .body { padding: 1.5rem; display: flex; flex-direction: column; flex: 1 1 auto; }
/* 型態標籤。每個都是原文裡本來就有的詞，只是抽出來讓人不用讀完整段才知道這是什麼 */
.proj .kind {
  align-self: flex-start; margin-bottom: .625rem;
  font-size: .75rem; font-weight: 600; line-height: 1;
  padding: .3125rem .5rem; border-radius: .375rem;
  background: linear-gradient(rgb(0 187 167 / .14), rgb(0 187 167 / .14)), var(--surface);
  color: var(--accent-deep);
}
.dark .proj .kind { color: var(--accent-text); }
.proj h3 { margin: 0 0 .625rem; font-size: 1.25rem; font-weight: 700; color: #18181b; letter-spacing: normal; }
.dark .proj h3 { color: #fff; }
/* 一句話定位。原本三段散文全部同一個灰，第一段是最該先看到的，給它深一階 */
.proj .lede { margin: 0; font-size: .9375rem; line-height: 1.7; color: #3f3f46; }
.dark .proj .lede { color: #d4d4d8; }
.proj .pts {
  list-style: none; margin: .875rem 0 0; padding: 0;
  display: grid; gap: .5rem; flex: 1 1 auto;
  font-size: .875rem; line-height: 1.65; color: #52525c;
}
.dark .proj .pts { color: #9f9fa9; }
.proj .pts > li { position: relative; padding-left: .875rem; }
.proj .pts > li::before {
  content: ""; position: absolute; left: 0; top: .5rem;
  width: .3125rem; height: .3125rem; border-radius: 9999px; background: var(--accent);
}
/* 原本寫成「1. 語音轉文字」的純文字，改成真的編號清單 */
.proj .pts .sub { margin: .375rem 0 0; padding-left: 1.25rem; display: grid; gap: .125rem; }
.proj .pts .sub li { list-style: decimal; }
.proj:not(.feat) .lede { flex: 1 1 auto; }
.proj .cta {
  margin-top: 1.25rem; display: inline-flex; align-items: center; gap: .25rem;
  font-size: .875rem; font-weight: 500; color: var(--accent-text);
}
.proj .cta svg { width: 1rem; height: 1rem; }

.about-card {
  border-radius: .75rem; background: #fff; overflow: hidden;
  box-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);
  transition: box-shadow .3s;
}
.dark .about-card { background: rgb(0 0 0 / .3); }
@media (min-width: 64rem) { .about-wrap { padding-inline: 3rem; } }
.about-card .inner {
  display: flex; flex-direction: column; align-items: center; gap: 2rem; padding: 2rem;
}
@media (min-width: 48rem) {
  .about-card .inner { flex-direction: row; align-items: flex-start; gap: 3rem; padding: 3rem; }
}
.about-card .photo {
  flex-shrink: 0; width: 12rem; height: 12rem; border-radius: 9999px; overflow: hidden;
  box-shadow: 0 0 0 4px rgb(229 231 235 / .5);
}
@media (min-width: 48rem) { .about-card .photo { width: 14rem; height: 14rem; } }
.dark .about-card .photo { box-shadow: 0 0 0 4px rgb(255 255 255 / .1); }
.about-card .photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.about-card .text p { font-size: 1rem; line-height: 1.8; color: #52525c; margin-bottom: 1rem; }
.dark .about-card .text p { color: #9f9fa9; }
.btn-more {
  display: inline-flex; align-items: center; gap: .5rem; margin-top: .5rem;
  border-radius: .625rem; border: 1px solid var(--border);
  padding: .625rem 1rem; font-size: .875rem; font-weight: 500; color: var(--foreground);
  transition: border-color .15s, color .15s;
}
.btn-more:hover { border-color: var(--accent-text); color: var(--accent-text); }
.btn-more svg { width: 1.125rem; height: 1.125rem; }
.section-gap { margin-top: 6rem; }
.proj > a { display: flex; flex-direction: column; flex: 1 1 auto; color: inherit; }
.proj > a:hover { color: inherit; }
.proj:hover h3 { color: var(--accent-text); }
/* 打字機佔位：隱形替身撐出最終高度，打字時下方內容不會上下跳 */
.typewrap { position: relative; display: block; }
.typewrap .ghost { visibility: hidden; }
.typewrap #typed { position: absolute; inset: 0; }

/* ================================================================
   關於我
   ================================================================ */
/* 桌機：內容在左（7fr）、照片＋社群在右（5fr），右欄整欄 sticky。
   窄螢幕：把右欄 display:contents 拆開，用 order 重排成 照片 → 內容 → 與我聯繫，
   否則單欄堆疊時照片會被擠到整串近況的後面。 */
.about-grid { display: flex; flex-direction: column; gap: 3rem; }
.about-grid .portrait-col { display: contents; }
.about-grid .portrait { order: 1; }
.about-grid .about-body { order: 2; }
.about-grid .contact-col { order: 3; }
@media (min-width: 64rem) {
  .about-grid { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 4rem; align-items: start; }
  .about-grid .portrait-col { display: block; position: sticky; top: 6rem; }
  .about-grid .portrait, .about-grid .about-body, .about-grid .contact-col { order: 0; }
}
.portrait {
  max-width: 20rem; border-radius: 1.5rem; overflow: hidden;
  box-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);
  rotate: 3deg;
}
@media (min-width: 64rem) { .portrait { max-width: none; } }
.portrait img { width: 100%; height: auto; display: block; aspect-ratio: 1; object-fit: cover; }

.about-body h1 {
  font-size: 1.875rem; line-height: 1.2; font-weight: 700; letter-spacing: .025em;
  color: var(--foreground); margin: 0 0 2rem;
}
@media (min-width: 64rem) { .about-body h1 { font-size: 2.25rem; } }
.about-body h2 {
  font-size: 1.375rem; font-weight: 700; color: var(--foreground);
  margin: 2.75rem 0 1rem; letter-spacing: normal;
}
.about-body h2:first-of-type { margin-top: 0; }
.about-body p { font-size: 1rem; line-height: 1.85; color: #52525c; margin: 0 0 1.125rem; }
.dark .about-body p { color: #9f9fa9; }
.about-body a { color: var(--accent-text); text-decoration: underline; text-underline-offset: .2em; }
.about-body a:hover { text-decoration-thickness: 2px; }
/* 兩個 side project。做成連結卡而不是句子，是因為這是整頁最常被點的東西。 */
.about-projects {
  display: grid; gap: .75rem; margin: 0 0 .75rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
}
.about-projects .proj {
  display: flex; flex-direction: column; gap: .25rem;
  border: 1px solid var(--border); border-radius: .75rem; padding: 1rem 1.125rem;
  background: var(--surface); text-decoration: none; color: var(--foreground);
  transition: border-color .2s, background .2s, transform .2s;
}
.about-projects .proj:hover {
  border-color: var(--accent-text);
  background: linear-gradient(rgb(0 187 167 / .06), rgb(0 187 167 / .06)), var(--surface);
  transform: translateY(-2px);
}
.about-projects .proj-name { font-size: 1.0625rem; font-weight: 700; }
.about-projects .proj-what { font-size: .875rem; color: var(--accent-text); }
.about-projects .proj-note { font-size: .8125rem; color: var(--muted-fg); line-height: 1.5; }

.about-body .about-aside { font-size: .8125rem; color: var(--muted-fg); margin: 0 0 1.5rem; }

/* 最近 Now 的時間軸。原稿本來就大致按時間排，所以這裡不重排、也不去猜年份，
   只是把 14 條長段落改成「左邊一條軸 + 每條一個標籤」，讓人可以跳著挑要讀哪幾條。 */
.nowline { list-style: none; margin: 0 0 1.5rem; padding: 0; position: relative; }
.nowline::before {
  content: ""; position: absolute; left: .3125rem; top: .5rem; bottom: .5rem;
  width: 1px; background: var(--border);
}
.nowline > li { position: relative; padding: 0 0 1.5rem 1.75rem; }
.nowline > li::before {
  content: ""; position: absolute; left: 0; top: .4375rem;
  width: .6875rem; height: .6875rem; border-radius: 9999px;
  background: var(--surface); box-shadow: 0 0 0 2px var(--muted-fg) inset;
}
.nowline > li[data-kind="work"]::before { box-shadow: none; background: var(--accent); }
.nowline > li[data-kind="talk"]::before { box-shadow: 0 0 0 2px var(--accent) inset; }
.nowline > li[data-kind="turn"]::before { box-shadow: none; background: #a34832; }
.dark .nowline > li[data-kind="turn"]::before { background: #d98a72; }

/* 時間點與標籤同一行。時間點在左、用等寬字對齊，掃的時候一眼看得出年份在往下退。 */
.about-body .nl-head {
  display: flex; align-items: center; flex-wrap: wrap; gap: .5rem;
  margin: 0 0 .375rem;
}
.nl-when {
  font-family: var(--font-mono); font-size: .75rem; line-height: 1;
  color: var(--muted-fg); white-space: nowrap;
}
.nl-tag {
  display: inline-block;
  font-size: .75rem; font-weight: 600; line-height: 1;
  padding: .3125rem .5rem; border-radius: .375rem;
  /* 中性標籤用 --foreground 不用 --muted-fg：#71717b 配 --divider 的 #f4f4f5
     只有 4.39:1，12 px 的字要 4.5。跟 .versus 的標題列同一個組合。 */
  background: var(--divider); color: var(--foreground);
}
li[data-kind="work"] > .nl-tag,
li[data-kind="talk"] > .nl-tag {
  background: linear-gradient(rgb(0 187 167 / .14), rgb(0 187 167 / .14)), var(--surface);
  color: var(--accent-deep);
}
.dark li[data-kind="work"] > .nl-tag,
.dark li[data-kind="talk"] > .nl-tag { color: var(--accent-text); }
li[data-kind="turn"] > .nl-tag {
  background: linear-gradient(rgb(180 83 60 / .12), rgb(180 83 60 / .12)), var(--surface);
  color: #a34832;
}
.dark li[data-kind="turn"] > .nl-tag { color: #d98a72; }

.nl-body { font-size: 1rem; line-height: 1.85; color: #52525c; }
.dark .nl-body { color: #9f9fa9; }

/* 那條「沈迷於打鱷魚，而不是通過沼澤」是整頁最有記憶點的一句，
   給它一張卡讓人掃過去時會停一下。 */
.nowline > li[data-kind="turn"] .nl-body {
  border-left: 3px solid #a34832;
  background: linear-gradient(rgb(180 83 60 / .06), rgb(180 83 60 / .06)), var(--surface);
  border-radius: 0 .5rem .5rem 0; padding: .875rem 1.125rem;
}
.dark .nowline > li[data-kind="turn"] .nl-body { border-left-color: #d98a72; }

/* 「關於本站」原本是三段散文，拆成三張卡；每段講的本來就是不同件事。 */
.about-cards {
  display: grid; gap: .75rem; margin: 0 0 1.125rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
}
.about-cards .ac {
  border: 1px solid var(--border); border-radius: .625rem;
  padding: 1rem 1.125rem; background: var(--surface);
}
/* 正文欄放不下三欄，三張卡會排成 2+1、最後一張變孤兒。
   讓落單的最後一張佔滿整列，行尾就不會缺一角。四張時自然變 2×2、這條不會生效。 */
.about-cards .ac:last-child:nth-child(odd) { grid-column: 1 / -1; }
.about-cards .ac h3 {
  margin: 0 0 .5rem; font-size: .9375rem; font-weight: 700;
  color: var(--accent-deep); line-height: 1.4;
}
.dark .about-cards .ac h3 { color: var(--accent-text); }
.about-body .about-cards .ac p { margin: 0; font-size: .9375rem; line-height: 1.75; }

/* 這個 h2 在 .about-body 外面，吃不到那邊的樣式，要自己補一份一樣的。
   照片下面留 2.5rem，不然標題會貼在相框上。 */
.contact-col h2 {
  font-size: 1.375rem; font-weight: 700; color: var(--foreground);
  margin: 2.5rem 0 0; letter-spacing: normal;
}
@media (min-width: 64rem) { .contact-col h2 { margin-top: 2rem; } }
.contact-list { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .75rem; }
/* 只有 40–64rem 這段是全寬堆疊，才排得下三欄；
   桌機時它在右邊那條窄欄裡，維持一欄直式，跟照片同寬。 */
@media (min-width: 40rem) and (max-width: 63.999rem) {
  .contact-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.contact-list a {
  display: flex; align-items: center; gap: .875rem;
  border: 1px solid var(--border); border-radius: .75rem; padding: .875rem 1rem;
  color: var(--foreground); text-decoration: none;
  transition: border-color .2s, background .2s, transform .2s;
}
.contact-list a:hover { border-color: var(--accent-text); background: color-mix(in oklch, var(--accent) 6%, transparent); transform: translateY(-2px); }
.contact-list .ico {
  flex: 0 0 auto; width: 2.25rem; height: 2.25rem; border-radius: .5rem;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in oklch, var(--accent) 12%, transparent); color: var(--accent-text);
}
.contact-list .ico svg { width: 1.25rem; height: 1.25rem; }
.contact-list .lbl { display: block; font-size: .875rem; font-weight: 600; line-height: 1.3; }
.contact-list .sub { display: block; font-size: .75rem; color: var(--muted-fg); line-height: 1.4; margin-top: .125rem; }

/* ================================================================
   工具頁共用
   ================================================================ */
.tool-head { max-width: 48rem; margin: 0 auto 2.5rem; }
.tool-head h1 {
  font-size: 1.75rem; line-height: 1.25; font-weight: 700;
  color: var(--foreground); letter-spacing: .01em; margin: 0 0 .75rem;
}
@media (min-width: 48rem) { .tool-head h1 { font-size: 2.25rem; } }
.tool-head .lead { font-size: 1.0625rem; line-height: 1.75; color: #52525c; margin: 0; }
.dark .tool-head .lead { color: #9f9fa9; }

.tool-col { max-width: 48rem; margin-inline: auto; }
.tool-card {
  border: 1px solid var(--border); border-radius: .875rem;
  padding: 1.5rem; background: #fff;
}
.dark .tool-card { background: rgb(255 255 255 / .03); }
.tool-card h2 { font-size: 1.0625rem; font-weight: 700; margin: 0 0 .875rem; color: var(--foreground); letter-spacing: normal; }
.tool-card p { font-size: .9375rem; line-height: 1.8; color: #52525c; margin: 0 0 .625rem; }
.dark .tool-card p { color: #9f9fa9; }
.tool-card p:last-child { margin-bottom: 0; }
.tool-card code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: .875em; padding: .1em .4em; border-radius: .25rem;
  background: color-mix(in oklch, var(--foreground) 8%, transparent);
}
.rule-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.rule-list li {
  display: grid; grid-template-columns: 1.5rem 1fr; gap: .625rem; align-items: start;
  font-size: .9375rem; line-height: 1.75; color: #52525c;
}
.dark .rule-list li { color: #9f9fa9; }
.rule-list .num {
  width: 1.5rem; height: 1.5rem; border-radius: 9999px; margin-top: .1rem;
  display: flex; align-items: center; justify-content: center;
  font-size: .75rem; font-weight: 600; font-variant-numeric: tabular-nums;
  background: color-mix(in oklch, var(--accent) 14%, transparent); color: var(--accent-text);
}
.tip { margin-top: 1rem; font-size: .875rem; color: var(--muted-fg); }

.field { margin-top: 1.75rem; }
.field > label { display: block; font-size: .875rem; font-weight: 600; color: var(--foreground); margin-bottom: .5rem; }
.field .hint { font-weight: 400; font-size: .75rem; color: var(--muted-fg); margin-left: .5rem; }
.field textarea {
  width: 100%; min-height: 12rem; resize: vertical;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: .875rem; line-height: 1.7;
  border: 1px solid var(--border); border-radius: .625rem; padding: .875rem;
  background: #fff; color: var(--foreground);
}
.dark .field textarea { background: rgb(255 255 255 / .04); }
.field textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }

.btn-row { margin-top: 1rem; display: flex; flex-wrap: wrap; gap: .625rem; align-items: center; }
.btn {
  display: inline-flex; align-items: center; gap: .375rem;
  border-radius: .625rem; padding: .625rem 1.125rem;
  font-size: .875rem; font-weight: 600; border: 1px solid transparent; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s, opacity .15s;
}
/* 白字放在品牌亮青上只有 2.4:1，深色模式 1.9:1，按鈕字會糊。
   淺色用深青底配白字、深色用亮青底配深字，兩邊都在 5:1 以上。 */
.btn-primary { background: var(--accent-deep); color: #fff; }
.dark .btn-primary { background: var(--accent); color: #04302c; }
.btn-primary:hover:not(:disabled) { filter: brightness(1.08); }
.btn-ghost { border-color: var(--border); background: transparent; color: var(--foreground); }
.btn-ghost:hover:not(:disabled) { border-color: var(--accent-text); color: var(--accent-text); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-status { font-size: .8125rem; color: var(--accent-text); opacity: 0; transition: opacity .2s; }
.btn-status.on { opacity: 1; }

.preview-box {
  margin-top: 1.75rem; border: 1px solid var(--border); border-radius: .625rem;
  padding: .875rem; background: color-mix(in oklch, var(--foreground) 4%, transparent);
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: .875rem; line-height: 1.7; white-space: pre-wrap; word-break: break-word;
  min-height: 6rem; color: var(--foreground);
}
.preview-box:empty::before { content: attr(data-empty); color: var(--muted-fg); }

/* 停用公告 */
.notice {
  border: 1px solid color-mix(in oklch, #f0b100 45%, transparent);
  background: color-mix(in oklch, #f0b100 10%, transparent);
  border-radius: .875rem; padding: 1.25rem 1.375rem; margin-bottom: 2rem;
}
.notice h2 {
  display: flex; align-items: center; gap: .5rem;
  font-size: 1rem; font-weight: 700; margin: 0 0 .75rem; color: #8a5300; letter-spacing: normal;
}
.dark .notice h2 { color: #ffd230; }
.notice h2 svg { width: 1.125rem; height: 1.125rem; flex: 0 0 auto; }
.notice p { font-size: .9375rem; line-height: 1.8; color: #7b4b00; margin: 0 0 .75rem; }
.dark .notice p { color: #e8c27a; }
.alt-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .625rem; }
.alt-list li {
  border-radius: .625rem; padding: .875rem 1rem;
  background: rgb(255 255 255 / .6); border: 1px solid transparent;
}
.dark .alt-list li { background: rgb(255 255 255 / .05); }
.alt-list li.pick { border-color: color-mix(in oklch, var(--accent) 45%, transparent); }
.alt-list p { font-size: .875rem; line-height: 1.75; color: #52525c; margin: 0 0 .5rem; }
.dark .alt-list p { color: #d4d4d8; }
.alt-list strong { color: var(--foreground); }
.alt-list a {
  display: inline-flex; align-items: center; gap: .25rem;
  font-size: .8125rem; font-weight: 600; color: var(--accent-text);
}
.alt-list a svg { width: .875rem; height: .875rem; }

.demo-video {
  margin: 3rem auto 0; max-width: 56rem; border-radius: .875rem;
  background: #27272a; padding: .75rem;
}
.demo-video video { width: 100%; height: auto; display: block; border-radius: .5rem; }
.tool-outro { margin: 6rem auto 0; text-align: center; max-width: 42rem; }
.tool-outro .name { font-size: 1.5rem; font-weight: 800; color: var(--foreground); letter-spacing: .02em; }
@media (min-width: 48rem) { .tool-outro .name { font-size: 2rem; } }
.tool-outro p { margin-top: .5rem; font-size: 1.0625rem; color: var(--muted-fg); }

/* ---------- 404 ---------- */
.nf { max-width: 34rem; margin: 4rem auto 0; }
.nf .code {
  font-size: 4.5rem; font-weight: 800; line-height: 1;
  color: color-mix(in oklch, var(--accent) 30%, transparent);
  margin: 0 0 .75rem; letter-spacing: .04em;
}
.nf h1 { font-size: 1.75rem; font-weight: 700; color: var(--foreground); margin: 0 0 .875rem; }
.nf .lead { font-size: 1rem; line-height: 1.8; color: #52525c; margin: 0; }
.dark .nf .lead { color: #9f9fa9; }
.nf .btn-row { margin-top: 1.75rem; }
.nf-list { list-style: none; margin: 3rem 0 0; padding: 1.5rem 0 0; border-top: 1px solid var(--border); display: grid; gap: .25rem; }
.nf-list a {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: .625rem 0; color: var(--foreground); font-size: .9375rem;
}
.nf-list a:hover { color: var(--accent-text); }
.nf-list time { flex: 0 0 auto; font-size: .8125rem; color: var(--muted-fg); font-variant-numeric: tabular-nums; }
