/* anoni.net 首頁與社群頁面。品牌色只有 cyan，依用途分工：
   - 結構：中性灰階（--n-*），分隔線、邊框與區塊底色。區塊靠淡底色區分，少用線框
   - 層級：深色文字，靠字重與大小
   - 互動：cyan，連結、按鈕、目前位置、焦點、滑過
   - 識別：logo 與首頁主視覺
   - 分類與資料：三大主題色、動態標籤、觀測圖表的 cyan 色階
   2026-10 以前 cyan 同時負責上面全部，標題、導言、連結與邊框都是同一種藍，讀者分不出哪裡
   可以點、哪裡是區塊的邊界，看久了也累。規格寫在品牌素材頁的「社群首頁的配色與版面」。
   色票照抄文件站 docs/zh-TW/stylesheets/extra.css 的 --brand-cyan-*，不自己調。 */

:root {
  --brand-cyan-50: #e0f4ff;
  --brand-cyan-100: #b3e3ff;
  --brand-cyan-200: #80d1ff;
  --brand-cyan-300: #4dbfff;
  --brand-cyan-400: #26b3ff;
  --brand-cyan-500: #00aeff;
  --brand-cyan-600: #009ee6;
  --brand-cyan-700: #0089bf;
  --brand-cyan-800: #006d99;
  --brand-cyan-900: #003e57;

  /* 中性灰階，從品牌的 --neutral-muted（#546e7a）那一系延伸，帶一點藍，跟 cyan 放在一起
     不顯得髒 */
  --n-50: #f3f6f7;
  --n-100: #e3e9ec;
  --n-200: #cdd6da;
  --n-300: #a7b5bb;

  --c-bg: #ffffff;
  --c-text: #1d2b31;
  --c-strong: #13232a;
  --c-muted: #52646b;
  --c-icon: #5b6e76;
  /* 結構 */
  --c-hair: var(--n-100);
  --c-border: var(--n-200);
  --c-border-strong: var(--n-300);
  --c-surface: var(--n-50);
  --c-fill: var(--n-50);
  /* 互動與識別：線框按鈕、地區切換、滑過的卡片用 --c-line，目前位置與焦點另有一組 */
  --c-line: var(--brand-cyan-500);
  --c-link: var(--brand-cyan-800);
  --c-accent: var(--brand-cyan-700);
  --c-solid: var(--brand-cyan-800);
  --c-active: var(--brand-cyan-600);
  --c-focus: var(--brand-cyan-500);

  /* 2026 三大主題的分類色，對應品牌素材的 --cat-privacy、--cat-relay、--cat-payments。
     品牌的綠與橘在白底對比不到 4.5，這裡用深一階的版本，深色模式另用淺色 */
  --topic-privacy: #2e7d32;
  --topic-relay: #7b1fa2;
  --topic-payments: #c25400;
  /* 圓形圖示的分類色，2026-10 從三大主題擴充成八類，只用在社群首頁（文件站用 Material 的配色）。
     後五類在 OKLCH 用相近的明度與彩度補出色相，白底與深色底的對比都在 4.5 以上 */
  --cat-privacy: var(--topic-privacy);
  --cat-relay: var(--topic-relay);
  --cat-payments: var(--topic-payments);
  --cat-observe: #026a9d;
  --cat-content: #02736e;
  --cat-dev: #4d57b7;
  --cat-secure: #a53453;
  --cat-community: #786101;

  /* 品牌的 --accent-action（橘）與 --accent-emergency（紅）。按鈕是白字，品牌的橘 #ef6c00
     對比只有 3.1，用深一階的版本 */
  --action: #c25400;
  --action-hover: #a84800;
  --danger: #d32f2f;
  /* 社群動態的標籤，照品牌素材頁的「公告 tag」：新增 cyan、活動橘、更新灰。
     品牌的 cyan-600 當小字對比不夠，用 cyan-800 */
  --ut-new: var(--brand-cyan-800);
  --ut-event: var(--action);
  --ut-update: var(--c-muted);
  /* OONI 測量結果的語意色：正常是 cyan，異常是琥珀，確認封鎖是警告紅，測量失敗是灰 */
  --oc-ok: var(--brand-cyan-600);
  --oc-anomaly: #f0a030;
  --oc-confirmed: var(--danger);
  --oc-failure: #a3b1b7;

  --radius: 8px;
  /* 外框由文件頁反推：內容欄 42rem（內文 17px，一行約 42 個中文字）+ 間距 + 本頁內容。
     頁首、內容、頁尾在每一頁都對齊這組左右邊界，見下方「版面」 */
  --toc-w: 13rem;
  --toc-gap: 3.5rem;
  --frame: calc(42rem + var(--toc-gap) + var(--toc-w));
  --font: system-ui, -apple-system, "Segoe UI", "Noto Sans TC", "Noto Sans CJK TC", "PingFang TC", "Microsoft JhengHei", sans-serif;
}

:lang(zh-Hans) {
  --font: system-ui, -apple-system, "Segoe UI", "Noto Sans SC", "Noto Sans CJK SC", "PingFang SC", "Microsoft YaHei", sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    --n-50: #082b3a;
    --n-100: #133847;
    --n-200: #234757;
    --n-300: #3c6070;
    --c-bg: #00202d;
    --c-text: #d8eef7;
    --c-strong: #ffffff;
    --c-muted: #9db7c2;
    --c-icon: #9db7c2;
    --c-line: var(--brand-cyan-600);
    --c-link: var(--brand-cyan-200);
    --c-accent: var(--brand-cyan-300);
    --c-solid: var(--brand-cyan-700);
    --c-active: var(--brand-cyan-400);
    --c-focus: var(--brand-cyan-400);
    --topic-privacy: #81c784;
    --topic-relay: #ce93d8;
    --topic-payments: #ffa040;
    --cat-observe: #69c1fc;
    --cat-content: #3ed0c8;
    --cat-dev: #a3b2fe;
    --cat-secure: #f996a9;
    --cat-community: #d3b555;
    --danger: #e57373;
    --ut-new: var(--brand-cyan-300);
    --ut-event: #ffa040;
    --oc-ok: var(--brand-cyan-600);
    --oc-anomaly: #ffb74d;
    --oc-failure: #5d727b;
  }
}

* { box-sizing: border-box; }
html { background: var(--c-bg); color: var(--c-text); font: 17px/1.75 var(--font); }
body { margin: 0; padding: 0 1rem; }
a { color: var(--c-link); text-underline-offset: .2em; }
a:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; border-radius: 2px; }
.i { width: 1.25em; height: 1.25em; fill: currentColor; vertical-align: -.25em; flex: none; }

/* 外框：沒有框線，只是一組左右邊界。2026-10 以前整頁裝在 42rem 的線框裡，表格、圖表與
   卡片都擠在同一個窄欄 */
.sheet { max-width: var(--frame); margin: 0 auto; }

/* 頁首：手機兩列（品牌與語言、導覽列），桌機併成一列，下面一條細線 */
header { padding-top: 1rem; }
.top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.brand { display: flex; align-items: center; gap: .4rem; font-weight: 700; color: var(--c-strong); text-decoration: none; font-size: 1.05rem; }
.brand .logo { width: 1.6rem; height: 1.6rem; }
.lang { display: flex; gap: .75rem; font-size: .85rem; }
.lang a { text-decoration: none; color: var(--c-muted); }
.lang a[aria-current] { color: var(--c-strong); font-weight: 700; }
nav.main {
  display: flex;
  justify-content: space-between;
  margin: .6rem 0 0;
  border-top: 1px solid var(--c-hair);
  border-bottom: 1px solid var(--c-hair);
}
nav.main a {
  flex: 1 1 auto;
  text-align: center;
  padding: .5rem .15rem;
  text-decoration: none;
  color: var(--c-text);
  font-size: .95rem;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
nav.main a[aria-current] { color: var(--c-strong); font-weight: 700; border-bottom-color: var(--c-active); }
nav.main a:hover { color: var(--c-accent); }
/* 英文的項目比較長，手機上縮小一點才放得進一列 */
:lang(en) nav.main a { font-size: .82rem; }
/* 320px 的手機上英文六項仍差十幾 px，再縮一點，項目間距也收窄 */
@media (max-width: 359px) { :lang(en) nav.main a { font-size: .74rem; padding-left: .05rem; padding-right: .05rem; } }
@media (min-width: 768px) {
  header { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 0 2rem; padding-top: 1.1rem; border-bottom: 1px solid var(--c-hair); }
  header .top { display: contents; }
  header .brand { grid-column: 1; grid-row: 1; }
  header .lang { grid-column: 3; grid-row: 1; }
  nav.main { grid-column: 2; grid-row: 1; justify-content: center; gap: .25rem 1.75rem; margin: 0; border: 0; }
  nav.main a { flex: none; padding: .9rem .1rem; }
}

/* 標題與段落 */
/* 麵包屑：上一層的名稱接一個箭頭，指向下方的標題。平常不加底線，滑鼠移上去才出現 */
.crumb { display: flex; align-items: center; gap: .1rem; margin: 1.5rem 0 -1rem; font-size: .85rem; }
.crumb a { color: var(--c-muted); text-decoration: none; }
.crumb a:hover { color: var(--c-accent); text-decoration: underline; }
.crumb .i { width: 1.15em; height: 1.15em; vertical-align: 0; color: var(--c-muted); opacity: .7; }
.crumb + h1 { margin-top: 1.25rem; }
h1 { color: var(--c-strong); font-size: 1.8rem; line-height: 1.3; margin: 1.5rem 0 .5rem; }
.lead { color: var(--c-text); font-size: 1.1rem; font-weight: 500; margin: 0 0 1rem; }
h2 {
  display: flex;
  align-items: center;
  gap: .6rem;
  color: var(--c-strong);
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: .02em;
  margin: 2.5rem 0 .75rem;
}
/* 標題後的線：開頭一小段用識別色 cyan-700，其餘是分隔線的灰，跟卡片框線與列表的分隔線區分開 */
h2::after {
  content: "";
  flex: 1;
  height: 3px;
  background:
    linear-gradient(var(--c-accent), var(--c-accent)) left center / 2.5rem 3px no-repeat,
    linear-gradient(var(--c-hair), var(--c-hair)) left center / 100% 1px no-repeat;
}
/* 從「本頁內容」跳過來時，標題不要貼齊視窗上緣 */
h2[id] { scroll-margin-top: 1rem; }
/* 層級是 h1 1.8rem > h2 1.25rem > h3 1.05rem，h2 原本是 .95rem 的段落標籤，比 h3 還小（2026-10-21 調整） */
h3 { color: var(--c-strong); font-size: 1.05rem; margin: 1.5rem 0 .25rem; }
p { margin: .5rem 0 1rem; }
/* 標題與導言避免最後一行只剩一兩個字，Firefox 不支援時照一般方式斷行。內文段落與列表不用：
   Safari 的 pretty 會重排整段讓每行等長，iPhone 上每行右邊都空出好幾個字（2026-10-12 發現） */
.lead, .row .t, h1, h3 { text-wrap: pretty; }

/* Markdown 內文 */
.prose ul:not(.rows), .prose ol { padding-left: 1.4rem; margin: .5rem 0 1rem; }
.prose li { margin: .25rem 0; }
/* 指紋、網址這類沒有空白的長字串，超出外框時才斷開 */
.prose a, .prose code { overflow-wrap: anywhere; }
.prose li > ul { margin: .25rem 0; }
.prose hr { border: 0; border-top: 1px solid var(--c-hair); margin: 2rem 0; }
/* 行內程式碼用淡底色，不用 cyan 字，才不會被當成連結 */
.prose code { font-size: .88em; color: var(--c-text); background: var(--c-surface); padding: .05em .3em; border-radius: 4px; overflow-wrap: anywhere; }
.prose pre { overflow-x: auto; background: var(--c-surface); border-radius: var(--radius); padding: .75rem 1rem; font-size: .8rem; line-height: 1.5; }
.prose pre code { color: var(--c-text); background: none; padding: 0; }
.prose table { border-collapse: collapse; width: 100%; font-size: .92rem; margin: 1rem 0; }
.prose th, .prose td { border-bottom: 1px solid var(--c-hair); padding: .4rem .5rem; text-align: left; vertical-align: top; overflow-wrap: anywhere; }
.prose th { background: var(--c-surface); }
/* 最窄的手機上，英文表格的欄位多又有長字，縮小間距與字級才不會撐破外框 */
@media (max-width: 359px) { .prose table { font-size: .8rem; } .prose th, .prose td { padding: .35rem .3rem; } }
/* 三欄以上的表格（build.py 的 stack_tables）在手機上一列排成一塊，第一格是標題。
   stack--label 把欄名放在每一格左邊，欄寬用建置時算好的 --lw（最長欄名的字數）；
   stack--plain 不顯示欄名，第三欄以後用灰色小字。表頭只對讀屏軟體保留 */
@media (max-width: 559px) {
  .prose table.stack, .prose table.stack tbody, .prose table.stack tr, .prose table.stack td { display: block; }
  .prose table.stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .prose table.stack tr { border-bottom: 1px solid var(--c-hair); padding: .65rem 0; }
  .prose table.stack td { border: 0; padding: 0; }
  .prose table.stack td:first-child { font-weight: 700; margin-bottom: .2rem; }
  .prose table.stack td:empty { display: none; }
  .prose table.stack--label td:not(:first-child) { display: grid; grid-template-columns: calc(var(--lw) * .78rem) 1fr; column-gap: .75rem; align-items: baseline; margin-top: .1rem; }
  .prose table.stack--label td:not(:first-child)::before { content: attr(data-label); font-size: .78rem; color: var(--c-muted); overflow-wrap: normal; }
  .prose table.stack--plain td:nth-child(n+3) { font-size: .85rem; color: var(--c-muted); margin-top: .2rem; }
}
.prose img { max-width: 100%; height: auto; }
/* 操作步驟的截圖加一圈中性灰細框，白底的截圖才不會跟頁面混在一起 */
.prose img.shot { display: block; border: 1px solid var(--c-border); border-radius: var(--radius); margin: .5rem 0 1rem; }
/* 從文件站搬過來的頁面用 <figure> 包截圖，瀏覽器預設左右各縮 40px，手機上太窄 */
.prose figure:not(.pulse-chart) { margin: 1rem 0 1.25rem; }
.prose figure:not(.pulse-chart) figcaption { font-size: .85rem; line-height: 1.6; color: var(--c-muted); }
/* 產品名稱與設定步驟的表格：英文只在詞與詞之間斷行，真的放不下才拆開單字 */
.prose .tbl-names td, .prose .tbl-names th { overflow-wrap: break-word; }
/* admonition 用淡底色，不加框線 */
.admonition { background: var(--c-surface); border-radius: var(--radius); padding: .25rem 1.1rem; margin: 1rem 0; }
.admonition-title { color: var(--c-strong); font-weight: 700; margin-bottom: .25rem; }
/* danger 只用在安全警告，照品牌的配色守則用紅色，一般的提醒用 warning、維持中性底色 */
.admonition.danger { background: color-mix(in srgb, var(--danger) 8%, var(--c-bg)); }
.admonition.danger .admonition-title { color: var(--danger); }

/* 從文件站搬過來的頁面用到的元件：折疊區塊、分頁、待辦清單、卡片格線、註腳、議程標籤。
   結構用中性灰階，互動與目前位置用 cyan。 */
.prose details { background: var(--c-surface); border-radius: var(--radius); padding: .5rem 1rem; margin: 1rem 0; }
.prose details[open] > summary { margin-bottom: .5rem; }
.prose summary { cursor: pointer; color: var(--c-strong); font-weight: 700; line-height: 1.5; }
.prose summary::marker { color: var(--c-icon); }

/* 分頁（pymdownx.tabbed 的 alternate_style）：radio 加 CSS，不需要 JavaScript。
   分頁多的時候標籤列橫向捲動，一組最多支援 30 頁 */
.tabbed-set { display: flex; flex-wrap: wrap; position: relative; margin: 1rem 0; }
.tabbed-set > input { position: absolute; opacity: 0; pointer-events: none; }
.tabbed-labels { display: flex; width: 100%; overflow-x: auto; border-bottom: 1px solid var(--c-hair); scrollbar-width: thin; }
.tabbed-labels > label { flex: none; padding: .35rem .8rem; font-size: .88rem; color: var(--c-muted); cursor: pointer; white-space: nowrap; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.tabbed-labels > label:hover { color: var(--c-accent); }
.tabbed-set > input:nth-child(1):checked ~ .tabbed-labels > label:nth-child(1),
.tabbed-set > input:nth-child(2):checked ~ .tabbed-labels > label:nth-child(2),
.tabbed-set > input:nth-child(3):checked ~ .tabbed-labels > label:nth-child(3),
.tabbed-set > input:nth-child(4):checked ~ .tabbed-labels > label:nth-child(4),
.tabbed-set > input:nth-child(5):checked ~ .tabbed-labels > label:nth-child(5),
.tabbed-set > input:nth-child(6):checked ~ .tabbed-labels > label:nth-child(6),
.tabbed-set > input:nth-child(7):checked ~ .tabbed-labels > label:nth-child(7),
.tabbed-set > input:nth-child(8):checked ~ .tabbed-labels > label:nth-child(8),
.tabbed-set > input:nth-child(9):checked ~ .tabbed-labels > label:nth-child(9),
.tabbed-set > input:nth-child(10):checked ~ .tabbed-labels > label:nth-child(10),
.tabbed-set > input:nth-child(11):checked ~ .tabbed-labels > label:nth-child(11),
.tabbed-set > input:nth-child(12):checked ~ .tabbed-labels > label:nth-child(12),
.tabbed-set > input:nth-child(13):checked ~ .tabbed-labels > label:nth-child(13),
.tabbed-set > input:nth-child(14):checked ~ .tabbed-labels > label:nth-child(14),
.tabbed-set > input:nth-child(15):checked ~ .tabbed-labels > label:nth-child(15),
.tabbed-set > input:nth-child(16):checked ~ .tabbed-labels > label:nth-child(16),
.tabbed-set > input:nth-child(17):checked ~ .tabbed-labels > label:nth-child(17),
.tabbed-set > input:nth-child(18):checked ~ .tabbed-labels > label:nth-child(18),
.tabbed-set > input:nth-child(19):checked ~ .tabbed-labels > label:nth-child(19),
.tabbed-set > input:nth-child(20):checked ~ .tabbed-labels > label:nth-child(20),
.tabbed-set > input:nth-child(21):checked ~ .tabbed-labels > label:nth-child(21),
.tabbed-set > input:nth-child(22):checked ~ .tabbed-labels > label:nth-child(22),
.tabbed-set > input:nth-child(23):checked ~ .tabbed-labels > label:nth-child(23),
.tabbed-set > input:nth-child(24):checked ~ .tabbed-labels > label:nth-child(24),
.tabbed-set > input:nth-child(25):checked ~ .tabbed-labels > label:nth-child(25),
.tabbed-set > input:nth-child(26):checked ~ .tabbed-labels > label:nth-child(26),
.tabbed-set > input:nth-child(27):checked ~ .tabbed-labels > label:nth-child(27),
.tabbed-set > input:nth-child(28):checked ~ .tabbed-labels > label:nth-child(28),
.tabbed-set > input:nth-child(29):checked ~ .tabbed-labels > label:nth-child(29),
.tabbed-set > input:nth-child(30):checked ~ .tabbed-labels > label:nth-child(30) { color: var(--c-strong); font-weight: 700; border-bottom-color: var(--c-active); }
.tabbed-set > input:focus-visible ~ .tabbed-labels { outline: 2px solid var(--c-focus); outline-offset: 2px; }
.tabbed-content { width: 100%; }
.tabbed-block { display: none; padding-top: .5rem; }
.tabbed-set > input:nth-child(1):checked ~ .tabbed-content > .tabbed-block:nth-child(1),
.tabbed-set > input:nth-child(2):checked ~ .tabbed-content > .tabbed-block:nth-child(2),
.tabbed-set > input:nth-child(3):checked ~ .tabbed-content > .tabbed-block:nth-child(3),
.tabbed-set > input:nth-child(4):checked ~ .tabbed-content > .tabbed-block:nth-child(4),
.tabbed-set > input:nth-child(5):checked ~ .tabbed-content > .tabbed-block:nth-child(5),
.tabbed-set > input:nth-child(6):checked ~ .tabbed-content > .tabbed-block:nth-child(6),
.tabbed-set > input:nth-child(7):checked ~ .tabbed-content > .tabbed-block:nth-child(7),
.tabbed-set > input:nth-child(8):checked ~ .tabbed-content > .tabbed-block:nth-child(8),
.tabbed-set > input:nth-child(9):checked ~ .tabbed-content > .tabbed-block:nth-child(9),
.tabbed-set > input:nth-child(10):checked ~ .tabbed-content > .tabbed-block:nth-child(10),
.tabbed-set > input:nth-child(11):checked ~ .tabbed-content > .tabbed-block:nth-child(11),
.tabbed-set > input:nth-child(12):checked ~ .tabbed-content > .tabbed-block:nth-child(12),
.tabbed-set > input:nth-child(13):checked ~ .tabbed-content > .tabbed-block:nth-child(13),
.tabbed-set > input:nth-child(14):checked ~ .tabbed-content > .tabbed-block:nth-child(14),
.tabbed-set > input:nth-child(15):checked ~ .tabbed-content > .tabbed-block:nth-child(15),
.tabbed-set > input:nth-child(16):checked ~ .tabbed-content > .tabbed-block:nth-child(16),
.tabbed-set > input:nth-child(17):checked ~ .tabbed-content > .tabbed-block:nth-child(17),
.tabbed-set > input:nth-child(18):checked ~ .tabbed-content > .tabbed-block:nth-child(18),
.tabbed-set > input:nth-child(19):checked ~ .tabbed-content > .tabbed-block:nth-child(19),
.tabbed-set > input:nth-child(20):checked ~ .tabbed-content > .tabbed-block:nth-child(20),
.tabbed-set > input:nth-child(21):checked ~ .tabbed-content > .tabbed-block:nth-child(21),
.tabbed-set > input:nth-child(22):checked ~ .tabbed-content > .tabbed-block:nth-child(22),
.tabbed-set > input:nth-child(23):checked ~ .tabbed-content > .tabbed-block:nth-child(23),
.tabbed-set > input:nth-child(24):checked ~ .tabbed-content > .tabbed-block:nth-child(24),
.tabbed-set > input:nth-child(25):checked ~ .tabbed-content > .tabbed-block:nth-child(25),
.tabbed-set > input:nth-child(26):checked ~ .tabbed-content > .tabbed-block:nth-child(26),
.tabbed-set > input:nth-child(27):checked ~ .tabbed-content > .tabbed-block:nth-child(27),
.tabbed-set > input:nth-child(28):checked ~ .tabbed-content > .tabbed-block:nth-child(28),
.tabbed-set > input:nth-child(29):checked ~ .tabbed-content > .tabbed-block:nth-child(29),
.tabbed-set > input:nth-child(30):checked ~ .tabbed-content > .tabbed-block:nth-child(30) { display: block; }

/* 待辦清單：勾選框畫成線框，完成的打勾 */
.task-list { list-style: none; padding-left: .2rem !important; }
.task-list-item { position: relative; padding-left: 1.6rem; }
.task-list-control input { position: absolute; opacity: 0; }
.task-list-indicator { position: absolute; left: 0; top: .35em; width: 1rem; height: 1rem; border: 1px solid var(--c-border-strong); border-radius: 3px; }
.task-list-control input:checked + .task-list-indicator { background: var(--c-solid); border-color: var(--c-solid); }
.task-list-control input:checked + .task-list-indicator::after { content: ""; position: absolute; left: .3rem; top: .08rem; width: .3rem; height: .55rem; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }

/* 卡片格線（md_in_html 的 grid cards）：線框卡，手機一欄、桌機兩欄 */
.grid.cards > ul { list-style: none; padding: 0 !important; margin: 1rem 0; display: grid; gap: .75rem; }
@media (min-width: 640px) { .grid.cards > ul { grid-template-columns: 1fr 1fr; } }
@media (min-width: 900px) { .grid.cards > ul { grid-template-columns: repeat(3, 1fr); } }
.grid.cards > ul > li { border: 1px solid var(--c-border); border-radius: var(--radius); padding: .8rem 1rem; margin: 0; }
.grid.cards > ul > li > :first-child { margin-top: 0; }
.grid.cards > ul > li > :last-child { margin-bottom: 0; }
.grid.cards hr { border: 0; border-top: 1px solid var(--c-hair); margin: .6rem 0; }
.grid.cards .i { color: var(--c-icon); }

/* 註腳 */
.footnote { font-size: .85rem; color: var(--c-muted); margin-top: 2rem; }
.footnote hr { border: 0; border-top: 1px solid var(--c-hair); }
.footnote-ref { font-size: .75em; }
/* 每一條註腳包著 <p>，段落的上下間距疊起來條目之間有 30px，拿掉之後靠 li 的間距分開 */
.footnote ol { margin-top: .75rem; }
.footnote li { margin: .35rem 0; }
.footnote li > p { margin: 0; }

/* 議程表的標籤：類型用 cyan 實心，場地用中性灰線框，強調文字用深色粗體 */
.tag { display: inline-block; padding: 0 .4rem; border: 1px solid var(--c-border); border-radius: 4px; font-size: .8rem; line-height: 1.6; color: var(--c-muted); white-space: nowrap; }
.tag--solid { background: var(--c-solid); border-color: var(--c-solid); color: #fff; }
.tag-text { color: var(--c-strong); font-weight: 700; }
/* 議程的主題分類，對應文件站的 .sess-tag：通用是 cyan，三大主題用 --topic-*。
   同一格的場次圖示與標題跟著標籤上色，描述列的箭頭維持中性。
   維持線框不加底色，淡底會讓淺色模式的綠與橘掉到 4.5 以下。通用用 --c-link（cyan-800），
   cyan-700 在白底只有 3.9 */
.tag--basic { --tag-c: var(--c-link); }
.tag--privacy { --tag-c: var(--topic-privacy); }
.tag--relay { --tag-c: var(--topic-relay); }
.tag--payments { --tag-c: var(--topic-payments); }
.tag--basic, .tag--privacy, .tag--relay, .tag--payments { border-color: var(--tag-c); color: var(--tag-c); }
.prose td:has(.tag--basic) { --row-c: var(--c-link); }
.prose td:has(.tag--privacy) { --row-c: var(--topic-privacy); }
.prose td:has(.tag--relay) { --row-c: var(--topic-relay); }
.prose td:has(.tag--payments) { --row-c: var(--topic-payments); }
.prose td:has(.tag--basic, .tag--privacy, .tag--relay, .tag--payments) :is(strong, .i:has(+ strong)) { color: var(--row-c); }
/* 桌機的議程表（時間、議程、講者三欄）。表格預設 overflow-wrap: anywhere，議程欄
   字多，時間被壓成「09:30- / 10:00 / 30 分 / 鐘」、講者從 anoni.n|et 中間斷開。
   時間不換行，講者給固定寬度並只在詞與詞之間換行。手機版是一列一塊，不受影響 */
@media (min-width: 560px) {
  .prose table.stack:has(td .tag) :is(th, td):first-child { white-space: nowrap; width: 1%; }
  .prose table.stack:has(td .tag) :is(th, td):last-child { width: 8.5em; overflow-wrap: normal; }
}
.prose .i { color: var(--c-icon); }
/* 連結與按鈕裡的圖示跟著文字的顏色：實心按鈕的圖示是白色，「全部專案」這類連結的箭頭與
   列表右側的箭頭是連結色。:where() 讓權重跟上一條相同，後面的 .toolrow .i 這類刻意用灰色
   的規則仍然有效 */
.prose :where(a) .i { color: inherit; }

/* 首頁主視覺 */
.hero h1 { display: flex; align-items: center; gap: .5rem; font-size: 2rem; margin-top: 1.75rem; }
.hero h1 .logo { width: 3rem; height: 3rem; flex: none; }
.hero h1 small { display: block; font-size: .55em; color: var(--c-accent); font-weight: 500; }

/* 細線列：三大主題、觀測與工具、頁內的延伸連結 */
.rows { list-style: none; margin: 0; padding: 0; }
.rows li { border-bottom: 1px solid var(--c-hair); margin: 0; }
.rows li:first-child { border-top: 1px solid var(--c-hair); }
.row { display: flex; gap: .9rem; align-items: flex-start; padding: .85rem .1rem; text-decoration: none; color: inherit; }
.row:hover .t { color: var(--c-accent); }
.row .ic { flex: none; display: grid; place-items: center; width: 2.4rem; height: 2.4rem; border-width: 1px; border-style: solid; border-radius: 50%; }
.row .b { flex: 1; min-width: 0; }
.row .t { display: block; font-weight: 700; color: var(--c-strong); }
/* 專案代號縮小放在名稱下方，名稱長短不一，放旁邊時換行的位置會不一致 */
.row .t .code { display: block; margin-top: .1rem; font-size: .75rem; font-weight: 400; color: var(--c-muted); font-family: ui-monospace, monospace; white-space: nowrap; }
.row .d { display: block; color: var(--c-muted); font-size: .9rem; line-height: 1.6; }
/* 右邊的箭頭代表可以點，用連結色 */
.row .go { align-self: center; color: var(--c-link); }
/* 圖示圈的分類色。.cat-* 可以加在圖示、整個列表或卡片上，底下的圖示圈都套用，沒有分類的維持中性灰。
   .topic-* 是三大主題原本的名稱，主題標籤還在用 */
.cat-privacy, .topic-privacy { --topic: var(--cat-privacy); }
.cat-relay, .topic-relay { --topic: var(--cat-relay); }
.cat-payments, .topic-payments { --topic: var(--cat-payments); }
.cat-observe, .topic-observe { --topic: var(--cat-observe); }
.cat-content { --topic: var(--cat-content); }
.cat-dev { --topic: var(--cat-dev); }
.cat-secure { --topic: var(--cat-secure); }
.cat-community { --topic: var(--cat-community); }
.row .ic, .card .ic { color: var(--topic, var(--c-icon)); border-color: var(--topic, var(--c-border)); }
:is(.row, .card) .ic:is([class*="cat-"], [class*="topic-"]), [class*="cat-"] :is(.row, .card) .ic, :is(.row, .card)[class*="cat-"] .ic { background: color-mix(in srgb, var(--topic) 8%, var(--c-bg)); }
.topic-tag { display: inline-flex; align-items: center; gap: .35rem; margin: 1.25rem 0 -.75rem; padding: .1rem .65rem .1rem .5rem; border: 1px solid var(--topic); border-radius: 999px; color: var(--topic); background: color-mix(in srgb, var(--topic) 8%, var(--c-bg)); font-size: .8rem; font-weight: 600; }
/* 麵包屑的下邊距是 -1rem（讓標題貼近），標籤是行內元素不會跟它摺疊，上邊距要多抵銷那 1rem */
.crumb + .topic-tag { margin-top: 1.6rem; }
.topic-tag + h1 { margin-top: 1.25rem; }
.row .meta { display: block; color: var(--c-muted); font-size: .85rem; font-variant-numeric: tabular-nums; }
/* 動態列表的摘要最多三行，完整內容在文章裡 */
.ut { display: inline-block; margin-right: .45rem; padding: 0 .4rem; border: 1px solid currentColor; border-radius: 4px; font-size: .75rem; font-weight: 600; line-height: 1.5; }
.ut-new { color: var(--ut-new); }
.ut-event { color: var(--ut-event); }
.ut-update { color: var(--ut-update); }
.rows.updates .d { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; }
.post-date { color: var(--c-muted); font-size: .9rem; margin: -.25rem 0 1.25rem; font-variant-numeric: tabular-nums; }

/* 內容專案的卡片（文件、新聞導讀）：白底中性灰細框，滑過時框線變 cyan。桌機兩欄。整張卡片可以點，
   卡片裡的最新文章、語系與「關於這個專案」是另外的連結，z-index 疊在整張卡片的連結上面 */
.cards { display: grid; gap: .75rem; margin: 1rem 0; }
@media (min-width: 768px) { .cards { grid-template-columns: repeat(2, 1fr); } }
.card { position: relative; display: flex; flex-direction: column; padding: 1rem 1.1rem .8rem; border: 1px solid var(--c-border); border-radius: var(--radius); background: var(--c-bg); transition: background-color .15s, border-color .15s; }
.card:hover { background: var(--c-fill); border-color: var(--c-line); }
.card-h { display: flex; align-items: center; gap: .7rem; }
.card .ic { flex: none; display: grid; place-items: center; width: 2.4rem; height: 2.4rem; border-width: 1px; border-style: solid; border-radius: 50%; }
.card a.n { color: var(--c-strong); font-weight: 700; font-size: 1.1rem; text-decoration: none; }
.card a.n::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius); }
.card .p { display: block; color: var(--c-muted); font-size: .8rem; line-height: 1.4; }
/* 全站的段落用 text-wrap: pretty。Safari 會重排整段讓每行等長，卡片的簡介每行都提早斷行，
   右邊空出好幾個字，這裡改回一般的換行 */
.card p { margin: .65rem 0 .6rem; font-size: .92rem; line-height: 1.7; text-wrap: wrap; }
.card ul.card-latest { list-style: none; margin: 0 0 .6rem; padding: .5rem 0 0; border-top: 1px solid var(--c-hair); }
.card-latest li { display: grid; grid-template-columns: 2.6rem 1fr; gap: .4rem; margin: .2rem 0; font-size: .85rem; line-height: 1.55; }
.card-latest time { color: var(--c-muted); font-variant-numeric: tabular-nums; }
/* 標題最多兩行，手機上的英文標題一行放不下 */
.card-latest a { position: relative; z-index: 1; min-width: 0; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; color: var(--c-text); text-decoration: none; }
.card-latest a:hover { color: var(--c-link); text-decoration: underline; }
.tags { display: flex; flex-wrap: wrap; gap: .2rem .8rem; font-size: .8rem; color: var(--c-muted); }
.tags a { position: relative; z-index: 1; }
.card .tags { margin-top: auto; padding-top: .55rem; border-top: 1px solid var(--c-hair); }
.card .tags a { color: var(--c-muted); text-decoration: none; }
.card .tags a[aria-current] { color: var(--c-strong); font-weight: 600; }
.card .tags a:hover { color: var(--c-link); text-decoration: underline; }
.card .tags a.about { color: var(--c-link); }

/* 線框卡：自架服務，中性灰框不填色，滑過時框線變 cyan。手機一欄、平板兩欄、桌機三欄 */
.svc { display: grid; gap: .75rem; margin: 1rem 0; }
@media (min-width: 640px) { .svc { grid-template-columns: 1fr 1fr; } }
@media (min-width: 900px) { .svc { grid-template-columns: repeat(3, 1fr); } }
.svc article { border: 1px solid var(--c-border); border-radius: var(--radius); padding: .9rem 1rem; }
.svc article:has(a:hover) { border-color: var(--c-line); }
.svc h3 { display: flex; align-items: center; gap: .45rem; margin: 0; }
/* 服務的圖示圈跟專案卡片一樣帶分類色，services.toml 的 cat 加在 article 上，沒有分類的維持中性灰 */
.svc h3 .ic { flex: none; display: grid; place-items: center; width: 2rem; height: 2rem; border: 1px solid var(--topic, var(--c-border)); border-radius: 50%; color: var(--topic, var(--c-icon)); }
.svc [class*="cat-"] h3 .ic, .svc article[class*="cat-"] h3 .ic { background: color-mix(in srgb, var(--topic) 8%, var(--c-bg)); }
.svc h3 .ic .i { color: inherit; }
.svc h3 a { color: var(--c-strong); }
.svc h3 small { font-weight: 400; color: var(--c-muted); font-size: .8rem; }
.svc p { font-size: .92rem; margin: .35rem 0 .5rem; }

/* 首頁那一排服務連結 */
.toolrow { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; margin: 1rem 0 0; font-size: .95rem; }
.toolrow a { display: flex; align-items: center; gap: .35rem; text-decoration: none; color: var(--c-text); }
.toolrow .i { color: var(--c-icon); }
.toolrow a[class*="cat-"] .i { color: var(--topic); }
.more { display: inline-flex; align-items: center; gap: .25rem; font-size: .9rem; }

/* 按鈕：實心的只有一個，其他是線框。圓角跟標籤一樣用 4px，不用膠囊形。實心按鈕是要讀者採取行動的（報名、訂閱、加入、投稿），
   照品牌的配色守則用橘色 */
.btns { display: flex; flex-wrap: wrap; gap: .6rem; margin: 1rem 0; }
.btn { display: inline-flex; align-items: center; gap: .4rem; padding: .4rem .9rem; border: 1px solid var(--c-line); border-radius: 4px; text-decoration: none; font-size: .92rem; }
.btn.solid { background: var(--action); border-color: var(--action); color: #fff; }
.btn.solid:hover, .btn.solid:focus-visible { background: var(--action-hover); border-color: var(--action-hover); }

/* 品牌素材頁：logo 放在四種底色上示範，底色是示範的內容，深色模式也不換 */
/* 每組都是四張，手機一欄、桌機排成 2×2，不會剩一張落單 */
.brand-row { display: grid; grid-template-columns: 1fr; gap: .75rem; margin: 1rem 0 1.25rem; }
@media (min-width: 520px) { .brand-row { grid-template-columns: 1fr 1fr; } }
.brand-card { background: #fff; border: 1px solid #cdcdcd; border-radius: var(--radius); padding: 1rem; }
.brand-card.dark { background: #1a1a1a; border-color: #333; }
.brand-card.cyan { background: var(--brand-cyan-500); border-color: var(--brand-cyan-700); }
.brand-card.cyan-deep { background: var(--brand-cyan-900); border-color: var(--brand-cyan-800); }
.brand-card-label { font-size: .75rem; color: #666; margin: 0 0 .75rem; }
.brand-card.dark .brand-card-label, .brand-card.cyan .brand-card-label, .brand-card.cyan-deep .brand-card-label { color: rgba(255, 255, 255, .75); }
.brand-sizes { display: flex; align-items: end; gap: .75rem; }
.brand-size { display: flex; flex-direction: column; align-items: center; }
.brand-size img { display: block; }
.brand-size-label { font-size: .65rem; color: #888; margin-top: .25rem; }
.brand-card.dark .brand-size-label, .brand-card.cyan .brand-size-label, .brand-card.cyan-deep .brand-size-label { color: rgba(255, 255, 255, .6); }
.wm-card { display: flex; flex-direction: column; }
.wm-card .wm-box { flex: 1; display: flex; align-items: center; justify-content: center; min-height: 5rem; }
.wm-card img { width: 100%; max-width: 14rem; height: auto; }
.wm-card.wm-stack img { max-width: 7rem; }
.color-swatch { display: inline-block; width: 1rem; height: 1rem; border: 1px solid #cdcdcd; border-radius: 3px; vertical-align: middle; margin-right: .4rem; }

/* Tor 中繼節點觀測（/projects/pulse/）：圖表是 pulse.py 畫的內嵌 SVG，顏色都從這裡給。
   五個深淺只用 cyan，淺色模式由深到淺，深色模式反過來，兩種底色上都讀得到。 */
.pulse { --pc1: var(--brand-cyan-800); --pc2: var(--brand-cyan-600); --pc3: var(--brand-cyan-400); --pc4: var(--brand-cyan-200); --pc5: var(--brand-cyan-100); }
@media (prefers-color-scheme: dark) {
  .pulse { --pc1: var(--brand-cyan-200); --pc2: var(--brand-cyan-400); --pc3: var(--brand-cyan-600); --pc4: var(--brand-cyan-800); --pc5: #0b4a63; }
}
.pulse-regions { display: flex; flex-wrap: wrap; gap: .4rem; margin: 1.25rem 0 .5rem; }
.pulse-regions a { padding: .15rem .75rem; border: 1px solid var(--c-line); border-radius: 4px; font-size: .85rem; text-decoration: none; }
.pulse-regions a[aria-current] { background: var(--c-solid); border-color: var(--c-solid); color: #fff; }
/* 地區名稱後面的代碼（TW、JP），跟網址 /projects/pulse/<code>/ 對得起來。不放國旗，港澳台的旗子沒有中立的選法。
   inline-block 讓連結的底線停在名稱，不延伸到代碼 */
.cc { display: inline-block; margin-left: .3em; font-size: .78em; font-weight: 400; letter-spacing: .03em; opacity: .65; }
.pulse-meta { margin: .25rem 0 0; font-size: .8rem; color: var(--c-muted); }
.pulse-stale { margin-left: .5rem; padding: 0 .4rem; border: 1px solid var(--c-border); border-radius: 4px; }
.pulse-empty { padding: 1rem; border: 1px dashed var(--c-border-strong); border-radius: var(--radius); color: var(--c-muted); }
.pulse-note { color: var(--c-muted); font-size: .9rem; }

/* 大數字卡片：數值、跟一個月前的差、近期走勢 */
.pulse-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: .6rem; margin: 1rem 0 1.75rem; }
@media (min-width: 640px) { .pulse-stats { grid-template-columns: repeat(4, 1fr); } }
.pulse-stat { border: 1px solid var(--c-hair); border-radius: var(--radius); padding: .7rem .8rem .5rem; background: linear-gradient(160deg, var(--c-fill), transparent 75%); }
.pulse-stat .k { display: block; font-size: .75rem; color: var(--c-muted); }
.pulse-stat .v { display: block; white-space: nowrap; font-size: 1.6rem; font-weight: 700; line-height: 1.25; color: var(--c-strong); font-variant-numeric: tabular-nums; }
.pulse-stat .v small { margin-left: .2rem; font-size: .55em; font-weight: 400; color: var(--c-muted); }
.pulse-stat .dl { display: block; font-size: .75rem; color: var(--c-muted); font-variant-numeric: tabular-nums; }
.pulse-stat .dl.down, .pulse-stat .dl.flat { color: var(--c-muted); }
.pulse-stat .dl small { margin-left: .3rem; color: var(--c-muted); font-size: 1em; }
.pc-spark { display: block; width: 100%; height: 28px; margin-top: .35rem; overflow: visible; }
.pc-spark polyline { fill: none; stroke: var(--pc2); stroke-width: 1.6; stroke-linejoin: round; }
.pc-spark circle { fill: var(--pc1); }

/* 圖表外框與圖例 */
.pulse-chart { margin: .75rem 0 1.25rem; padding: .75rem .75rem .5rem; border: 1px solid var(--c-hair); border-radius: var(--radius); }
.pulse-chart figcaption { display: flex; flex-wrap: wrap; justify-content: space-between; gap: .25rem .75rem; margin-bottom: .5rem; font-size: .8rem; font-weight: 700; color: var(--c-strong); }
.pulse-chart .lg { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .7rem; font-weight: 400; color: var(--c-muted); }
.sw { display: inline-block; width: .7rem; height: .7rem; margin-right: .3rem; border-radius: 2px; vertical-align: -.05rem; }
svg.pc { display: block; width: 100%; height: auto; overflow: visible; }
.pc-grid { stroke: var(--c-hair); stroke-width: 1; }
.pc-tick { fill: var(--c-muted); font-size: 11px; font-family: var(--font); }
/* SVG 跟著外框縮放，手機上整張圖縮到一半左右，刻度字用 viewBox 的單位放大回來 */
@media (max-width: 560px) { .pc-tick { font-size: 21px; } }
/* 幾年長的時間軸：計數異常的期間用琥珀底色，事件用虛線，註記字跟刻度一樣在手機上放大 */
svg.pc rect.pc-band { fill: color-mix(in srgb, var(--oc-anomaly) 16%, transparent); }
svg.pc rect.pc-band:hover { opacity: 1; }
.pc-mark { stroke: var(--c-muted); stroke-width: 1; stroke-dasharray: 4 4; }
.pc-note { fill: var(--c-muted); font-size: 11px; font-family: var(--font); }
.pc-peak { fill: var(--c-strong); font-weight: 700; }
.pc-line.pc-thin { stroke-width: 1.3; }
@media (max-width: 560px) { .pc-note { font-size: 20px; } }
/* 顏色類別只設定變數，長條、線、點各自讀變數，彼此不會互相覆蓋 */
.pc-s1 { --pcc: var(--pc1); }
.pc-s2 { --pcc: var(--pc2); }
.pc-s3 { --pcc: var(--pc3); }
.pc-s4 { --pcc: var(--pc4); }
.pc-s5 { --pcc: var(--pc5); }
.oc-ok { --pcc: var(--oc-ok); }
.oc-anomaly { --pcc: var(--oc-anomaly); }
.oc-confirmed { --pcc: var(--oc-confirmed); }
.oc-failure { --pcc: var(--oc-failure); }
svg.pc rect { fill: var(--pcc, var(--pc1)); }
.sw, .pulse-share span { background: var(--pcc, var(--pc1)); }
.pc-line { fill: none; stroke: var(--pcc, var(--pc1)); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.pc-dot { fill: var(--pcc, var(--pc1)); }
.pc-line.pc-dash { stroke-dasharray: 5 4; }
.sw.pc-dash { background: repeating-linear-gradient(90deg, var(--pcc) 0 3px, transparent 3px 5px); }
.pc-grad-top { stop-color: var(--pc2); stop-opacity: .45; }
.pc-grad-bottom { stop-color: var(--pc2); stop-opacity: 0; }
svg.pc rect:hover, svg.pc circle:hover { opacity: .7; }

/* ASN：一條分段的占比長條，加上前幾名的表 */
.pulse-share { display: flex; gap: 2px; height: .9rem; margin: .25rem 0 .9rem; border-radius: 999px; overflow: hidden; }
.pulse-share span { display: block; min-width: 3px; }
.pulse-asn { margin: 0; font-size: .85rem; }
.pulse-asn td:first-child, .pulse-asn th { white-space: nowrap; }
.pulse-asn .n { text-align: right; font-variant-numeric: tabular-nums; }
/* 網路名稱常是 UBBNET-AS-TW 這種沒有空格的長字串，不允許在中間斷開的話，窄螢幕上整張表會撐破外框 */
.pulse-asn td { overflow-wrap: anywhere; }
/* 數字與表頭維持一行，只讓名稱欄斷開 */
.pulse-asn td.n, .pulse-asn th { white-space: nowrap; overflow-wrap: normal; }
.pulse-asn .asn-m { display: none; }
/* 手機上 ASN 欄併進名稱欄（.m-asn），字與間距縮小，留給名稱與數字 */
@media (max-width: 560px) {
  .pulse-asn { font-size: .78rem; }
  .prose .pulse-asn th, .prose .pulse-asn td { padding-left: .3rem; padding-right: .3rem; }
  .pulse-asn.m-asn th:first-child, .pulse-asn.m-asn td:first-child { display: none; }
  .pulse-asn.m-asn .asn-m { display: block; font-size: .72rem; }
}
.pulse .bar { display: block; height: 4px; margin-top: .3rem; border-radius: 2px; background: var(--c-hair); }
.pulse .bar span { display: block; height: 100%; border-radius: 2px; background: var(--pc2); }
.pulse-more { margin: .5rem 0 0; font-size: .8rem; color: var(--c-muted); }

/* 版本與標記：橫向長條 */
.pulse-cols { display: grid; gap: 0 .75rem; }
@media (min-width: 640px) { .pulse-cols { grid-template-columns: 1fr 1fr; } }
.pulse-bars { list-style: none; margin: 0; padding: 0; }
.pulse-bars li { display: grid; grid-template-columns: 5.5rem 1fr 2.5rem; align-items: center; gap: .5rem; margin: .3rem 0; font-size: .85rem; }
.pulse-bars .l { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pulse-bars .bar { height: .6rem; margin: 0; }
.pulse-bars .n { text-align: right; font-variant-numeric: tabular-nums; }
/* 台灣的 Tor 使用者數的地區比較，台灣那一列加粗、用主色 */
.tu-bars li { grid-template-columns: 4.5rem 1fr 3.2rem; }
:lang(en) .tu-bars li { grid-template-columns: 8.5rem 1fr 3.2rem; }
.tu-bars li.me .l, .tu-bars li.me .n { font-weight: 700; color: var(--c-strong); }
.tu-bars li.me .bar span { background: var(--pc1); }
/* Tor 標記的說明放在名稱下面，橫跨整列 */
.pulse-flags li { row-gap: .1rem; }
.pulse-flags .d { grid-column: 1 / -1; font-size: .72rem; line-height: 1.4; color: var(--c-muted); }

/* 各地區比較：每個地區一張小卡，數字加走勢 */
/* 觀測地區地圖：灰色底圖，觀測地區用主色、參照地區用淺色，目前這一頁的地區加深 */
.rmap-fig { margin: 0 0 1rem; }
.rmap { display: block; width: 100%; height: auto; border: 1px solid var(--c-hair); border-radius: var(--radius); background: var(--c-bg); }
.rmap path, .rmap circle { stroke: var(--c-bg); stroke-width: .6; }
.rmap .rm-land { fill: color-mix(in srgb, var(--c-muted) 16%, var(--c-bg)); }
.rmap .rm-ref { fill: color-mix(in srgb, var(--c-accent) 30%, var(--c-bg)); }
.rmap .rm-obs { fill: var(--c-accent); }
.rmap a:hover .rm-obs, .rmap a:focus .rm-obs { fill: var(--c-strong); }
.rmap .rm-cur { fill: var(--c-strong); }
.rmap .rm-later { fill: color-mix(in srgb, var(--c-accent) 40%, var(--c-bg)); }
.rmap a:hover .rm-later, .rmap a:focus .rm-later { fill: color-mix(in srgb, var(--c-accent) 70%, var(--c-bg)); }
.rmap .rm-cur, .rmap circle.rm-obs { stroke: var(--c-bg); }
.rmap circle.rm-obs { stroke-width: 1.2; }
.rmap-fig figcaption { margin-top: .4rem; font-size: .8rem; line-height: 1.6; color: var(--c-muted); }
.rmap-fig .lg { display: flex; flex-wrap: wrap; gap: .25rem 1rem; margin-bottom: .2rem; color: var(--c-strong); }
.rm-sw-obs { background: var(--c-accent); }
.rm-sw-cur { background: var(--c-strong); }
.rm-sw-later { background: color-mix(in srgb, var(--c-accent) 40%, var(--c-bg)); }
.rm-sw-ref { background: color-mix(in srgb, var(--c-accent) 30%, var(--c-bg)); }
/* 分級上色（Tor 中繼節點觀測、OONI 觀測涵蓋率）：觀測地區依數值分五級，把最深的 cyan 跟底色
   等比例混合，級距之間的深淺差才平均。數值越大越深，深色模式反過來越大越亮。目前這一頁的地區改用外框標出，參照地區用斜線 */
.rm-q0 { --rmq: color-mix(in srgb, var(--c-muted) 34%, var(--c-bg)); }
.rm-q1 { --rmq: color-mix(in oklab, var(--pc1) 26%, var(--c-bg)); }
.rm-q2 { --rmq: color-mix(in oklab, var(--pc1) 44%, var(--c-bg)); }
.rm-q3 { --rmq: color-mix(in oklab, var(--pc1) 62%, var(--c-bg)); }
.rm-q4 { --rmq: color-mix(in oklab, var(--pc1) 80%, var(--c-bg)); }
.rm-q5 { --rmq: var(--pc1); }
.rmap.rm-choro .rm-obs { fill: var(--rmq); }
.rmap.rm-choro .rm-cur { stroke: var(--c-strong); stroke-width: 2; }
.rmap.rm-choro circle.rm-cur { stroke-width: 2.4; }
.rmap.rm-choro a:hover .rm-obs, .rmap.rm-choro a:focus .rm-obs { fill: var(--rmq); stroke: var(--c-strong); stroke-width: 1.4; }
.rmap.rm-choro .rm-ref { fill: url(#rm-hatch); }
.rmap .rm-hatch-bg { fill: color-mix(in srgb, var(--c-muted) 16%, var(--c-bg)); stroke: none; }
.rmap .rm-hatch { stroke: color-mix(in srgb, var(--c-muted) 60%, var(--c-bg)); stroke-width: 1.4; }
.rm-steps { align-items: center; }
.rm-steps .t { color: var(--c-muted); }
.rm-steps .sw { background: var(--rmq); }
.rm-sw-out { box-sizing: border-box; border: 2px solid var(--c-strong); background: color-mix(in oklab, var(--pc1) 62%, var(--c-bg)); }
.rm-choro ~ figcaption .rm-sw-ref {
  background: repeating-linear-gradient(45deg, color-mix(in srgb, var(--c-muted) 60%, var(--c-bg)) 0 1.5px, color-mix(in srgb, var(--c-muted) 16%, var(--c-bg)) 1.5px 4px);
}
/* 各地區的使用與貢獻：目前所在的地區整列加粗 */
.pulse-cmp { margin-bottom: 1.5rem; }
.pulse-cmp tr.cur td { font-weight: 700; }
/* 參照地區前面加一列小標 */
.pulse-cmp tr.ref th { padding-top: .9rem; font-size: .75rem; color: var(--c-muted); font-weight: 400; }
/* 英文的地區名較長（South Korea、United States），手機上讓名稱斷行，數字欄才放得下 */
.prose .pulse-asn.pulse-cmp td:first-child, .prose .pulse-cmp td:first-child a { white-space: normal; overflow-wrap: normal; }
/* 通訊 App 的比較表：異常比例過半的格子標成重點色，參照地區前面加一列小標 */
/* 異常比例過半通常代表當地封鎖了那個 App，用警告紅 */
.asncov-appcmp td.hi { font-weight: 700; color: var(--danger); }
.asncov-apps .bar span { background: var(--oc-anomaly); }
.asncov-appcmp tr.ref th { padding-top: .9rem; font-size: .75rem; color: var(--c-muted); font-weight: 400; }
/* 欄位多的表格在窄螢幕上左右捲動，不撐破外框 */
.pulse-scroll { overflow-x: auto; margin-bottom: 1.5rem; }
.pulse-scroll .pulse-cmp { margin-bottom: 0; }
@media (max-width: 420px) {
  .asncov-appcmp { font-size: .72rem; }
  .prose .asncov-appcmp th, .prose .asncov-appcmp td { padding-left: .2rem; padding-right: .2rem; }
  .asncov-appcmp thead th { font-size: .66rem; }
}
.pulse-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .5rem; margin-bottom: 1.5rem; }
@media (min-width: 640px) { .pulse-grid { grid-template-columns: repeat(5, 1fr); } }
.pulse-country { display: block; padding: .5rem .6rem .4rem; border: 1px solid var(--c-hair); border-radius: var(--radius); color: inherit; text-decoration: none; }
.pulse-country:hover { border-color: var(--c-line); }
.pulse-country[aria-current] { border-color: var(--c-line); background: var(--c-fill); }
.pulse-country .name { display: block; font-size: .8rem; color: var(--c-muted); }
.pulse-country .v { display: block; font-size: 1.25rem; font-weight: 700; color: var(--c-strong); font-variant-numeric: tabular-nums; }
.pulse-country .chg { margin-left: .35rem; font-size: .7rem; font-weight: 400; color: var(--c-muted); }
/* 各地區比較的小倍數圖：所有地區共用同一個刻度，刻度寫在格子下方 */
.pc-multi { display: block; width: 100%; height: 36px; margin-top: .3rem; overflow: visible; }
.pc-multi polygon { fill: color-mix(in srgb, var(--pc3) 28%, transparent); }
.pc-multi polyline { fill: none; stroke: var(--pc2); stroke-width: 1.6; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.pc-multi .pc-base { stroke: var(--c-muted); stroke-width: 1; stroke-dasharray: 3 3; opacity: .7; vector-effect: non-scaling-stroke; }
.pulse-grid + .pulse-more { margin: -1rem 0 1.5rem; }

/* OONI 觀測涵蓋率（/projects/asn-coverage/）沿用上面的 .pulse 樣式，只補兩種版面：
   使用者占比與測量占比上下並排的兩條長條，以及占比清單裡的網路名稱 */
.asncov-net .bar { height: 4px; margin-top: .25rem; }
.asncov-net .bar + .bar { margin-top: 2px; }
.asncov-net .bar span { background: var(--pcc); }
.asncov-net tr.gap td { background: var(--c-fill); }
.asncov-net .asn-m { display: none; }
/* 手機上五欄放不下：ASN 併進名稱欄，天數欄收起來 */
@media (max-width: 560px) {
  .asncov-net th:first-child, .asncov-net td:first-child, .asncov-net th:last-child, .asncov-net td:last-child { display: none; }
  .asncov-net .asn-m { display: block; font-size: .75rem; }
}
.asncov-share li { grid-template-columns: 5.5rem 1fr 3rem; }
.asncov-apps li { grid-template-columns: 5.5rem 1fr 3.2rem; }
.asncov-share .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--c-muted); }

/* 觀測季報（/projects/reports/）沿用 .pulse 的樣式，補上季初季末的流向條與各地區排名。
   季報的圖表穿插在本文之間，.prose 的清單縮排不套到圖表裡的清單 */
.prose .pulse ul { padding-left: 0; margin: 0; }
.rq-flow { display: grid; grid-template-columns: 4.5rem 1fr; align-items: center; gap: .45rem .6rem; font-size: .85rem; }
.rq-bar { display: flex; gap: 2px; height: 1.4rem; }
.rq-bar span { display: flex; align-items: center; justify-content: center; min-width: 1.4rem; border-radius: 3px; background: var(--pcc); color: #fff; font-size: .75rem; font-variant-numeric: tabular-nums; }
.rq-bar .pc-s4, .rq-bar .pc-s3 { color: var(--c-strong); }
.rq-rank li { grid-template-columns: 4.5rem 1fr 2.8rem 6.5rem; }
.pulse-asn .kind { display: block; font-size: .72rem; color: var(--c-muted); }
.rq-types td:first-child { white-space: normal; }
/* 英文的四個欄名都是不能斷開的單字，320px 寬時再縮一點 */
@media (max-width: 359px) { .pulse-asn.rq-types { font-size: .7rem; } .prose .pulse-asn.rq-types th, .prose .pulse-asn.rq-types td { padding-left: .2rem; padding-right: .2rem; } }
.rq-types .bar { height: 4px; margin-top: .25rem; }
.rq-types .bar + .bar { margin-top: 2px; }
.rq-types .bar span { background: var(--pcc); }
.rq-rank .t { font-size: .75rem; color: var(--c-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rq-rank li.me .l, .rq-rank li.me .n { font-weight: 700; color: var(--c-strong); }
.rq-rank li.me .bar span { background: var(--pc1); }
@media (max-width: 560px) { .rq-rank li { grid-template-columns: 4rem 1fr 2.6rem; } .rq-rank .t { display: none; } }
/* 英文的地區名比較長（Netherlands、United States），名稱欄放寬 */
:lang(en) .rq-rank li { grid-template-columns: 7rem 1fr 2.8rem 6.5rem; }
@media (max-width: 560px) { :lang(en) .rq-rank li { grid-template-columns: 6.2rem 1fr 2.6rem; } }

/* 404 頁三種語言疊在一起，用細線分開 */
.not-found + .not-found { border-top: 1px solid var(--c-hair); margin-top: 1.5rem; }
.not-found h1 { font-size: 1.4rem; }

/* 頁尾：整列淡底色，頁面在哪裡結束一眼看得出來。底色用 box-shadow 往兩側延伸到視窗邊緣，
   clip-path 切掉上下，不會撐出橫向捲軸 */
footer { margin-top: 3.5rem; padding: 1.5rem 0 2.5rem; background: var(--c-surface); box-shadow: 0 0 0 100vmax var(--c-surface); clip-path: inset(0 -100vmax); font-size: .85rem; color: var(--c-muted); line-height: 1.9; }
footer .cols { display: grid; gap: .1rem 1.5rem; grid-template-columns: 1fr; }
@media (min-width: 520px) { footer .cols { grid-template-columns: 1fr 1fr; } }
@media (min-width: 900px) { footer .cols { grid-template-columns: repeat(3, auto); justify-content: start; gap: .1rem 3rem; } }
footer .cols a { color: var(--c-muted); white-space: nowrap; }
/* 頁尾每一項都是圖示加文字，文件與新聞導讀用專案卡片的同一個圖示 */
footer .i { margin-right: .3rem; }
footer p { margin: .5rem 0 0; }
footer .onion { word-break: break-all; font-size: .75rem; margin-top: .75rem; }
footer .license { font-size: .75rem; }

/* 觀測圖表的出場動畫：長條從基線長出來，折線與面積由左往右畫出，地圖的分級色淡入。
   純 CSS，沒有 JavaScript 也會動，結束之後跟靜態的圖一樣。系統設定要求減少動態效果時不播放 */
@media (prefers-reduced-motion: no-preference) {
  .pc-bars { transform-box: fill-box; transform-origin: 50% 100%; animation: pc-grow .7s cubic-bezier(.2, .7, .3, 1) both; }
  .pc-trace, .pc-multi .pc-marks, .pulse-share { animation: pc-wipe 1s ease-out both; }
  .pulse-country .pc-marks { animation-delay: calc(var(--i, 0) * 60ms); }
  .pulse .bar span { transform-origin: 0 50%; animation: pc-growx .8s cubic-bezier(.2, .7, .3, 1) both; }
  .rmap.rm-choro .rm-obs { animation: rm-in .9s ease-out both; }
}
@keyframes pc-grow { from { transform: scaleY(0); } }
@keyframes pc-growx { from { transform: scaleX(0); } }
@keyframes pc-wipe { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes rm-in { from { opacity: 0; } }

/* 示意圖（diagrams.py）：關於頁的社群全貌、關注地區與時間軸。SVG 的畫布照手機寬度設計，
   桌機用 max-width 限制放大的倍數，圖上的字才跟內文差不多大 */
/* 內文的 figure 左右邊距是 0（見上方 .prose figure），示意圖要寫到同樣的權重才能置中 */
.prose figure.dg-fig, .dg-fig { margin: 1.25rem auto 1.5rem; }
.dg-fig figcaption { margin-top: .4rem; font-size: .8rem; line-height: 1.6; color: var(--c-muted); text-align: center; }
.dg-fig figcaption .lg { justify-content: center; }
.dg-fig-community { max-width: 30rem; }
.dg { display: block; width: 100%; height: auto; overflow: visible; font-family: var(--font); }
.dg-link { stroke: var(--topic); stroke-width: 1.5; stroke-dasharray: 4 4; opacity: .7; }
.dg-hub { fill: var(--c-fill); stroke: var(--c-border); stroke-width: 1; }
.dg-hub-t { fill: var(--c-strong); font-size: 14px; font-weight: 700; }
.dg-dot { fill: var(--topic); }
.dg-ic { fill: var(--c-bg); }
.dg-name { fill: var(--c-strong); font-size: 16px; font-weight: 700; }
.dg-item { fill: var(--c-muted); font-size: 13.5px; }
.dg-node:hover .dg-name, .dg-node:focus .dg-name { fill: var(--topic); text-decoration: underline; }
.dg-node:hover .dg-dot, .dg-node:focus .dg-dot { stroke: var(--c-strong); stroke-width: 2; }
.rmap .rm-first { fill: var(--c-strong); }
.rmap .rm-second { fill: color-mix(in srgb, var(--c-accent) 55%, var(--c-bg)); }
.rm-sw-first { background: var(--c-strong); }
.rm-sw-second { background: color-mix(in srgb, var(--c-accent) 55%, var(--c-bg)); }
/* 關注地區的地圖跟內文同寬。畫布裁切之後約 580 單位寬，桌機放大到 1.1 倍多、手機只剩一半，
   地名的字級用畫布的單位，依螢幕寬度分開設，實際大小都在 11 到 15px 之間 */
.dg-label { fill: var(--c-text); font-size: 21px; paint-order: stroke; stroke: var(--c-bg); stroke-width: 5px; stroke-linejoin: round; }
@media (min-width: 640px) { .dg-label { font-size: 13px; stroke-width: 3.5px; } }
.dg-label-first { fill: var(--c-strong); font-weight: 700; }
/* 時間軸：左邊一條線，每一筆一個圓點，顏色跟社群動態的標籤同一套 */
ol.tl { list-style: none; margin: 1.25rem 0 1.5rem; padding: 0; }
.tl li { position: relative; display: grid; grid-template-columns: 4.6rem 1fr; gap: .1rem .75rem; margin: 0 0 0 .4rem; padding: 0 0 1rem 1.25rem; border-left: 2px solid var(--c-hair); }
.tl li:last-child { border-left-color: transparent; }
.tl li::before { content: ""; position: absolute; left: calc(-.4rem - 1px); top: .35rem; width: .8rem; height: .8rem; border-radius: 50%; background: var(--dot, var(--c-accent)); box-shadow: 0 0 0 3px var(--c-bg); }
.tl .tl-origin { --dot: var(--c-strong); }
.tl .tl-new { --dot: var(--ut-new); }
.tl .tl-event { --dot: var(--ut-event); }
.tl .tl-update { --dot: var(--ut-update); }
.tl-when { font-size: .85rem; color: var(--c-muted); font-variant-numeric: tabular-nums; padding-top: .05rem; }
.tl-t { display: block; font-weight: 700; }
.tl-d { display: block; color: var(--c-muted); font-size: .9rem; line-height: 1.6; }
@media (max-width: 560px) {
  .tl li { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: no-preference) {
  .dg-node { animation: rm-in .6s ease-out both; }
  .dg-node:nth-of-type(2) { animation-delay: .1s; }
  .dg-node:nth-of-type(3) { animation-delay: .2s; }
  .dg-node:nth-of-type(4) { animation-delay: .3s; }
  .dg-link { animation: pc-wipe-dash .8s ease-out both; }
}
@keyframes pc-wipe-dash { from { opacity: 0; } }

/* 步驟流程（ol.flow）：編號圓點用一條細線串起來，每一步寫名稱、說明與結果（.out），
   最後一步（.ok）用實心圓點。手機上條件與結果分兩行排在說明下方，桌機靠右對齊並加上箭頭，一眼看出每一步對應的值。
   第一個用在 OONI 的封鎖判定方式，取代文件站搬來的 SVG 流程圖 */
.prose ol.flow { list-style: none; margin: 1.25rem 0 1rem; padding: 0; }
.flow > li { position: relative; display: grid; grid-template-columns: 2rem 1fr; gap: .75rem; margin: 0; padding: 0 0 1.1rem; }
.flow > li:not(:last-child)::after { content: ""; position: absolute; left: calc(1rem - 1px); top: 2rem; bottom: 0; width: 2px; background: var(--c-hair); }
.flow .n { width: 2rem; height: 2rem; border-radius: 50%; border: 1.5px solid var(--c-border-strong); color: var(--c-strong); display: grid; place-items: center; font-weight: 700; font-size: .9rem; background: var(--c-bg); }
.flow .ok .n { background: var(--c-solid); border-color: var(--c-solid); color: #fff; }
.flow .b { display: flex; flex-direction: column; gap: .15rem; padding-top: .2rem; }
.flow .d { color: var(--c-muted); font-size: .9rem; line-height: 1.6; }
.flow .out { display: flex; flex-direction: column; align-items: flex-start; gap: .1rem; margin-top: .2rem; font-size: .9rem; }
.flow .if { color: var(--c-muted); }
@media (min-width: 640px) {
  .flow .b { display: grid; grid-template-columns: 1fr auto; column-gap: 1.25rem; }
  .flow .b > b, .flow .d { grid-column: 1; }
  .flow .out { grid-column: 2; grid-row: 1 / 3; align-items: flex-end; margin: 0; text-align: right; }
  .flow .if::after { content: " →"; }
}

/* ==========================================================================
   版面：兩種頁型

   - 文件頁（文章、指南、活動、動態、觀測資料、季報）：左邊內容欄，右邊固定的「本頁內容」。
     全站多半是一兩千到八千字、八到十四個小節的長文，側欄讓讀者看得到整頁的結構。
     內容欄的寬度就是閱讀寬度，段落、標題的細線、表格與圖表都填滿所在的欄，不另外限制
     文字的寬度，換行的位置才會對齊版面上的邊界
   - 目錄頁（首頁與各區入口）：整個外框排成格狀
   手機一律單欄，「本頁內容」收在標題下方。判斷頁型與產生目錄的是 templates/_doc.html.j2
   與 build.py 的 toc()。目前讀到哪一節不另外標示，那需要 JavaScript
   ========================================================================== */
@media (min-width: 1080px) {
  .doc { display: grid; grid-template-columns: minmax(0, 1fr) var(--toc-w); gap: var(--toc-gap); align-items: start; }
  .doc:not(.has-toc) .doc-main { grid-column: 1; }
  .toc { position: sticky; top: 1.5rem; margin-top: 2.5rem; max-height: calc(100vh - 3rem); overflow-y: auto; padding-left: 1rem; border-left: 1px solid var(--c-hair); font-size: .85rem; line-height: 1.5; }
  .toc-m { display: none; }
}
@media (max-width: 1079px) { .toc { display: none; } }
.toc-h { margin: 0 0 .6rem; color: var(--c-muted); font-size: .8rem; font-weight: 700; letter-spacing: .05em; }
.toc ol { list-style: none; margin: 0; padding: 0; }
.toc ol + .toc-h { margin-top: 1.5rem; }
.toc li { margin: 0 0 .55rem; }
.toc a { color: var(--c-muted); text-decoration: none; }
.toc a:hover { color: var(--c-link); text-decoration: underline; }
/* 社群動態的側欄在目錄下面接其他三篇動態 */
.toc-posts time { display: block; font-size: .75rem; font-variant-numeric: tabular-nums; }
.toc-m { margin: 1rem 0 1.25rem; padding: .55rem .9rem; border: 1px solid var(--c-hair); border-radius: var(--radius); font-size: .9rem; }
.toc-m summary { cursor: pointer; color: var(--c-strong); font-weight: 700; }
.toc-m ol { margin: .5rem 0 .2rem; padding-left: 1.3rem; }
.toc-m li { margin: .2rem 0; }

/* 目錄頁與首頁的列表：每格至少 17rem，外框寬度下排成三欄。三大主題這類三項的列表剛好
   一列，項目多的列表依序往下排 */
@media (min-width: 900px) {
  :is(.index, main:has(> .hero)) .prose > .rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: 0 1.5rem; }
  :is(.index, main:has(> .hero)) .prose > .rows li { border-top: 1px solid var(--c-hair); }
}
