/* ============================================================
   解碼 BL／百合的情感經濟 — Switch-Lit
   Inked editorial grid on cream paper

   字體：標題＝源泉圓體 GenSenRounded2 TC（SIL OFL，已 subset 成本頁用字）
        內文＝Noto Sans TC
   ============================================================ */

@font-face {
  font-family: 'GenSenRounded2 TC';
  src: url('../fonts/GenSenRounded2TC-B.subset.woff2?v=2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'GenSenRounded2 TC';
  src: url('../fonts/GenSenRounded2TC-H.subset.woff2?v=2') format('woff2');
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Colors — 語意命名
     bl  紫  BL 數據
     gl  橘  百合數據
     hl  黃  重點／強調（非 BL 也非百合的通用高亮）
     aux 灰  輔助（雙棲、三次元、次要標籤）
     mute 淺灰  刻意不強調的項目（其他／未透露、無法估計） */
  --cream: #f9f9f9;
  --ink: #000000;

  /* --ink 是畫布上的文字與所有結構線；「壓在油墨色塊上的字」獨立拆出一個名字，
     因為它永遠得是黑的，不會跟著 --ink 一起變。 */
  --on-ink: #000000;   /* 壓在 BL 紫／百合橘／重點黃／淺灰色塊上的字，恆黑 */
  --on-aux: #f9f9f9;   /* 壓在輔助灰 --aux 上的字，恆近白 */

  /* 重點黃拿來「當記號畫在紙上」時的可讀值 —— 跟它當色塊填色時是兩回事。
     純黃 #fac55d 對奶油紙只有 1.5:1，畫在上面等於看不見，所以要壓成深色調
     （與 .quote--paper 署名同一個值，對奶油紙 ≥6.4:1）。 */
  --hl-mark: #6b5a33;

  --bl: #7a86f1;
  --gl: #ed8959;
  --hl: #fac55d;
  --aux: #64748b;
  --mute: #ccd3de;
  --paper-shadow: #eef0f4;
  --mist: #d7dce5;
  --paper-texture: var(--cream) url('../img/paper.png') repeat;
  /* 另一種紙：整段換印在偏黃的厚紙上，用來標出「這一段不一樣」 */
  --kraft: #ece5d6;

  /* Riso ink 色塊 — 純色填充，不做漸層淡出，不疊任何混合模式。 */
  --bl-ink: var(--bl);
  --gl-ink: var(--gl);
  --hl-ink: var(--hl);
  --mute-ink: var(--mute);

  /* Type — 兩支字體：圓體標題 + Noto Sans TC 內文 */
  --font-sans: "Noto Sans TC", "PingFang TC", "Hiragino Sans CNS", "Microsoft JhengHei",
    ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-round: "GenSenRounded2 TC", "GenSenRounded TC", "源泉圓體", "GenJyuuGothic",
    "jf-openhuninn", "Noto Sans TC", "PingFang TC", sans-serif;

  /* Layout */
  --page: 1200px;
  --gutter: 28px;
  --nav-h: 64px;
  --hair: 1px solid var(--ink);
  --hair-soft: 1px solid rgba(0, 0, 0, 0.14);

  /* 閱讀欄 — 內文與引言都待在這個寬度，讀者的視線只有一條軸線。
     只有「資料」（圖表、並排比較、卡片列）才有資格撐滿版面，
     所以每一次變寬都在告訴讀者：證據來了。

     680px 在桌機解出來只有 36 個全形字一行 —— 中文長文的舒適區是
     38～42 字，36 已經在下緣，加上行高 2、字距 0.04em，整段被拉成
     一條細帶子；更糟的是章名的分隔線是 --page（1200px），內文只有
     680，兩者差 520px，讀者看到的不是「刻意收窄的閱讀欄」而是
     「沒對齊的窄字」。760px 解出來約 40.6 字，落在舒適區內，
     跟 1200px 的資料帶仍差 440px —— 收窄的語意還在，只是不再像失誤。
     字級維持 18px：試過 19px，字身變重、頁面壓迫感反而上升，
     「窄」的問題出在欄寬與對比，不在字太小。 */
  --read: 760px;

  /* Vertical rhythm — 五層節奏，由密到疏：
     tight     圖說貼著它的圖表（同一個東西）
     para      同一串思緒的段落之間
     component 一般元件之間
     evidence  文字轉進資料、或從資料回到文字（換一種說話方式）
     block     換一個概念
     section   換一章
     block／section 同時吃 vw 與 vh：螢幕越高，概念之間的停頓越長，
     讀者一次就更容易只沈浸在一個概念裡；矮螢幕則不浪費半個畫面。

     這一階一階要拉得開、但也要拉得勻 —— 讀者是靠「這個空隙比上一個大多少」
     在辨認語意距離的，所以每一階對前一階的倍率必須接近，大約 1.6 倍。
     舊值在 1440×900 解出來是 16／26／44／70／180／212，倍率
     1.63、1.69、1.59、2.57、1.18 —— 最後兩階壞掉了：
     evidence 跳到 block 一次拉開 2.57 倍（其餘都只有 1.6），而 block 跟 section
     只差 1.18 倍，「換一個概念」和「換一章」在畫面上根本分不出來。
     現在把 block 拉回階梯上（1.84 倍），section 因此重新比 block 明顯，
     倍率變成 1.63、1.54、1.53、1.84、1.53 —— 語意層級沒有變少，只是不再空轉。

     evidence 的下限（手機）不跟著等比縮：手機上 component 已經是 30px，
     evidence 若壓到 38px，兩者只差 1.27 倍，「文字轉進資料」那個轉折就看不出來了。
     42px 把差距拉回 1.4 倍 —— 這一階承載的是 DESIGN.md 說的「證據來了」，
     是全套節奏裡最不能被壓扁的一階。 */
  --space-xs: 14px;
  --space-sm: 22px;
  --space-tight: 16px;
  --space-para: 26px;
  --space-component: clamp(30px, 3.2vw, 40px);
  --space-evidence: clamp(42px, 2.6vw + 2.6vh, 64px);
  --space-block: clamp(76px, 3.4vw + 7vh, 130px);
  --space-section: clamp(110px, 5vw + 11vh, 200px);

  /* Radius */
  --r-card: 12px;
  --r-btn: 6px;
  --r-pill: 24px;
  --r-sm: 3px;

  color-scheme: light;
}

/* ---------- reset ---------- */
*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper-texture);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.85;
  letter-spacing: 0.04em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
ul, ol { margin: 0; padding: 0; list-style: none; }
h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
button { font: inherit; color: inherit; }

::selection { background: var(--hl); color: var(--on-ink); }

/* ---------- shared ---------- */
.wrap {
  width: 100%;
  max-width: var(--page);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.measure {
  width: 100%;
  max-width: var(--read);
  margin-left: auto;
  margin-right: auto;
  font-size: clamp(16px, 2vw, 18px);
  line-height: 2;
}

.tag {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1;
  text-transform: uppercase;
  padding: 7px 9px;
  border: var(--hair);
  border-radius: var(--r-btn);
  background: transparent;
}
.tag--bl { background: var(--bl-ink); color: var(--on-ink); }
.tag--gl { background: var(--gl-ink); color: var(--on-ink); }
.tag--hl { background: var(--hl-ink); color: var(--on-ink); }
.tag--aux { background: var(--aux); color: var(--on-aux); }
/* 實心黑標籤：留給「就是現在這一個」的狀態（系列預告的 NOW READING）。
   壓在上面的字用 --cream 而不是 --on-aux，換紙時才會跟著翻。 */
.tag--ink { background: var(--ink); color: var(--cream); }


/* ============================================================
   NAV
   ============================================================ */
.progress {
  position: fixed;
  inset: 0 auto auto 0;
  height: 3px;
  width: 0;
  background: var(--ink);
  z-index: 60;
}

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--paper-texture);
  border-bottom: var(--hair);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  height: var(--nav-h);
  max-width: var(--page);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.nav__mark {
  display: flex;
  align-items: baseline;
  gap: 8px;
  text-decoration: none;
  font-weight: 700;
  font-size: 17px;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
.nav__mark i {
  display: inline-block;
  width: 11px;
  height: 11px;
  background: var(--hl);
  border: var(--hair);
  font-style: normal;
}
/* 站名有長短兩版，同一時間只顯示一版：
   寬螢幕用全名，窄螢幕換成短版，把省下來的寬度讓給換紙鈕與目錄鈕。 */
.nav__mark__brief { display: none; }

.nav__links {
  display: flex;
  align-items: center;
  gap: 23px;
}
.nav__links a {
  text-decoration: none;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.06em;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  white-space: nowrap;
}
.nav__links a:hover { border-bottom-color: var(--ink); }
.nav__links a[aria-current="true"] {
  border-bottom-color: var(--ink);
  font-weight: 700;
}
.nav__links a em {
  font-style: normal;
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.14em;
  margin-right: 6px;
  opacity: 0.7;
}

.nav__toggle {
  display: none;
  align-items: center;
  gap: 8px;
  background: transparent;
  border: var(--hair);
  border-radius: var(--r-pill);
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.14em;
  cursor: pointer;
}

/* 導覽列右側的一組控制項，讓 .nav__inner 的 space-between 仍然只分成左右兩堆 */
.nav__actions {
  display: flex;
  align-items: center;
  gap: 20px;
}

.nav__toggle:hover { background: var(--paper-shadow); }

/* ---------- 下載完整報告（實際上是跳到 #pdf-preview 的錨點） ----------
   跟 CTA 按鈕（.btn-cta）同一個 --hl 底色語意：全站通用的強調色，不分 BL／百合。 */
.nav__dl {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: var(--hair);
  border-radius: var(--r-pill);
  background: var(--hl);
  color: var(--on-ink);
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-decoration: none;
  white-space: nowrap;
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.nav__dl:hover { transform: translateY(-1px); }
.nav__dl:active { transform: translateY(0); }
.nav__dl:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.nav__dl svg { display: block; width: 15px; height: 15px; }

/* ============================================================
   HERO
   ============================================================ */
.hero {
  padding: clamp(32px, 5vw, 64px) 0 clamp(36px, 5vw, 56px);
}

.hero__top {
  display: flex;
  /* 文字與插圖靠同一條底線收尾 —— byline 與插圖的腳落在一起，
     下面 strip 的分隔線就成為兩者共同的地面。用 center 的話文字會卡在
     插圖的中間高度，兩塊沒有任何一條共同的邊，看起來各自漂浮。 */
  align-items: end;
  gap: clamp(28px, 5vw, 64px);
}
/* 500 + 580 + 64（gap）= 1144，剛好是 --page 扣掉左右 gutter，
   在最寬的情況下兩欄填滿、中間不會留下沒人認領的空隙。
   分法不是對半：新的插圖去掉了四周透明留白，畫面是滿的，
   多給它 40px 換文字欄讓 40px —— 文字欄最寬的是 byline 那三段（473px），
   500 還放得下同一行，所以這 40px 是純賺的。
   插圖 580 寬對應 430 高，底線對齊後左欄標題上方的空白就是
  「插圖高 - 文字高」，插圖越高那塊空白越大。 */
.hero__text { flex: 1 1 400px; min-width: 0; max-width: 500px; }
.hero__art {
  flex: 1 1 560px;
  max-width: 580px;
}
.hero__art img {
  display: block;
  width: 100%;
  height: auto;
}

/* ---- 分層插圖：漂浮 ＋ 捲動視差 ＋ 可拖曳 ----
   .hero-art 是那張坐標紙：長寬比鎖回原稿裁切框（1576×1146），
   七層才有一個共同的百分比座標可以站。它自己沒有內容撐高度，
   所以高度只能由 aspect-ratio 來給，圖片載入前後版面不會跳。
   物件會走出框外（漂浮 --amp 最多 16px、拖曳最多 44px），這裡不能 overflow:hidden，
   不然拖到邊界的紙片會被切一刀。 */
.hero-art {
  position: relative;
  width: 100%;
  aspect-ratio: 1576 / 1146;
}
.hero-art__layer {
  position: absolute;
  left: var(--l);
  top: var(--t);
  width: var(--w);
  /* 視差量由 JS 每次捲動寫進 --shift（單位 px，已經乘過 --depth）。
     沒有 JS 時它是 0，七層就停在 full-view 的原位。 */
  transform: translate3d(0, var(--shift, 0px), 0);
  will-change: transform;
  /* 每層都是一個矩形，而圖是不規則的 —— 人物那層的矩形有一半是透明的，
     卻剛好蓋在立牌上面（DOM 在後面，滑鼠會被它接走）。
     所以層一律不吃指標事件，只有 grab 層自己收，
     否則會出現「看起來抓得到、其實抓不到」的物件。 */
  pointer-events: none;
}
.hero-art__grab,
.hero-art__float,
.hero-art__still {
  display: block;
  width: 100%;
  height: auto;
}

/* ---- 小物件：抓起來拖，放手彈回 ----
   拖曳量由 JS 寫進 --dx／--dy。沒有 JS 時這層就只是個 div，
   物件照樣在原位漂浮，只是抓不動。
   touch-action: pan-y —— 手機上垂直滑動一律交還給瀏覽器捲頁，
   絕對不能整塊 none：小物件散在插圖各處，把捲動吃掉會變成滑不動的死角。 */
.hero-art__grab {
  transform: translate3d(var(--dx, 0px), var(--dy, 0px), 0);
  pointer-events: auto;
  cursor: grab;
  touch-action: pan-y;
  -webkit-user-select: none;
  user-select: none;
}
.hero-art__grab.is-held { cursor: grabbing; }
/* 抓在手上的東西不該還在自己飄 —— 暫停（不是取消）動畫，
   放手後從停住的那一格接著飄，不會跳格。 */
.hero-art__grab.is-held .hero-art__float { animation-play-state: paused; }
/* 彈回：cubic-bezier 的第二個控制點超過 1，物件會衝過原位一點再收住，
   這一下過衝就是「彈」的手感；線性或 ease-out 只會像被拉回去。 */
.hero-art__grab.is-returning {
  transition: transform 0.62s cubic-bezier(0.22, 1.4, 0.36, 1);
}
/* 漂浮：只有上下 ＋ 一點點傾斜。
   每層的 --dur／--delay 都不一樣，而且 --delay 是負的 ——
   負延遲等於「動畫已經播了一段」，所以載入的第一幀七層就各在不同高度，
   不會出現七個物件一起從最低點齊步上升的那種機械感。 */
@keyframes hero-float {
  0%, 100% { transform: translate3d(0, calc(var(--amp) * var(--amp-scale, 1) * -0.5), 0) rotate(calc(var(--rot) * -0.5)); }
  50%      { transform: translate3d(0, calc(var(--amp) * var(--amp-scale, 1) * 0.5), 0) rotate(calc(var(--rot) * 0.5)); }
}
.hero-art__float {
  animation: hero-float var(--dur, 6s) ease-in-out var(--delay, 0s) infinite;
  will-change: transform;
}
/* 讀者說了不要動態就整組定住：漂浮與視差都停，構圖本身不變。
   拖曳留著 —— 那是讀者自己的手在動，不是畫面自己在動；
   但彈回改成短而不過衝的收尾，不要多那一下彈。 */
@media (prefers-reduced-motion: reduce) {
  .hero-art__float { animation: none; }
  .hero-art__layer { transform: none; }
  .hero-art__grab.is-returning { transition: transform 0.2s ease-out; }
}
/* 換成直向堆疊時，flex-basis 從「寬度」變成「高度」，
   400px／560px 會直接變成撐開的高度 —— 兩個都要放回 auto，讓高度回到內容決定。 */
@media (max-width: 860px) {
  /* 直向堆疊後主軸換成垂直，align-items 管的就變成「水平對齊」——
     再留著 end／center，文字整塊會依內容寬度被推開，跟導覽列站名、
     下面的 strip 錯開（768px 時量到差 168px）。stretch 才會撐滿欄寬。 */
  .hero__top { flex-direction: column; align-items: stretch; }
  .hero__text { flex-basis: auto; max-width: none; align-self: stretch; }
  .hero__art { flex-basis: auto; width: 100%; max-width: 560px; align-self: center; }
}
@media (max-width: 640px) {
  /* 手機直接撐滿欄寬 —— 插圖是這頁的個性，縮成 300px 只會變成貼紙。 */
  .hero__art { width: 100%; max-width: none; }
  /* --amp 是絕對 px，插圖在手機上小了一號，同樣的 16px 看起來就晃得多。
     幅度乘 0.72 收回來，飄的幅度跟插圖大小維持同一個比例。
     （--amp 寫在 img 的 inline style 上，蓋不掉，所以改成乘一個係數。） */
  .hero-art { --amp-scale: 0.72; }
}

.hero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: clamp(20px, 2.4vw, 26px);
}

.hero__title {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: clamp(34px, 5vw, 58px);
  line-height: 1.14;
  letter-spacing: 0.005em;
}
.hero__title .mark {
  /* 左右各撐開 0.12em 讓黃底包住第一筆與最後一筆，再用等量的負 margin
     抵銷掉，所以只有底色變寬、字的位置不動。 */
  padding-inline: 0.12em;
  margin-inline: -0.12em;
  background: linear-gradient(transparent 42%, var(--hl) 42%, var(--hl) 84%, transparent 84%);
}

.hero__sub {
  margin-top: clamp(20px, 2.6vw, 28px);
  font-family: var(--font-round);
  font-weight: 700;
  font-size: clamp(18px, 1.9vw, 22px);
  line-height: 1.7;
  letter-spacing: 0.03em;
  /* 整句 17 字，26ch 在 22px 只解出 337px、句子要 374px，
     於是「與消費」被推成孤零零一行。32ch 才放得下。 */
  max-width: 32ch;
}

.hero__byline {
  margin-top: 28px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  font-size: 13px;
  letter-spacing: 0.08em;
}
/* 三段加起來要 473px，手機欄寬只有 350px，橫排一定折成參差的兩行，
   而且斷在「海香草（MEI）」和「調查樣本」之間、中間留一塊空。
   直接直排反而齊，總高度也差不多。 */
@media (max-width: 640px) {
  /* line-height 收到 1.5：內文的 1.9 是給長段落的，三行短資訊沿用會鬆到
     看不出是同一組。收窄後三行的總高跟原本折成兩行差不多。 */
  .hero__byline { flex-direction: column; gap: 2px; line-height: 1.5; }
}
.hero__byline b { font-weight: 700; }

/* stat strip */
.strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: var(--hair);
  border-bottom: var(--hair);
  margin-top: clamp(40px, 6vw, 64px);
}
.strip__cell {
  padding: 22px 20px;
  border-left: var(--hair);
}
.strip__cell:first-child { border-left: 0; }
.strip__num {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: clamp(34px, 5vw, 54px);
  line-height: 1;
  letter-spacing: 0;
}
.strip__num small {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.06em;
  margin-left: 4px;
}
/* 前三格是人數、第四格是金額，四個數字等重並排時容易被讀成同一組。
   試過把「最高」加在數字前面，但那會讓第四個數字的起點比前三個往右退，
   整列數字失去共同的左緣 —— 代價比它解決的誤讀更明顯。
   最後靠單位本身區分：「萬元」跟「人」在 14px 就看得出不同類，
   「最高」留在標籤裡。 */
.strip__label {
  margin-top: 10px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.12em;
  line-height: 1.5;
}

/* ============================================================
   CHAPTERS
   ============================================================ */
.chapter { border-top: var(--hair); }
/* 導覽列會蓋住跳過去的位置，所以每個可被 #id 指到的東西都先讓開它的高度 ——
   #report 不是 <section>，得自己列一次。 */
section[id],
#report,
#pdf-preview { scroll-margin-top: calc(var(--nav-h) + 8px); }

.chapter__head {
  padding: clamp(44px, 7vw, 80px) var(--gutter) clamp(34px, 4.5vw, 50px);
  display: grid;
  grid-template-columns: 168px 1fr;
  gap: 0 40px;
  align-items: start;
}
.chapter__num {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: clamp(64px, 10vw, 112px);
  line-height: 0.9;
  letter-spacing: 0;
  grid-row: 1 / span 3;
}
.chapter__title {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: clamp(32px, 5.6vw, 54px);
  line-height: 1.28;
  letter-spacing: 0.02em;
}

.blocks {
  padding-bottom: var(--space-section);
  display: flex;
  flex-direction: column;
  gap: var(--space-block);
}

.block { display: flex; flex-direction: column; gap: var(--space-component); }

/* ---------- block 內的節奏：靠間距分組，不靠再多加框 ----------
   flex gap 給了統一的基準值，下面各條用 margin-top 往回加減，
   把「屬於同一件事」的拉近、「換一種說話方式」的推遠。 */

/* 引言屬於閱讀內容，跟內文共用同一條閱讀欄；
   撐滿版的權利留給圖表與並排比較這類資料。 */
.block > .quote,
.block > .quotes {
  width: 100%;
  max-width: var(--read);
  margin-left: auto;
  margin-right: auto;
}

/* 圖說貼著它說明的那張圖 */
.block > figure + .note {
  margin-top: calc(var(--space-tight) - var(--space-component));
}

/* 同一串思緒的連續段落靠得比元件更近 */
.block > .measure + .measure {
  margin-top: calc(var(--space-para) - var(--space-component));
}

/* 文字↔資料的轉換點，停頓比段落之間長 */
.block > .measure + :is(.chart, .quote, .quotes, .voice, .grid2, .grid3, .versus, .cite-row),
.block > :is(.chart, .quote, .quotes, .voice, .grid2, .grid3, .versus, .cite-row, .note) + .measure {
  margin-top: calc(var(--space-evidence) - var(--space-component));
}

/* 標題往下綁住自己的內容：上方留白由 block 間距負責，下方收緊 */
.block > .h3 + * {
  margin-top: calc(30px - var(--space-component));
}
/* 同一個 block 裡的次概念，上方要看得出換了個小節。
   字級要比內文大一階：.h4 本身的 18px 是給並排欄位與卡片小標用的，那裡的內文是 15px；
   放進 680px 閱讀欄之後，內文也是 18px，兩者同級——圓體的筆畫又比 Noto 輕，
   次標反而看起來比它要說明的段落還小。所以閱讀欄裡的 .h4 另外升一階。 */
.block > .h4 {
  margin-top: calc(var(--space-evidence) - var(--space-component));
  font-size: clamp(19px, 2.2vw, 22px);
}
/* 次標往下綁住自己的段落，理由同 .h3：上方的留白由 evidence 負責，下方收緊 */
.block > .h4 + * {
  margin-top: calc(24px - var(--space-component));
}

.h3 {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: clamp(21px, 3vw, 29px);
  line-height: 1.5;
  letter-spacing: 0.02em;
  padding-bottom: 18px;
  border-bottom: var(--hair);
  display: flex;
  gap: 12px;
  align-items: baseline;
}
/* 標題錨點 —— 每一章／每一節旁邊的「#」，讓讀者能分享到具體段落，
   搜尋引擎也可能把章節列成「跳至段落」的結果。id 命名是「第幾章-第幾節」
   （s2-3），跟 index.html 的小節註解編號一致，新增小節時照抄即可。
   平常淡到幾乎看不見，滑過或鍵盤 focus 時才顯色；位置一直留著，所以不會有
   hover 才推開版面的位移。 */
.anchor {
  flex: 0 0 auto;
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 0.62em;
  line-height: 1;
  color: var(--mute);
  text-decoration: none;
  opacity: 0;
  transition: opacity 0.18s ease, color 0.18s ease;
}
.anchor--h2 {
  margin-left: 0.4em;
  font-size: 0.4em;
  vertical-align: 0.35em;
}
.h3:hover .anchor,
.chapter__title:hover .anchor,
.works-sec__title:hover .anchor,
.anchor:focus-visible {
  opacity: 1;
}
.anchor:hover,
.anchor:focus-visible {
  color: var(--ink);
  text-decoration: underline;
}
.anchor:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}
/* 跳到錨點時別讓標題躲進固定導覽列底下 */
.h3[id],
.chapter,
.outro,
.works-sec {
  scroll-margin-top: calc(var(--nav-h) + 20px);
}

.h3::before {
  content: "";
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  background: var(--ink);
  transform: translateY(-2px);
}

.h4 {
  font-family: var(--font-round);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.04em;
  line-height: 1.6;
}

p + p { margin-top: 1.25em; }
p b, li b { font-weight: 700; }
p em {
  font-style: normal;
  background: linear-gradient(transparent 62%, var(--hl) 62%);
  padding: 0 2px;
}

.note {
  font-size: 13px;
  line-height: 1.7;
  letter-spacing: 0.06em;
  opacity: 0.7;
  padding-left: 14px;
  border-left: 2px solid var(--mist);
}

/* ---------- 名詞解釋：點開的邊欄註 ----------
   解釋在 HTML 裡預設是攤開的，main.js 的 initGlossary() 加上 .is-ready
   之後才收起來並接上按鈕 —— 腳本沒跑到時解釋照樣讀得到。
   寬螢幕時解釋走到閱讀欄外的左邊欄，正文一個字都不必移動；窄螢幕落回行下。
   要再加一組就複製整段 markup，換掉 id 與 aria-controls 即可。

   <p class="measure gloss">
     …那麼 <button type="button" class="gloss__term"
       aria-expanded="false" aria-controls="X">名詞</button> 呢？…
     <span class="gloss__body" id="X">解釋內容</span>
   </p> */
.gloss { position: relative; }
.gloss__term {
  position: relative;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 700;
  letter-spacing: inherit;
  color: inherit;
  vertical-align: baseline;
}
.gloss__term:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* 以下只在腳本接上之後才成立：沒有 JS 就不該出現可以按的樣子 */
.gloss.is-ready .gloss__term { cursor: pointer; }
.gloss.is-ready .gloss__term::after {
  content: "註";
  display: inline-block;
  width: 1.35em;
  height: 1.35em;
  margin-left: 0.25em;
  font-size: 0.62em;
  font-weight: 700;
  line-height: 1.35em;
  text-align: center;
  vertical-align: 0.7em;
  background: var(--ink);
  color: var(--cream);
}
.gloss.is-ready .gloss__term:hover::after,
.gloss.is-ready[data-open] .gloss__term::after { background: var(--gl); }

/* 觸控裝置把可點範圍撐到手指大小，但不動到行高 */
@media (pointer: coarse) {
  .gloss.is-ready .gloss__term::before {
    content: "";
    position: absolute;
    inset: -11px -8px;
  }
}

.gloss__body {
  display: block;
  margin: 18px 0 2px;
  padding-left: 16px;
  border-left: 1px solid var(--ink);
  font-size: 15px;
  line-height: 1.9;
}
.gloss.is-ready .gloss__body { display: none; }
.gloss.is-ready[data-open] .gloss__body { display: block; }

/* 版面夠寬才把註解移到閱讀欄外，否則會擠掉正文 */
@media (min-width: 1180px) {
  .gloss.is-ready[data-open] .gloss__body {
    position: absolute;
    top: 0;
    right: calc(100% + 32px);
    width: 196px;
    margin: 0;
    padding: 0 16px 0 0;
    border-left: 0;
    border-right: 1px solid var(--ink);
    text-align: right;
    font-size: 14px;
    line-height: 1.85;
  }
}

/* ---------- cards ---------- */
.card {
  background: var(--paper-texture);
  border: var(--hair);
  border-radius: var(--r-card);
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}
.card--bl { background: var(--bl-ink); color: var(--on-ink); }
.card--gl { background: var(--gl-ink); color: var(--on-ink); }
.card--aux { background: var(--aux); color: var(--on-aux); }
.card--aux .tag { color: var(--on-aux); border-color: var(--on-aux); }
.card__title {
  font-family: var(--font-round);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.03em;
  line-height: 1.55;
}
.card p { font-size: 15px; line-height: 1.8; }

.grid2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-sm); }

/* 直式海報與橫式劇照並排。欄寬按各自的長寬比分配（0.8fr : 1.5fr），
   兩張圖因此等高、上下緣齊平；整組寬度就是 680px 閱讀欄，
   左右緣與正文段落落在同一條軸線上。手機收成單欄（見 861px 斷點）。 */
.media-pair {
  display: grid;
  grid-template-columns: 0.8fr 1.5fr;
  align-items: start;
  column-gap: var(--space-sm);
  row-gap: var(--space-tight);
  width: 100%;
  max-width: var(--read);
  margin: var(--space-para) auto 0;
}
.media-pair img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
  border: var(--hair);
  border-radius: var(--r-card);
}
.media-pair__portrait { aspect-ratio: 4 / 5; }
.media-pair__landscape { aspect-ratio: 3 / 2; }
.media-pair__credit {
  grid-column: 1 / -1;
  margin-top: 0;
  font-size: 13px;
  line-height: 1.7;
  letter-spacing: 0.06em;
  opacity: 0.7;
}

/* 並排的兩欄各自是一個小節（標題＋內文＋引言）。
   欄內的疏密在所有尺寸都成立；手機上兩欄疊起來時，欄與欄之間拉開成小節距離。 */
.grid--aligned { row-gap: var(--space-evidence); }
.grid--aligned > * {
  display: grid;
  row-gap: var(--space-sm);
}
.grid--aligned > * > :is(.quote, .voice) {
  margin-top: calc(var(--space-component) - var(--space-sm));
}
/* 引言被 .voice 包起來時，撐滿最後一列的變成外層；
   讓它當 grid 容器，裡面的引言框才會跟著長高，兩欄依然等高。 */
.grid--aligned > * > .voice {
  display: grid;
}

/* 桌機並排時共用列線：標題對標題、內文對內文、引言對引言，
   欄位不會因為文字長短而高低參差。
   不支援 subgrid 的瀏覽器退回上面的直向堆疊，間距照樣成立。 */
@media (min-width: 861px) {
  .grid--aligned {
    grid-template-rows: auto auto 1fr;
    column-gap: var(--space-component);
    row-gap: var(--space-sm);
  }
  .grid--aligned > * {
    grid-row: 1 / -1;
    grid-template-rows: subgrid;
  }
}
.grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-sm); }

/* ---------- quote ---------- */
.quote {
  border: var(--hair);
  border-radius: var(--r-card);
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.quote p {
  font-family: var(--font-sans);
  font-size: clamp(15.5px, 2vw, 18px);
  line-height: 1.9;
  letter-spacing: 0.04em;
}
.quote--bl { background: var(--bl-ink); color: var(--on-ink); }
.quote--gl { background: var(--gl-ink); color: var(--on-ink); }
.quote--hl { background: var(--hl-ink); color: var(--on-ink); }
.quote cite {
  font-style: normal;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* 淺調引言：整塊色底退成紙上一層薄調，色相收進頂端的短色條與署名底下的螢光筆
   與 quote--bl／--gl／--hl 併用，由該修飾字決定色相 */
.quote--paper {
  --q-ink: var(--hl);
  --q-wash: rgba(250, 197, 93, 0.08);
  --q-cite: #6b5a33;
  gap: 18px;
  padding: clamp(24px, 3vw, 34px);
  background: var(--q-wash);
  /* 淺調版與滿版共用 --bl／--gl／--hl 修飾字，但底下只有一層薄調而不是實色油墨，
     所以文字要跟著紙走（--ink），不能沿用滿版那條「壓在油墨上恆黑」的規則。 */
  color: var(--ink);
}
.quote--bl.quote--paper {
  --q-ink: var(--bl);
  --q-wash: rgba(122, 134, 241, 0.08);
  --q-cite: #3f4790;
}
.quote--gl.quote--paper {
  --q-ink: var(--gl);
  --q-wash: rgba(237, 137, 89, 0.08);
  --q-cite: #8a4416;
}
/* 頂端短色條：署名不一定存在，色相靠這一筆固定留住 */
.quote--paper::before {
  content: "";
  width: 26px;
  height: 5px;
  background: var(--q-ink);
}
.quote--paper p {
  max-width: 40em;
  font-size: clamp(15.5px, 2vw, 17px);
  line-height: 2.05;
}
.quote--paper cite {
  align-self: flex-start;
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: none;
  color: var(--q-cite);
  padding: 0 0.25em 0.1em;
  background-image: linear-gradient(to top, var(--q-ink) 0 0.55em, transparent 0.55em);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.quotes { display: flex; flex-direction: column; gap: var(--space-sm); }

/* ---------- 受訪者頭像：站在引言框裡面的上方中央 ----------
   頭像擺在框外面會讀成兩個各自獨立的東西，中間那道空白就是分離的證據。
   所以整個收進框裡：跟內文、署名同屬一個容器，是這段話的開場而不是旁邊的附件。

   底色不填——圓框裡直接透出引言框自己的 8% 薄調。填一層奶油紙會讓圓形變成
   「貼上去的另一張紙」，透明才是同一個表面上畫的一個圈。外框仍是 1px 純黑，
   跟全站所有結構線同一支筆。

   一種構圖從 375px 一路到桌機，只有尺寸在變（上限 108px，比作者的綿羊 120px 小
   一階）：這是受訪者的聲音，不是作者在說話。 */
.voice {
  --voice-face: clamp(88px, 11vw, 108px);
  /* 頭像下方那行名牌所佔的高度；沒有名牌時是 0，框頂就不用多讓 */
  --voice-name: 0px;
  /* 與 .quote--paper 的內距同一條算式，臉的上緣才會落在框的內距線上 */
  --voice-inset: clamp(24px, 3vw, 34px);
  position: relative;
  width: 100%;
  max-width: var(--read);
  margin-left: auto;
  margin-right: auto;
}
.voice__avatar {
  position: absolute;
  top: var(--voice-inset);
  left: 50%;
  /* 絕對定位的容器是 shrink-to-fit，寬度得寫死：全站的 img { max-width: 100% }
     碰上寬度由自己決定的父層會解成 0，圖片就只剩兩條邊框。 */
  width: var(--voice-face);
  margin: 0;
  transform: translateX(-50%);
}
.voice__avatar img {
  width: var(--voice-face);
  height: var(--voice-face);
  border-radius: 50%;
  border: var(--hair);
  object-fit: cover;
  background: transparent;
}
/* 說話的對象不是受訪者本人而是被談論的那組人時，臉下面補一行名牌。
   小字、粗體、字距放開，跟作者對話框（.author-say__avatar）的名牌同一支筆，
   讀起來是「這張臉是誰」的標籤，不會跟引言本文搶重量。 */
.voice__avatar figcaption {
  margin-top: 6px;
  text-align: center;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.2;
  white-space: nowrap;
}
.voice--named { --voice-name: 22px; }

/* 框的上內距讓出頭像整個高度（含名牌），再加一個 --space-sm 的呼吸 */
.voice .quote--paper {
  padding-top: calc(var(--voice-inset) + var(--voice-face) + var(--voice-name) + var(--space-sm));
}

/* 成組堆疊的短引言（.quotes）：一句話配一張大頭像，會變成一大片空白架著一行字。
   這裡的臉是「誰在說」的記號，不是一段長證言的開場，所以縮一階、上方也收緊。 */
.quotes .voice {
  --voice-face: clamp(60px, 7vw, 72px);
  --voice-inset: clamp(18px, 2.2vw, 24px);
}

/* 寬度放得下就把臉移到文字左邊：橫向一排讀起來直接是「誰」說了「什麼」，
   比上下堆疊更緊，短句也不會被一段留白架著。

   條件看的是「這張卡自己有多寬」，不是視窗有多寬 —— 因為同一個斷點下，
   引言可能直接躺在 680px 的閱讀欄裡，也可能被塞進 .grid2 的一半欄寬。
   用 @media 時後者在 1440px 上只剩 352px 文字欄（21 個中文字），
   剛好卡在 The Breathing Room Rule 的 20 字下限上 —— 而那兩則正是 BL／百合
   並置對照的那一組，最不該讓行長變成勉強及格。
   560px 是回推的：臉 108 ＋ 內距 34 ＋ 呼吸 22 ＋ 右內距 34，
   要讓文字還留得住 20 個字（340px），卡就得有 560px 寬。
   窄過這條線就自動退回上方置中；不支援容器查詢的瀏覽器也落在同一個安全結果。 */
.voice { container-type: inline-size; }

@container (min-width: 560px) {
  /* 獨立的長證言也走同一種橫向構圖。原本只有 .quotes 套用，獨立引言一路堆疊到桌機，
     結果是為了讓出 108px 的臉，框頂多留了 164px 內距 —— 六則加起來，
     光是「臉上面的空氣」就佔掉快一屏，而框裡有一半以上的高度不是話、是內距。
     臉在框的高度上置中：長短證言一致，臉不會孤零零地卡在左上角。 */
  .voice__avatar {
    top: 50%;
    left: var(--voice-inset);
    transform: translateY(-50%);
  }
  .voice .quote--paper {
    padding-top: clamp(24px, 3vw, 34px);
    padding-left: calc(var(--voice-inset) + var(--voice-face) + var(--space-sm));
  }
}


/* ---------- 開場：整屏高度區塊（電腦版限定） ---------- */
@media (min-width: 861px) {
  .blocks--screen { gap: 0; }
  .block--screen {
    min-height: calc(100vh - var(--nav-h));
    justify-content: center;
  }
}

/* 手機也讓「BL 和百合」這個場景轉場目標區塊整屏顯示，黃色轉場才有完整的一屏效果 */
[data-scene-target] {
  min-height: calc(100vh - var(--nav-h));
  justify-content: center;
}

/* ---------- 開場：黃色圓形場景轉場（電腦版限定，JS 依捲動位置連續驅動） ---------- */
.chapter--scene { position: relative; isolation: isolate; overflow: hidden; }
.scene-wash {
  position: absolute;
  inset: 0;
  background: var(--hl);
  opacity: 0;
  z-index: -1;
  pointer-events: none;
}
@media (min-width: 861px) {
  .scene-pin {
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
  }
  .scene-pin__inner {
    position: sticky;
    top: var(--nav-h);
    height: calc(100vh - var(--nav-h));
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .scene-circle {
    width: min(40vw, 380px);
    height: min(40vw, 380px);
    border-radius: 50%;
    background: var(--hl);
    transform: scale(1);
    will-change: transform;
  }
}

@media (prefers-reduced-motion: reduce) {
  .scene-wash { opacity: 0 !important; }
  .scene-circle { transform: none !important; }
}

/* ---------- 開場：彈幕背景（其他受訪者的話，橫過打字機那句話的後方） ----------
   一屏只打得出一句話，但填答者有 886 位。彈幕層把其餘的話送過畫面後方，
   讓「這是一個人的話」變成「這是很多人同時在說話」——它是質地，不是內文，
   所以刻意壓到剛好看得見的濃度（0.14），aria-hidden，
   而且每一句都在下面的引言清單裡完整存在一次，螢幕閱讀器讀那一份就夠。 */
.block--danmaku { position: relative; }

/* 手機版的引言區塊本來只有文字那麼高，彈幕沒有跑道。給它一屏的一半以上，
   彈幕才有上下分軌的空間，這一屏也才像個「場景」而不是一行字。 */
@media (max-width: 860px) {
  .block--danmaku { min-height: clamp(420px, 62vh, 620px); justify-content: center; }
}

/* 彈幕要滿版橫過去，不受閱讀欄寬度限制 —— 溢出由 .chapter--scene 的 overflow: hidden 收掉 */
.danmaku {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  overflow: hidden;
  pointer-events: none;
  user-select: none;
  /* -2 讓彈幕排在黃色圓形與色彩轉場（都是 -1）之下 —— 彈幕不能蓋過黃色，
     得反過來被黃色吞掉：捲動時圓形放大，人聲一句一句被那片黃蓋掉，
     正好接上「換一個場景」這件事。
     ⚠️ 這條靠的是祖先都沒有生出 stacking context，所以
     .block--danmaku 不能掛 .reveal（進場前的 transform 會生出一個）。 */
  z-index: -2;
  font-family: var(--font-sans);
  --dm-op: 0.14;
}

.danmaku__item {
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
  font-size: var(--dm-size, 15px);
  font-weight: 500;
  line-height: 1;
  color: var(--ink);
  opacity: 0;
  will-change: transform, opacity;
  transform: translate3d(100vw, 0, 0);
}
.danmaku__item.is-running {
  opacity: var(--dm-lane-op, var(--dm-op));
  animation: danmaku-drift var(--dm-dur, 18s) linear forwards;
}
/* 常態：從右邊界掃到左邊界。兩端都在畫面外，
   .danmaku 的 overflow: hidden 會切掉，不需要淡入淡出。 */
@keyframes danmaku-drift {
  from { transform: translate3d(var(--dm-start, 100vw), 0, 0); }
  to   { transform: translate3d(-100%, 0, 0); }
}
/* 只有每條跑道「最初出場」的那一句例外：從畫面中線起跑，
   讀者一進到這一屏就已經有話在跑，不必等它從右邊走過來。
   代價是起跑點落在畫面裡，所以前 14% 的行程用來淡入 ——
   電腦版中線正好是黃色圓形所在，這段淡入整個被那片黃遮住，
   字看起來是從黃色後面走出來的；窄螢幕沒有圓形，就靠這段淡入。 */
.danmaku__item.is-running.is-first { animation-name: danmaku-drift-in; }
@keyframes danmaku-drift-in {
  from { transform: translate3d(var(--dm-start, 50vw), 0, 0); opacity: 0; }
  14%  { opacity: var(--dm-lane-op, var(--dm-op)); }
  to   { transform: translate3d(-100%, 0, 0); opacity: var(--dm-lane-op, var(--dm-op)); }
}
/* 捲出畫面就凍住，不在看不見的地方燒 CPU */
.danmaku.is-paused .danmaku__item { animation-play-state: paused; }

/* 引言本人要壓在彈幕上面 */
.quote-cycle { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  .danmaku { display: none; }
}

/* ---------- 開場：打字機引言輪播（不用線框卡片，文字直接 pop-up） ---------- */
.quote-cycle {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  text-align: center;
}
.quote-cycle__text {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: clamp(22px, 3.4vw, 34px);
  line-height: 1.6;
  /* em 而不是 px：字級縮一階，行長也跟著縮，一行永遠是 ~28 個中文字 */
  max-width: min(100%, 28em);
  margin-inline: auto;
}
/* 這批引言的長度差了四倍 —— 一句 24 字的話值得用最大的字級砸出來，
   一段 100 字的證言用同樣字級會變成佔滿半屏的字牆。JS 依字數掛上這兩級。 */
.quote-cycle__text.is-long { font-size: clamp(20px, 2.8vw, 28px); }
.quote-cycle__text.is-xlong { font-size: clamp(18px, 2.3vw, 24px); }
.quote-cycle__text cite {
  display: block;
  margin-top: 10px;
  font-style: normal;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  opacity: 0.65;
}
.quote-cycle.is-cycling {
  position: relative;
  min-height: clamp(160px, 24vw, 240px);
}
.quote-cycle.is-cycling .quote-cycle__text {
  position: absolute;
  inset: 0;
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(0.85);
  pointer-events: none;
  transition: opacity 0.35s ease, transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.quote-cycle.is-cycling .quote-cycle__text.is-current {
  opacity: 1;
  transform: scale(1);
}
.quote-cycle.is-cycling .quote-cycle__text cite {
  opacity: 0;
  transition: opacity 0.3s ease;
}
.quote-cycle.is-cycling .quote-cycle__text.is-typed cite { opacity: 0.65; }

/* ---------- 「BL和百合」場景：置中大標題 + 作者頭像對話框 ---------- */
.author-say {
  display: flex;
  /* 頭像在對話框高度上置中：文字長短不一時，靠上對齊會讓短氣泡的頭像顯得懸空 */
  align-items: center;
  justify-content: center;
  gap: clamp(20px, 3vw, 32px);
  margin-top: var(--space-component);
}
.author-say__avatar {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin: 0;
}
.author-say__avatar img {
  width: 90px;
  height: 90px;
  border-radius: 50%;
  border: var(--hair);
  object-fit: cover;
  background: var(--paper-texture);
}
.author-say__avatar figcaption {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
}

.speech-bubble {
  position: relative;
  flex: 1 1 480px;
  max-width: 560px;
  background: var(--cream);
  border: var(--hair);
  border-radius: var(--r-card);
  padding: 20px 24px;
}
.speech-bubble::before,
.speech-bubble::after {
  content: "";
  position: absolute;
  /* 尖角跟著置中的頭像走，指向頭像中心 */
  top: 50%;
  transform: translateY(-50%);
  width: 0;
  height: 0;
  border-top: 11px solid transparent;
  border-bottom: 11px solid transparent;
}
.speech-bubble::before {
  left: -14px;
  border-right: 14px solid var(--ink);
}
.speech-bubble::after {
  left: -12px;
  border-top-width: 10px;
  border-bottom-width: 10px;
  border-right: 12px solid var(--cream);
}

@media (max-width: 640px) {
  /* 頭像與圖說靠 align-items 居中就夠了；這裡不能下 text-align: center ——
     它會一路吃到氣泡裡那段七八行的中文，兩邊同時參差，是最難讀的排法。
     對話框裡的字跟全站內文一樣左對齊，左緣才有一條可以回頭的軸線。 */
  .author-say { flex-direction: column; align-items: center; }
  /* 直向堆疊後 480px 的 flex-basis 會變成氣泡的高度，短句子底下就空出一大片 */
  .speech-bubble { flex-basis: auto; max-width: 100%; }
  .speech-bubble::before,
  .speech-bubble::after { display: none; }
}

/* 標題、頭像、對話框依序由下往上浮現（沿用既有 .reveal／.in 動畫，只疊加進場延遲做出前後順序） */
.js .reveal.in.author-say__avatar { transition-delay: 0.12s; }
.js .reveal.in.speech-bubble { transition-delay: 0.24s; }

/* ---------- 換紙區塊：整段印在另一種紙上 ----------
   取代原本的照片＋半透明遮罩。純色紙 + riso 網點，留在「印在紙上」的世界裡：
   黑字對這個紙色是 16.7:1，內文的 BL／百合色塊也還分得出來。
   網點是 CSS 畫的，沒有多一個圖檔要載。 */
.stock {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border: var(--hair);
  border-radius: var(--r-card);
  background-color: var(--kraft);
  background-image:
    radial-gradient(rgba(0, 0, 0, 0.075) 1px, transparent 1px),
    url('../img/paper.png');
  background-size: 7px 7px, auto;
  background-repeat: repeat, repeat;
}
.stock__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-component);
  padding: clamp(28px, 4.5vw, 44px) clamp(20px, 4vw, 36px);
}

/* ---------- 換紙上的開場敘事 ----------
   一段第一人稱的小故事，不是論述。所以它跟 .stock 的一般用法反過來：
   段落之間收到 para（同一串思緒），而不是 component（各自獨立的元件），
   五段讀起來才是連著的一口氣。開場句用圓體升一階，像說書人先開口；
   最後的提問前留一個 evidence 級的停頓，把「故事」交還給讀者。 */
.story-stock .stock__content { gap: 0; }
.story-stock .measure { line-height: 2.1; }
.story-stock .measure + .measure { margin-top: var(--space-para); }
.story-stock .story-stock__open {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: clamp(21px, 3vw, 29px);
  line-height: 1.5;
  letter-spacing: 0.02em;
}
.story-stock .measure + .story-stock__turn { margin-top: var(--space-evidence); }

/* ---------- 引用書籍：文字＋書封卡片 ---------- */
.cite-row {
  display: flex;
  align-items: flex-start;
  gap: clamp(24px, 4vw, 56px);
}
.cite-row__text {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-component);
}

.book-cite {
  /* 基準寬度給 200px：空間不夠時讓內文先讓一點，書封不會被壓到看不清 */
  flex: 1 1 200px;
  min-width: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
}
.book-cite__stage {
  display: block;
  width: min(38vw, 200px);
  max-width: 100%; /* 欄位被壓窄時跟著縮，不要撐破版面 */
}
.book-cite__cover {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 2px 5px 5px 2px;
  box-shadow:
    inset 7px 0 12px -7px rgba(0, 0, 0, 0.55),
    6px 10px 22px rgba(0, 0, 0, 0.22);
}
.book-cite figcaption {
  max-width: 22ch;
  text-align: center;
  font-size: 12px;
  line-height: 1.6;
  opacity: 0.7;
}
@media (max-width: 720px) {
  .cite-row { flex-direction: column; align-items: center; text-align: center; }
  .book-cite { flex-basis: auto; }
  .book-cite__stage { width: min(50vw, 180px); }
}

/* ---------- 作品海報列：文字點名的劇，直接把海報並排擺出來 ----------
   跟 .book-cite 不同，這裡不模擬桌上的一本實體書，而是四張並置的參照圖，
   所以不套那組書封陰影 —— 每張海報的存在證據就是它的 1px 黑細框。
   四張海報統一裁成 4:5，讓這一列有一條齊平的天地線；只有 Gel Boys 是
   2:3 原比例，用 object-position 把裁切留在下緣，劇名與四張臉都保得住。 */
.posters {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(14px, 1.8vw, 22px);
  /* 整列收到七成寬並置中：四張海報一起等比縮小，行距與比例都不用另外改 */
  width: 70%;
  margin-left: auto;
  margin-right: auto;
}
.poster {
  margin: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.poster img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border: var(--hair);
  border-radius: var(--r-sm);
}
/* 兩張劇照並排的變體：非官方海報，裁成 1:1 讓正方形原圖與橫幅劇照統一高度；
   原本沒收邊寬，在寬螢幕上會被 .block 撐滿、跟真人臉一樣大——收回到 --read
   （跟 .media-pair 同一條基準線），單張高度大致砍半，回到跟其他內文圖片一致的尺度 */
.posters--2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  width: 100%;
  max-width: var(--read);
  margin-left: auto;
  margin-right: auto;
}
.poster--square img { aspect-ratio: 1 / 1; }
.poster figcaption {
  font-size: 13px;
  line-height: 1.6;
  letter-spacing: 0.04em;
}
.poster figcaption b {
  font-family: var(--font-round);
  font-weight: 700;
}
/* 產地標籤自己佔一行，用字距拉開，跟劇名分出層級 */
.poster figcaption span {
  display: block;
  margin-top: 3px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  opacity: 0.65;
}
.posters__credit {
  grid-column: 1 / -1;
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.7;
  letter-spacing: 0.06em;
  opacity: 0.6;
}

@media (max-width: 860px) {
  /* 兩欄時再縮到七成會太窄，收回滿寬 */
  .posters { grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
}

/* ---------- 粉絲投入的五種資源：一個循環 ----------
   注意力 → 時間 → 金錢 → 勞動力 → 人群連結 → 更多注意力。

   刻意不是五張卡片：卡片會讀成「五個不相干的東西」，
   一條連續的帶配上細線分格，讀到的是「同一份投入的五個面向」。
   分隔線上各壓一枚三角把順序講出來，帶子下面再接一條走回起點的路徑，
   整組就從「一列並排的資源」變成「一個轉得起來的循環」。

   圖示是畫出來的 SVG（Feather icons, MIT），24 格線、1.75 筆畫、圓端點 ——
   跟換紙鈕同一套語彙，全站的線性圖示只有這一種規格。
   刻意不用 BL 紫與百合橘：這五種資源兩個社群都在投入，用任一邊的油墨都會誤導。 */
.cycle__band {
  border: var(--hair);
  border-radius: var(--r-card);
  background: var(--paper-texture);
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
.cycle__seg {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  padding: 26px 16px;
}
.cycle__seg + .cycle__seg { border-left: var(--hair); }

/* 流向的三角直接壓在分隔線上，而且跟線同一個黑 ——
   讀起來是「這條線上長出一個箭頭」，不是另外貼一枚圖示上去。 */
.cycle__seg + .cycle__seg::before {
  content: "";
  position: absolute;
  top: 50%;
  left: -5px;
  margin-top: -5px;
  width: 0;
  height: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 9px solid var(--ink);
}
.cycle__ic {
  display: block;
  width: 31px;
  height: 31px;
  color: var(--ink);
}
.cycle__ic svg { display: block; width: 100%; height: 100%; }

/* ---------- 雙色圖示：線稿之外的第二版油墨 ----------
   黃色不是拿來替圖示上色的，它只落在每一格真正在講的那一塊上
   （金錢＝卡片的磁條），像 riso 印完黑線稿之後再壓一版黃。
   線稿仍走 currentColor（跟著紙翻），黃色是不翻的油墨，兩種紙上都成立。 */
.ic-duo__spot { fill: var(--hl); stroke: none; }
.cycle__label {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 20px;
  line-height: 1.4;
  letter-spacing: 0.03em;
}
.cycle__eg {
  font-size: 13px;
  line-height: 1.75;
  letter-spacing: 0.04em;
  opacity: 0.75;
}

/* ---------- 回流路徑 ----------
   帶子下面的一個 U：左右兩條垂直線接上帶子的下緣，所以整組讀起來是
   一條「走得回來」的封閉電路，而不是一列走到底就沒了的流程。
   兩枚三角標出走向：底邊中央往左、左上角往上回到第一格。

   線用 --hl-mark 而不是 --hl —— 這是畫在紙上的記號不是色塊填色，
   純黃 #fac55d 對奶油紙只有 1.5:1，畫上去等於看不見。 */
.cycle__loop {
  position: relative;
  /* 高度跟著標籤走：窄螢幕文案折成兩行時 U 會自己長高，
     不會讓字貼上路徑的線。 */
  display: grid;
  place-items: center;
  min-height: 58px;
  padding: 10px 0;
  margin: 0 26px;
  border: 1px solid var(--hl-mark);
  border-top: 0;
  border-radius: 0 0 var(--r-card) var(--r-card);
}
.cycle__loop::before {
  content: "";
  position: absolute;
  left: -5px;
  top: -1px;
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 9px solid var(--hl-mark);
}
.cycle__loop::after {
  content: "";
  position: absolute;
  left: calc(50% - 4px);
  bottom: -5px;
  width: 0;
  height: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-right: 9px solid var(--hl-mark);
}
.cycle__loop-t {
  margin: 0;
  /* 把字推離 U 的兩條垂直線，不讓文字貼到路徑上 */
  padding: 0 12px;
  text-align: center;
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 16px;
  line-height: 1.4;
  letter-spacing: 0.03em;
}

/* 窄螢幕轉成直列，每格改成「圖示在左、文字在右」的橫向排法，
   分隔線與流向三角也跟著從直的換成橫的（箭頭改為朝下）。 */
@media (max-width: 860px) {
  .cycle__band { grid-template-columns: 1fr; }
  .cycle__seg {
    flex-direction: row;
    align-items: center;
    text-align: left;
    gap: 16px;
    padding: 18px;
  }
  .cycle__seg + .cycle__seg { border-left: 0; border-top: var(--hair); }
  .cycle__seg + .cycle__seg::before {
    top: -5px;
    left: 50%;
    margin-top: 0;
    margin-left: -5px;
    border-top: 9px solid var(--ink);
    border-bottom: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
  }
  .cycle__ic { flex: 0 0 auto; }
  /* 橫排時標籤不讓步：例子文字可以折行，「勞動力」被拆成兩行不行。 */
  .cycle__label { flex: 0 0 auto; white-space: nowrap; }
  .cycle__loop { min-height: 50px; margin: 0 22px; }
}

/* ---------- charts ---------- */
.chart {
  border: var(--hair);
  border-radius: var(--r-card);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.chart__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding-bottom: 12px;
  border-bottom: var(--hair);
  margin-bottom: 8px;
}
.chart__title {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.08em;
}
.chart__unit {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  opacity: 0.6;
}

.legend { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.legend span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
}
.legend i {
  width: 12px;
  height: 12px;
  border: var(--hair);
  display: inline-block;
}
.legend .k-bl { background: var(--bl); }
.legend .k-gl { background: var(--gl); }

/* single-series bar */
.bar {
  display: grid;
  grid-template-columns: 168px minmax(0, 1fr) 66px;
  align-items: center;
  gap: 14px;
  padding: 9px 0;
  border-bottom: var(--hair-soft);
}
.bar:last-child { border-bottom: 0; }
.bar__label { font-size: 14px; line-height: 1.45; letter-spacing: 0.03em; }
.bar__label small {
  display: block;
  font-size: 11px;
  letter-spacing: 0.06em;
  opacity: 0.6;
}
.bar__track {
  height: 18px;
  border: var(--hair);
  border-radius: var(--r-sm);
  background: var(--paper-texture);
  overflow: hidden;
}
.fill {
  display: block;
  height: 100%;
  width: calc(var(--v) * 1%);
  background: var(--hl-ink);
  border-right: var(--hair);
  transform-origin: left center;
}
.fill--bl { background: var(--bl-ink); }
.fill--gl { background: var(--gl-ink); }
.fill--hl { background: var(--hl-ink); }
.fill--mute { background: var(--mute-ink); }
.bar__val {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: 16px;
  line-height: 1;
  text-align: right;
  letter-spacing: 0.01em;
}
.bar--peak .bar__label { font-weight: 700; }

/* comparison rows */
.cmp {
  display: grid;
  grid-template-columns: 168px minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: 14px;
  padding: 9px 0;
  border-bottom: var(--hair-soft);
}
.cmp:last-child { border-bottom: 0; }
.cmp__label { font-size: 14px; line-height: 1.45; letter-spacing: 0.03em; }
.cmp__side { display: grid; grid-template-columns: minmax(0, 1fr) 60px; align-items: center; gap: 10px; }
.cmp__k {
  display: none;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
}
.cmp__val {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: 15px;
  line-height: 1;
  text-align: right;
}

/* stacked band */
.stack {
  display: flex;
  border: var(--hair);
  border-radius: var(--r-sm);
  overflow: hidden;
  height: 46px;
}
.stack i {
  display: flex;
  align-items: center;
  justify-content: center;
  font-style: normal;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  border-right: var(--hair);
  white-space: nowrap;
  overflow: hidden;
}
.stack i:last-child { border-right: 0; }

/* checklist / bullets */
.bullets { display: flex; flex-direction: column; gap: 12px; }
.bullets li {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  gap: 12px;
  font-size: 15px;
  line-height: 1.8;
  align-items: start;
}
.bullets li::before {
  content: "";
  width: 9px;
  height: 9px;
  border: var(--hair);
  background: var(--hl);
  margin-top: 12px;
}
/* 卡片裡的線索清單：記號跟 .bullets 同一套，只把記號欄收窄。
   grid3 的卡片只有 ~360px 寬，預設 22px 的記號欄會把每一行的行首推掉一截。 */
.bullets--cues { gap: 10px; }
.bullets--cues li { grid-template-columns: 9px minmax(0, 1fr); }

/* ---------- chat — 粉絲之間你一言我一語的對話 ----------
   這幾句不是條列，是兩個人在群組裡輪流丟出來的猜測。
   所以左右交替：a 說一句、b 接一句、a 再補一句。
   紙泡（奶油紙＋細線）對重點黃油墨泡 —— 一樣待在「印在紙上」的世界裡，
   泡尾用同色的小方塊接出去，不做圓弧氣泡尾，維持全站的直角細線語彙。 */
.chat {
  list-style: none;
  margin: 0;
  /* 左右各留 7px，剛好是泡尾伸出去的寬度，泡尾才不會頂出卡片的內距 */
  padding: 2px 7px 4px;
  display: flex;
  flex-direction: column;
  gap: 13px;
}
.chat__row { display: flex; }
.chat__row--b { justify-content: flex-end; }

.chat__bubble {
  --bubble-bg: var(--cream);
  position: relative;
  max-width: 86%;
  padding: 9px 13px 10px;
  border: var(--hair);
  border-radius: var(--r-card);
  background: var(--bubble-bg);
  color: var(--ink);
  font-size: 15px;
  line-height: 1.85;
  letter-spacing: 0.02em;
}
/* 泡尾那一角要跟泡尾接成同一條線，所以泡泡自己的圓角收成直角 */
.chat__row--a .chat__bubble { border-bottom-left-radius: 0; }
.chat__row--b .chat__bubble {
  --bubble-bg: var(--hl);
  color: var(--on-ink);
  border-bottom-right-radius: 0;
}

/* 泡尾：同底色的小方塊，外側三條細線（上、外、下）接著泡泡的框線走一圈，
   內側不畫線，並且剛好蓋在泡泡的側框上，把那一段框線吃掉，讓輪廓連續。 */
.chat__bubble::after {
  content: "";
  position: absolute;
  bottom: -1px;
  width: 7px;
  height: 7px;
  background: var(--bubble-bg);
  border-top: var(--hair);
  border-bottom: var(--hair);
}
.chat__row--a .chat__bubble::after {
  left: -7px;
  border-left: var(--hair);
  border-bottom-left-radius: var(--r-sm);
}
.chat__row--b .chat__bubble::after {
  right: -7px;
  border-right: var(--hair);
  border-bottom-right-radius: var(--r-sm);
}

/* touchpoint map — 三個節點騎在一條橫貫的細線上，文字往下掛。
   三個特質是並列而非先後，所以軸線是橫的：一眼看完三個，而不是讀一串清單。 */
.touchpoints {
  --tp-gap: clamp(20px, 3vw, 36px);
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--tp-gap);
}
/* 橫軸兩端剛好收在頭尾節點的圓心：三等分欄寬的一半，就是第一個圓心的位置，
   線頭因此完全藏在不透明的實色油墨圓裡，兩端不會露出小尾巴。 */
.touchpoints::before {
  content: "";
  position: absolute;
  top: 38px;
  left: calc((100% - 2 * var(--tp-gap)) / 6);
  right: calc((100% - 2 * var(--tp-gap)) / 6);
  height: 1px;
  background: var(--mist);
}
.touchpoint {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
/* 欄線從節點下緣才開始，避免跟橫軸交叉成十字 */
.touchpoint + .touchpoint::before {
  content: "";
  position: absolute;
  top: 96px;
  bottom: 2px;
  left: calc(var(--tp-gap) / -2);
  width: 1px;
  background: var(--mist);
}
.touchpoint__node {
  position: relative;
  z-index: 1;
  width: 76px;
  height: 76px;
  border-radius: 50%;
  border: var(--hair);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 14px;
  line-height: 1.35;
  letter-spacing: 0.02em;
}
.touchpoint__node--a { background: var(--mute-ink); color: var(--on-ink); }
.touchpoint__node--b { background: var(--hl-ink); color: var(--on-ink); }
.touchpoint__node--c { background: var(--aux); color: var(--on-aux); }

.touchpoint__title {
  margin: 22px 0 9px;
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 16.5px;
  letter-spacing: 0.02em;
  line-height: 1.55;
  text-wrap: balance;
}
.touchpoint__desc {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.85;
  max-width: 32em;
}

/* 窄螢幕放不下三欄，橫軸也就不成立：改回直排，欄線翻成橫的分隔線 */
@media (max-width: 720px) {
  .touchpoints { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .touchpoints::before { display: none; }
  .touchpoint { align-items: flex-start; text-align: left; }
  .touchpoint + .touchpoint::before {
    top: -14px;
    bottom: auto;
    left: 0;
    right: 0;
    width: auto;
    height: 1px;
  }
  .touchpoint__node { width: 60px; height: 60px; font-size: 12px; }
  .touchpoint__title { margin-top: 16px; }
}

/* two-tone compare panel */
.versus {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border: var(--hair);
  border-radius: var(--r-card);
  overflow: hidden;
}
.versus > div { padding: 20px; }
.versus > div + div { border-left: var(--hair); }
.versus__head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-bottom: 12px;
  margin-bottom: 14px;
  border-bottom: var(--hair);
  font-family: var(--font-round);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.04em;
}
.versus__head .tag {
  font-size: 13px;
  padding: 8px 11px;
}

/* big number inline */
.figure-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-sm); }
.figure {
  border: var(--hair);
  border-radius: var(--r-card);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.figure__num {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.05;
  letter-spacing: 0;
}
.figure__num sup { font-size: 0.4em; vertical-align: super; letter-spacing: 0; }
.figure__note { font-size: 13px; line-height: 1.7; opacity: 0.75; }
.figure--bl { background: var(--bl-ink); color: var(--on-ink); }
.figure--gl { background: var(--gl-ink); color: var(--on-ink); }

/* ============================================================
   PDF 全文預覽（slwl 斜向縮圖牆）
   來源：素材／wallembed.html，逐字搬過來，只改了縮圖的路徑
   （原本內嵌 base64，現在抽成 img/report-wall/page-XX.webp）。
   ============================================================ */
.slwl{--slwl-fg:var(--ink);--slwl-mute:var(--aux);
  --slwl-bg:#f4f2ed;
  --slwl-bg-rgb:244,242,237;
  position:relative;width:100%;margin:0 auto;overflow:hidden;border-radius:18px;
  background:var(--slwl-bg);
  font-family:"Noto Serif TC","Songti TC","PingFang TC","Microsoft JhengHei",-apple-system,BlinkMacSystemFont,"Segoe UI",serif;
  -webkit-font-smoothing:antialiased;}
.slwl *{box-sizing:border-box}
.slwl-clip{position:relative;width:100%;height:var(--slwl-h,clamp(228px,27.6vw,372px));overflow:hidden}

/* 傾斜的平面，刻意做得比容器大很多，旋轉後四角才不會露空 */
.slwl-plane{position:absolute;top:50%;left:50%;width:170%;height:190%;
  display:flex;gap:1.6%;
  transform:translate(-50%,-50%) perspective(1500px) rotateX(var(--slwl-rx,12deg)) rotateZ(calc(var(--slwl-tilt,16) * -1deg));
  transform-style:preserve-3d;will-change:transform}
.slwl-col{flex:1 1 0;min-width:0;align-self:flex-start;
  display:flex;flex-direction:column;
  animation:slwl-run var(--slwl-d,90s) linear infinite;will-change:transform}
.slwl-col.slwl-rev{animation-direction:reverse}
.slwl-half{display:block;flex:0 0 auto}
@keyframes slwl-run{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,-50%,0)}}

.slwl-card{display:block;width:100%;margin-bottom:12px;border-radius:7px;overflow:hidden;
  background:#fff;border:1px solid rgba(128,120,108,.22);
  box-shadow:0 6px 18px rgba(30,26,20,.13), 0 1px 2px rgba(30,26,20,.06);
  transition:transform .3s ease, box-shadow .3s ease}
.slwl-card img{display:block;width:100%;aspect-ratio:16/9;object-fit:cover;
  -webkit-user-drag:none;user-drag:none}

/* 四邊柔和淡出，讓牆融進頁面而不是被硬切一刀 */
.slwl-fade{position:absolute;inset:0;pointer-events:none;z-index:2}
.slwl-fade::before{content:"";position:absolute;inset:0;
  background:
    linear-gradient(to right,  var(--slwl-bg) 0%, rgba(var(--slwl-bg-rgb),0) 13%, rgba(var(--slwl-bg-rgb),0) 87%, var(--slwl-bg) 100%),
    linear-gradient(to bottom, var(--slwl-bg) 0%, rgba(var(--slwl-bg-rgb),0) 12%, rgba(var(--slwl-bg-rgb),0) 84%, var(--slwl-bg) 100%)}
.slwl-fade::after{content:"";position:absolute;inset:0;
  background:radial-gradient(120% 90% at 50% 45%, rgba(0,0,0,0) 40%, rgba(30,26,20,.1) 100%)}

/* 覆蓋層 */
.slwl-over{position:absolute;inset:0;z-index:3;display:flex;flex-direction:column;
  justify-content:flex-end;padding:clamp(20px,4%,42px);pointer-events:none}
.slwl-over::before{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg, rgba(var(--slwl-bg-rgb),0) 42%, rgba(var(--slwl-bg-rgb),.66) 70%, rgba(var(--slwl-bg-rgb),.93) 100%)}
.slwl-over>*{position:relative}
.slwl-t{font-size:clamp(18px,2vw,21px);font-weight:700;line-height:1.4;letter-spacing:.01em;color:var(--slwl-fg)}
.slwl-s{margin-top:8px;font-size:13px;line-height:1.9;color:var(--slwl-mute);max-width:38em}
.slwl-cta{align-self:flex-start;margin-top:16px;pointer-events:auto;
  display:inline-flex;align-items:center;gap:8px;height:40px;padding:0 22px;border-radius:999px;
  background:#2a2825;color:#fbf9f4;text-decoration:none;white-space:nowrap;
  font-size:13px;letter-spacing:.08em;
  transition:background .18s,transform .18s,box-shadow .18s}
.slwl-cta:hover{background:#403c37;box-shadow:0 10px 24px rgba(0,0,0,.22)}
.slwl-cta:active{transform:scale(.97)}
.slwl-badge{position:absolute;top:clamp(14px,3%,26px);right:clamp(14px,3%,26px);z-index:4;
  font-size:11.5px;letter-spacing:.16em;color:var(--slwl-fg);
  background:rgba(var(--slwl-bg-rgb),.82);border:1px solid rgba(128,120,108,.3);
  border-radius:999px;padding:6px 14px;backdrop-filter:blur(6px)}

.slwl-link{position:absolute;inset:0;z-index:5;display:block}
.slwl-over[hidden],.slwl-cta[hidden],.slwl-badge[hidden]{display:none}

@media (hover:hover){
  .slwl:hover .slwl-card:hover{transform:translateY(-4px) scale(1.03);
    box-shadow:0 16px 34px rgba(30,26,20,.24)}
}
@media (prefers-reduced-motion:reduce){
  .slwl-col{animation:none}
}

/* ---- 訂閱區（跟縮圖牆各自獨立，牆後面接一張卡片） ---- */
.sgate{--sgate-fg:var(--ink);--sgate-mute:var(--aux);
  align-self: stretch;
  display: flex;
  flex-direction: column;
  margin-top: var(--space-component);
  padding:20px 22px;border-radius:16px;
  background:rgba(42,40,37,.04);border:1px solid rgba(42,40,37,.1);
  font-family: var(--font-sans);
  -webkit-font-smoothing:antialiased;}
.sgate-t{font-family:var(--font-round);font-size:20px;font-weight:700;letter-spacing:.03em;line-height:1.55;color:var(--sgate-fg)}
.sgate-s{margin-top:6px;font-size:15px;line-height:1.85;color:var(--sgate-mute)}
.sgate-s p{margin:0}
.sgate-s p + p{margin-top:10px}
.sgate-box{position:relative;margin-top:14px;border-radius:10px;overflow:hidden;
  background:#fff;border:1px solid rgba(42,40,37,.12)}
.sgate-embed{display:block;width:100%;border:0;background:transparent;transform-origin:top left}
.sgate-ph{padding:18px;font-size:13px;line-height:1.9;color:var(--sgate-mute)}
.sgate-f{margin-top:auto;padding-top:14px;font-size:13px;line-height:1.9;color:var(--sgate-mute)}
.sgate-f a{color:var(--sgate-fg);text-underline-offset:3px}
@media (max-width:560px){
  .sgate{margin-left:0;margin-right:0;padding:15px 13px;border-radius:13px}
  .sgate-t{font-size:14px}
}

/* PDF 全文預覽：≥861px 縮圖牆與訂閱框並排，牆才不用靠拉高撐版面 */
@media (min-width: 861px) {
  #pdf-preview {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(240px, 1fr);
    column-gap: clamp(28px, 3vw, 44px);
    align-items: start;
  }
  #pdf-preview > .h3,
  #pdf-preview > .measure {
    grid-column: 1 / -1;
  }
  #pdf-preview .sgate { margin-top: 0; }
}

/* ============================================================
   系列專題 — 四張刊物卡
   ============================================================
   把整個系列講成幾本並排的刊物。序號沉在頂端、刊名與說明沉到底部，
   中間留白撐開，所以有直式封面的比例感，但高度只有整張 3/4 封面的一半。

   狀態只靠「紙」講，三檔都是實色 vs 空白的差別，不是深一點淺一點：
     ・--now   正在讀的這一本，整張印成實色重點黃（--hl，全樣本通用色，
               跟這份報告的主 CTA 同一支油墨）。全站同時只有一張。
     ・--done  已發布的舊作，也是實色，但退成牛皮紙（--kraft），把重點黃
               留給正在讀的那一本；期數大字不降階，因為它真的存在。
     ・--next／--coming  還沒有：留在奶油紙上、蓋 45° 硬邊斜線網紋 —— 那是
               作品牆「圖片待補」用過的同一個記號。

   ── 下一彈上線時要改什麼 ──────────────────────────────────
   1. 新上線那張換成 sspn__item--now，原本的 --now 換成 --done。
   2. 標籤文字（已發布／NOW READING／製作中）直接改 .sspn__tag 內容。
   3. 有網址的那張把標題包成 <a class="sspn__link">，::after 會把整張卡
      撐成點擊區；沒有網址的就別包，因為還沒有可去的地方。 */
.sspn {
  margin-top: clamp(18px, 2.4vw, 28px);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-sm);
}
.sspn__item {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: clamp(14px, 2vw, 24px);
  min-height: 210px;
  padding: clamp(18px, 2vw, 24px);
  border: var(--hair);
  border-radius: var(--r-card);
}
/* 已解鎖：實色油墨，不疊紙紋 —— 跟 .card--hl／.btn-cta 同一種填法 */
.sspn__item--now { background: var(--hl-ink); }
/* 已發布的舊作：也是實色（它真的存在），但退成牛皮紙，把重點黃留給正在讀的那一本 */
.sspn__item--done { background: var(--kraft); }
/* 整張卡可點：連結本體只包標題（螢幕閱讀器讀到的就是刊名），
   再用一塊透明的 ::after 把整張卡撐成點擊區 —— 不動 DOM 結構。 */
.sspn__link {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.sspn__link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.sspn__item--done:hover { background: color-mix(in srgb, var(--kraft) 82%, var(--ink)); }
.sspn__item--done:focus-within { outline: 2px solid var(--ink); outline-offset: 2px; }
.sspn__link:focus-visible { outline: none; }
/* 未解鎖：留在紙上，蓋 45° 硬邊斜線網紋（硬停止點，不是漸層） */
.sspn__item--next,
.sspn__item--coming {
  background-image: repeating-linear-gradient(45deg,
    color-mix(in srgb, var(--ink) 10%, transparent) 0 1px, transparent 1px 7px);
}
.sspn__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.sspn__num {
  font-family: var(--font-round);
  font-weight: 900;
  /* figure-number 階（DESIGN.md typography）：全站大數字共用的那一階 */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.05;
}
/* 退階的下限是對比度不是好看：期數大字守 3:1，所以只能比已解鎖淡一階 */
.sspn__item--next .sspn__num,
.sspn__item--coming .sspn__num { opacity: .5; }
.sspn__foot { display: flex; flex-direction: column; gap: 6px; }
.sspn__title {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 17px;
  line-height: 1.5;
  letter-spacing: .02em;
}
.sspn__desc { font-size: 13px; line-height: 1.7; opacity: .74; }

@media (max-width: 1080px) {
  .sspn { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .sspn { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================
   調查方法 — 三欄步驟（qcol）
   ============================================================
   這一段是讀者要「看懂」而不是「被說服」的內容，所以沒有卡片、沒有填色塊：
   三個步驟只靠欄與欄之間一條 16% 黑細線分開，序號退成小號註解字。
   全站唯一一處用淡黑線而不是 1px 純黑 --hair 的地方 —— 這條線是欄距，
   不是結構框，跟黑線一樣重會把方法論講得比結論還大聲。 */
.qcols {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 clamp(22px, 3vw, 40px);
}
.qcol {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-left: clamp(18px, 2.4vw, 30px);
  border-left: 1px solid rgba(0, 0, 0, 0.16);
}
.qcol:first-child { padding-left: 0; border-left: 0; }
.qcol__step {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .14em;
  color: var(--aux);
}
.qcol__title {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: .02em;
}
.qcol p { font-size: 14px; line-height: 1.85; }

@media (max-width: 860px) {
  .qcols { grid-template-columns: minmax(0, 1fr); gap: var(--space-component); }
  .qcol { padding-left: 0; border-left: 0; }
}

/* ============================================================
   OUTRO + FOOTER
   ============================================================ */
.outro { border-top: var(--hair); }
.outro__body { padding: clamp(44px, 7vw, 80px) 0; display: flex; flex-direction: column; gap: var(--space-block); }

/* 結語沒有自己的排版規則：它就是一個 .block + .measure，跟前面每一章的內文
   走同一條閱讀欄、同一組段距。舊的 .closing 自成一套（62ch 寬、14px 段距），
   結果比內文窄一截、段落也擠一截 —— 讀到最後一段會覺得換了個版面。 */

/* ---------- about（關於我） ---------- */
.about {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-sm) clamp(32px, 5vw, 64px);
}
.about__text { flex: 1 1 360px; }
.about__text p + p { margin-top: 1.25em; }
.about__text .bullets { margin-top: 16px; }
.about__text a {
  text-decoration: none;
  border-bottom: 1px solid var(--ink);
}
.about__text a:hover,
.about__text a:focus-visible { background: var(--hl); color: var(--on-ink); }
.about__avatars {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 16px;
  margin-left: auto;
}
.about__avatar {
  display: block;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  border: var(--hair);
  object-fit: cover;
  background: var(--paper-texture);
}
@media (max-width: 640px) {
  .about { flex-direction: column; align-items: flex-start; }
  .about__text { flex-basis: auto; }
  .about__avatars { margin-left: 0; }
}

/* ---------- cta（來信邀約按鈕） ---------- */
.cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
  text-align: center;
  padding: var(--space-component) 0;
}
.btn-cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: var(--hair);
  border-radius: var(--r-pill);
  background: var(--hl);
  color: var(--on-ink);
  padding: 16px 36px;
  font-family: var(--font-round);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.08em;
  cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.btn-cta:hover { transform: translateY(-2px); }
.btn-cta:active { transform: translateY(0); }
.btn-cta:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.btn-cta__toast {
  position: absolute;
  bottom: calc(100% + 12px);
  left: 50%;
  background: var(--ink);
  color: var(--cream);
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 7px 14px;
  border-radius: var(--r-btn);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 4px);
  transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
.btn-cta__toast::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  border: 5px solid transparent;
  border-top-color: var(--ink);
  transform: translateX(-50%);
}
.btn-cta__toast.is-shown {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ---------- credits（製作名單，排在 footer 之前） ---------- */
.credits {
  border-top: var(--hair);
  background: var(--paper-texture);
}
.credits__inner {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--space-component) var(--gutter);
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 20px 40px;
  align-items: start;
}
.credits__title {
  margin: 0;
  font-family: var(--font-round);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.credits__list { margin: 0; }
.credits__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 14px;
  padding: 10px 0;
  border-top: var(--hair-soft);
}
.credits__row:first-child { border-top: 0; padding-top: 0; }
.credits__list dt {
  flex: 0 0 auto;
  font-size: 12px;
  letter-spacing: 0.1em;
  color: var(--aux);
}
.credits__list dd {
  margin: 0;
  font-family: var(--font-round);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.05em;
}
@media (max-width: 640px) {
  .credits__inner { grid-template-columns: 1fr; gap: 14px; }
}

.site-footer {
  border-top: var(--hair);
  background: var(--paper-texture);
}
.site-footer__inner {
  padding: 40px var(--gutter);
  max-width: var(--page);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 30px 20px;
}
.site-footer h5 {
  margin: 0 0 12px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.site-footer li, .site-footer p { font-size: 13px; line-height: 1.9; letter-spacing: 0.05em; }
.site-footer a { text-decoration: none; border-bottom: 1px solid transparent; }
.site-footer a:hover { border-bottom-color: var(--ink); }
.site-footer__mark {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: 22px;
  line-height: 1.45;
  margin-bottom: 10px;
}
.site-footer__legal {
  border-top: var(--hair);
  padding: 16px var(--gutter) 64px;
  max-width: var(--page);
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 8px 20px;
  font-size: 11px;
  letter-spacing: 0.12em;
}

.totop {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 40;
  border: var(--hair);
  background: var(--cream);
  border-radius: var(--r-pill);
  padding: 10px 18px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  cursor: pointer;
  box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}
.totop.is-on { opacity: 1; pointer-events: auto; }
.totop:hover { background: var(--hl); color: var(--on-ink); }

/* ============================================================
   MOTION (progressive enhancement)
   ============================================================ */
.js .fill { transform: scaleX(0); }
.js .in .fill { transform: scaleX(1); transition: transform 0.9s cubic-bezier(0.16, 1, 0.3, 1); }
.js .reveal { opacity: 0; transform: translateY(14px); }
.js .reveal.in {
  opacity: 1;
  transform: none;
  transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .fill { transform: none; }
  .js .reveal { opacity: 1; transform: none; }
  * { transition-duration: 0.001ms !important; }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 1000px) {
  .grid3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .chapter__head { grid-template-columns: 110px 1fr; gap: 0 24px; }
}

@media (max-width: 860px) {
  :root { --gutter: 20px; }

  .nav__links {
    position: absolute;
    top: var(--nav-h);
    left: 0;
    right: 0;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--paper-texture);
    border-bottom: var(--hair);
    padding: 6px var(--gutter) 14px;
  }
  .nav__toggle { white-space: nowrap; padding: 7px 14px; }
  .nav__actions { gap: 12px; }

  /* 窄螢幕已經有換紙鈕 + 目錄鈕搶版面，「下載完整報告」收成純圖示鈕
     （文字用跟換紙鈕標籤同一招藏起來，不是拿掉，可及名稱還在）。 */
  .nav__dl { padding: 8px; gap: 0; }
  .nav__dl__text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .nav__links.is-open { display: flex; }
  .nav__links a {
    padding: 13px 2px;
    border-bottom: var(--hair-soft);
    font-size: 15px;
  }
  .nav__links a:last-child { border-bottom: 0; }
  .nav__links a[aria-current="true"] { border-bottom-color: rgba(0, 0, 0, 0.14); }
  .nav__links a[aria-current="true"]::after { content: " ●"; font-size: 9px; vertical-align: middle; }
  .nav__toggle { display: inline-flex; }

  .strip { grid-template-columns: repeat(2, 1fr); }
  .strip__cell { border-left: 0; border-top: var(--hair-soft); }
  .strip__cell:nth-child(-n + 2) { border-top: 0; }
  .strip__cell:nth-child(even) { border-left: var(--hair); }

  .grid2, .grid3, .figure-row, .media-pair { grid-template-columns: 1fr; }

  .versus { grid-template-columns: 1fr; }
  .versus > div + div { border-left: 0; border-top: var(--hair); }

  .chapter__head { grid-template-columns: 1fr; gap: 0; }
  .chapter__num { grid-row: auto; margin-bottom: 6px; }

  .site-footer__inner { grid-template-columns: 1fr; }
}

/* 窄螢幕的導覽列：先犧牲裝飾，最後才犧牲站名。
   三個元件搶同一條 64px 高的橫列，讓步的順序是刻意的 ——
   MENU 只是給目錄鈕一點英文質感，不是資訊，所以它第一個走（省下 53px）；
   接著收窄目錄鈕的左右內距與各處間距（再省 14px）；
   全名站名是這份報告的招牌，排到最後才換成短版。 */
@media (max-width: 540px) {
  .nav__toggle__en { display: none; }
  /* 只寫左右內距 —— 上下留給 pointer: coarse 那條規則去顧觸控高度，
     兩邊各管一個軸就不會互相蓋掉。
     收窄後目錄鈕仍是 56×47，兩個方向都還在 44px 觸控門檻之上。 */
  .nav__toggle { padding-left: 12px; padding-right: 12px; }
  .nav__actions { gap: 6px; }
  .nav__inner { gap: 8px; }
}

/* 讓到這裡還是擠不下才換短版站名。
   量出來全名這一列需要 384px（站名的字體若沒載到、退回 Hiragino 則是 386px，
   所以斷點抓在 387 而不是 384，留 2px 給後備字體的差異）：
   390／393／402（iPhone 14・15・16 系列）、412、428、430 都放得下全名，
   375（SE、mini）與 360 這類才會看到短版。 */
@media (max-width: 387px) {
  .nav__mark__long { display: none; }
  .nav__mark__brief { display: inline; }
}

@media (max-width: 640px) {
  body { font-size: 15.5px; line-height: 1.9; }

  .bar { grid-template-columns: minmax(0, 1fr) 62px; gap: 6px 12px; padding: 12px 0; }
  .bar__label { grid-column: 1 / -1; }
  .bar__val { font-size: 16px; }

  .cmp { grid-template-columns: 1fr; gap: 8px; padding: 14px 0; }
  .cmp__label { font-weight: 700; }
  .cmp__side { grid-template-columns: 34px minmax(0, 1fr) 56px; }
  .cmp__k { display: block; }

  .stack { height: 40px; }
  .stack i { font-size: 11px; }

  .quote { padding: 16px 18px; }
  .chart, .card, .figure { padding: 16px; }
  .totop { right: 14px; bottom: 14px; padding: 9px 14px; }
}

/* ============================================================
   觸控裝置：把每個可點的東西撐到手指大小
   ============================================================
   跟著名詞解釋那顆按鈕（見 .gloss__term::before）的作法走：條件是「用手指點」
   而不是「螢幕很窄」，所以掛在 pointer: coarse 上，觸控筆電也一併受惠。

   兩種情況要用兩種解法，不能一律套同一招：

   1. 文章裡的行內連結 —— 四周都是不能點的文字，把可點範圍用 ::before
      往外撐開就好，行高一個像素都不會動。
   2. 連續排列的連結列（頁尾目錄）—— 上下相鄰的都是連結，硬撐開會讓兩個
      可點範圍互相重疊，點到的變成 DOM 順序在後的那一個，比目標太小更糟。
      這種就得老實把行距拉開，讓每一列真的有 44px。 */
@media (pointer: coarse) {
  /* 1. 行內連結：撐開可點範圍，不動行高 */
  .note a,
  .bullets a {
    position: relative;
  }
  /* 高度直接釘在 44px 並上下置中，不管這行的字級與行高是多少都成立 */
  .note a::before,
  .bullets a::before {
    content: "";
    position: absolute;
    left: -8px;
    right: -8px;
    top: 50%;
    height: 44px;
    transform: translateY(-50%);
  }
  /* 兩條個人社群連結原本只差 39px，撐開後會疊到一起，把行距一起拉開 */
  .bullets { gap: 18px; }

  /* 2. 頁尾目錄：連續的連結列，改用真正的行距 */
  .site-footer li a {
    display: block;
    padding: 10px 0;
  }

  /* 3. 差幾個像素就到 44px 的既有元件 */
  .nav__mark { padding: 6px 0; }
  /* 只補上下 —— 左右交給上面的斷點規則，不然 shorthand 會把窄螢幕收窄的內距蓋回去 */
  .nav__toggle { padding-top: 10px; padding-bottom: 10px; }
  /* 圖示 15px，上下各補 15px 才到 44px；左右交給 860px 那個斷點規則 */
  .nav__dl { padding-top: 15px; padding-bottom: 15px; }
  .totop { padding: 12px 18px; }
}

/* ============================================================
   導讀 — 一句提問 ＋ 三個章節入口
   ============================================================
   開場那一屏是情緒，作品牆是換氣，中間需要一張目錄：告訴讀者這篇在問什麼、
   有多長、可以從哪裡切進去。所以它不做成卡片牆，而是一份「印在紙上的目錄」——
   三列共用同一條細線，跟全站所有結構線同一支筆。

   點得下去這件事要看得出來：整列填一塊重點黃、字翻成恆黑（跟 .about__text a:hover
   同一個動作，也是這份報告一貫的「印上去」而不是「打光」）。觸控裝置沒有 hover，
   右側那枚箭頭圈就是靜態的可點性提示。 */
.guide {
  border-top: var(--hair);
  padding: clamp(52px, 6.5vw, 88px) 0 clamp(56px, 7vw, 96px);
}

/* 讓導讀貼齊視窗高度：內容垂直置中，列距放寬，讓三列目錄自然撐出接近整屏的
   份量，而不是硬加一段空白。窄螢幕（≤720px）維持原本的 padding，不強制撐滿。 */
.guide.guide--fill {
  min-height: calc(0.99 * (100vh - var(--nav-h)));
  min-height: calc(0.99 * (100dvh - var(--nav-h)));
  display: flex;
  align-items: center;
  padding-top: 0;
  padding-bottom: 0;
}
.guide.guide--fill > .wrap { width: 100%; }
.guide--fill .guide-card { padding-top: clamp(26px, 3.2vw, 38px); padding-bottom: clamp(26px, 3.2vw, 38px); }
.guide--fill .guide__list { margin-top: clamp(28px, 3.6vw, 44px); }
.guide--fill .guide__note { margin-top: clamp(40px, 4.6vw, 60px); }
@media (max-width: 720px) {
  .guide.guide--fill {
    min-height: auto;
    display: block;
    padding: clamp(52px, 6.5vw, 88px) 0 clamp(56px, 7vw, 96px);
  }
}

.guide__lede {
  margin-top: 0;
  max-width: 62ch;
  font-size: clamp(15px, 1.7vw, 16.5px);
  line-height: 1.72;
}

/* ---------- 三列章節入口 ---------- */
.guide__list { margin-top: clamp(14px, 1.8vw, 22px); }
/* 列與列共用一條線，最後一列自己補下緣 */
.guide__item { border-top: var(--hair); }
.guide__item:last-child { border-bottom: var(--hair); }

/* 一列＝目錄的一行：序號、章名、提問、頁碼位置的那枚箭頭，全部落在同一條線上。 */
.guide-card {
  display: grid;
  grid-template-columns: minmax(40px, 58px) minmax(0, 1fr) auto;
  align-items: center;
  gap: 0 clamp(12px, 1.8vw, 22px);
  padding: 22px clamp(8px, 1.2vw, 14px);
  text-decoration: none;
  transition: background-color 0.18s ease, color 0.18s ease;
}
.guide-card__num {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: clamp(22px, 2.4vw, 30px);
  line-height: 1.1;
  letter-spacing: 0;
  color: var(--hl-mark);
  transition: color 0.18s ease;
}
.guide-card__text {
  display: block;
  min-width: 0;
}
/* 章名與提問並排成一行；容不下時提問自己換行，列不會被撐成兩倍高 */
.guide-card__line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 1px 14px;
}
.guide-card__title {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: clamp(18px, 2vw, 23px);
  line-height: 1.4;
  letter-spacing: 0.02em;
}
.guide-card__ask {
  font-weight: 400;
  font-size: clamp(14px, 1.6vw, 15.5px);
  line-height: 1.6;
}
/* 靜態的可點性提示：觸控裝置沒有 hover，這枚圈就是唯一在說「這一列會帶你去別的地方」的記號 */
.guide-card__go {
  align-self: center;
  width: 30px;
  height: 30px;
  border: var(--hair);
  border-radius: 50%;
  display: grid;
  place-items: center;
}
.guide-card__go svg {
  width: 14px;
  height: 14px;
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

@media (hover: hover) {
  .guide-card:hover { background: var(--hl-ink); color: var(--on-ink); }
  .guide-card:hover .guide-card__num { color: var(--on-ink); }
  .guide-card:hover .guide-card__go svg { transform: translateX(3px); }
}
.guide-card:focus-visible {
  background: var(--hl-ink);
  color: var(--on-ink);
  outline: 2px solid var(--ink);
  outline-offset: -5px;
}
.guide-card:focus-visible .guide-card__num { color: var(--on-ink); }

/* ---------- 附註：完整版報告 ----------
   目錄讀完到這裡，語氣要換一次：所以換一張紙。牛皮紙（--kraft）＋整塊置中，
   像把一張便條夾進報告裡，而不是又一個跟目錄同色的框。
   寬度給到全站閱讀寬（--read），內容只有一句下載引導 —— 它是附註，
   不該在目錄後面再長出一個高塊。 */
.guide__note {
  margin: clamp(26px, 3.2vw, 40px) auto 0;
  max-width: var(--read);
  background-color: var(--kraft);
  border: var(--hair);
  border-radius: var(--r-card);
  padding: clamp(14px, 1.6vw, 20px) clamp(20px, 3vw, 32px);
  text-align: center;
}
.guide__note__lead {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: clamp(17px, 2.1vw, 21px);
  line-height: 1.55;
  letter-spacing: 0.02em;
}
.guide__note a {
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}
.guide__note a:hover,
.guide__note a:focus-visible { background: var(--hl); color: var(--on-ink); }

/* 附註跟目錄一樣撐滿版寬，不再窄成一張浮在空白裡的卡片；文字本身仍留在
   閱讀寬內，只有卡片邊界跟著整份目錄的寬度走。 */
.guide__note--band {
  max-width: none;
  text-align: left;
}
.guide__note--band .guide__note__lead {
  max-width: var(--read);
  margin-left: 0;
  margin-right: 0;
}

/* 窄螢幕：序號與箭頭並排成一條「頁碼行」，章名與提問整段落到下面 */
@media (max-width: 720px) {
  .guide-card {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 4px 14px;
    padding-left: 0;
    padding-right: 0;
    align-items: start;
  }
  .guide-card__num { grid-row: 1; align-self: center; }
  .guide-card__go { grid-column: 2; grid-row: 1; justify-self: end; }
  .guide-card__text { grid-column: 1 / -1; }
  /* 內距歸零後，hover 那塊黃要左右各撐出去一點，才不會貼著字。
     用兩枚位移陰影（不帶擴散）只往左右長，上下的細線不會被蓋掉。 */
  @media (hover: hover) {
    .guide-card:hover { box-shadow: 12px 0 0 var(--hl-ink), -12px 0 0 var(--hl-ink); }
  }
}

@media (prefers-reduced-motion: reduce) {
  .guide-card,
  .guide-card__num,
  .guide-card__go svg { transition: none; }
}

/* ============================================================
   作品牆 — 兩排反向跑馬燈・點擊翻牌
   ============================================================
   進第一章之前的一段換氣：先看見「那些作品」，再看見「那些人」。

   為什麼是跑馬燈而不是一面靜止的牆：作品清單沒有排名，也不該有。
   讓它一直流過去，讀者看到的是一片持續經過的作品，而不是「第一名是誰」。
   兩排方向相反，BL 往左、百合往右 —— 兩種取向各走各的，同時在場。

   動起來的是 .works__track（裡面兩份一模一樣的 .works__group，
   往左推剛好一份的寬度就回到原點，所以接縫看不出來）。
   複製那一份、以及換算跑完一圈要幾秒，都由 main.js 依實際卡片數處理，
   HTML 只要寫一份卡片就好。

   停：滑鼠移上去、手指按住、鍵盤 focus 進來、有卡片翻開、捲出畫面 —— 都停。
   翻：卡片是真的 <button>，鍵盤可以 Tab 進去用 Enter 翻，一次只開一張。 */
.works-sec {
  border-top: var(--hair);
  padding: clamp(52px, 6.5vw, 88px) 0 clamp(56px, 7vw, 96px);
  /* 跟 .stock 同一種厚紙：這一段跟前後不一樣，用紙色說 */
  background-color: var(--kraft);
  background-image:
    radial-gradient(rgba(0, 0, 0, 0.075) 1px, transparent 1px),
    url('../img/paper.png');
  background-size: 7px 7px, auto;
  background-repeat: repeat, repeat;
}

.works-sec__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: clamp(28px, 3.6vw, 44px);
}
.works-sec__title {
  font-family: var(--font-round);
  font-weight: 900;
  font-size: clamp(26px, 4.2vw, 40px);
  line-height: 1.32;
  letter-spacing: 0.02em;
}
.works-sec__lede {
  max-width: var(--read);
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.95;
}

/* ---------- 兩排 ---------- */
.works {
  display: flex;
  flex-direction: column;
  gap: clamp(22px, 2.8vw, 36px);
}
.works__row {
  --work-w: clamp(158px, 16vw, 200px);
  /* 卡片高度算出來寫死，不靠 aspect-ratio。
     卡片是兩層 flex（track > group > work）裡的項目，flex 預設的 align-items: stretch
     會叫項目「撐滿這一行的交叉尺寸」，而這一行的高度又來自項目自己 ——
     用 aspect-ratio 的話這是一個循環，Chrome 解得出 4:3，WebKit 會把卡片拉成一整條。
     所以：高度直接由寬度算出來，並且在兩層 flex 都把 stretch 關掉。 */
  --work-h: calc(var(--work-w) * 4 / 3);
  --work-gap: clamp(12px, 1.4vw, 18px);
}
/* 排標籤跟正文切齊在同一條軸線上，卡片本身則是滿版流過去 */
.works__rowlabel {
  max-width: var(--page);
  margin: 0 auto 12px;
  padding: 0 var(--gutter);
}
/* 上下留一點空間給 hover 時浮起來的卡片，不然會被裁掉 */
.works__viewport {
  overflow: hidden;
  padding: 7px 0 9px;
  /* 橫向的手勢交給 main.js（按住拖動這一排），垂直的留給頁面自己捲 ——
     不寫這條的話手機上橫滑會被當成想捲頁面，拖不動。 */
  touch-action: pan-y;
}
.works__track {
  display: flex;
  align-items: flex-start;
  width: max-content;
  will-change: transform;
  animation: works-run var(--works-dur, 60s) linear infinite;
}
/* 第二份 group 由 main.js 複製進來；--works-span 就是一份的寬度 */
@keyframes works-run {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-1 * var(--works-span, 0px)), 0, 0); }
}
/* 反向：同一段動畫倒著播，等於從左往右流 */
.works__row[data-works-dir="right"] .works__track { animation-direction: reverse; }
.works__group {
  display: flex;
  align-items: flex-start;
  gap: var(--work-gap);
  padding-right: var(--work-gap);
}

/* 該停的時候 */
@media (hover: hover) {
  .works__row:hover .works__track { animation-play-state: paused; }
}
.works__row:focus-within .works__track,
.works__row.is-held .works__track,
.works__row.is-open .works__track,
.works__row.is-demo .works__track,
.works.is-idle .works__track { animation-play-state: paused; }

/* 正在被拖動：不要順手選到字，游標也換成「抓著」的樣子。
   卡片本身是 <button>，平常是 pointer —— 只有這個當下才蓋掉它。 */
.works__row.is-dragging {
  user-select: none;
  -webkit-user-select: none;
}
.works__row.is-dragging .work,
.works__row.is-dragging .work__face { cursor: grabbing; }

/* ---------- 一張卡片 ---------- */
.work {
  flex: 0 0 auto;
  width: var(--work-w);
  height: var(--work-h);
  padding: 0;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  perspective: 1000px;
  -webkit-tap-highlight-color: transparent;
}
.work:focus-visible {
  outline: 3px solid var(--hl-mark);
  outline-offset: 4px;
  border-radius: var(--r-card);
}
.work__inner {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.55s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.work.is-flipped .work__inner { transform: rotateY(180deg); }
/* 進場的那一次翻牌示範（見 main.js 的 initWorks）：跟真的翻牌同一個動作，
   但走另一個 class —— is-flipped 那一組還綁著 aria-pressed 與「一次只開一張」的狀態，
   示範不是讀者按的，不該混進去。 */
.work.is-demo .work__inner { transform: rotateY(180deg); }

.work__face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: var(--hair);
  border-radius: var(--r-card);
  background: var(--cream);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  transition: box-shadow 0.2s;
}
/* 浮起來用的是印刷的實心影子，不是柔邊陰影 —— 跟整份報告同一個世界 */
@media (hover: hover) {
  .work:hover .work__face--front { box-shadow: 5px 5px 0 -1px var(--ink); }
}

/* 正面：圖滿版，名字壓在下面一條帶子裡。
   圖片一律置中裁切；某張圖的重點不在正中間時，直接在那個 <img> 上加
   style="object-position: center 20%" 之類的就好，不必動這裡。 */
.work__img {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  display: block;
  object-fit: cover;
}
/* 還沒有圖的卡片：斜線網紋 + 方塊記號，一眼就看得出這張還沒補圖 */
.work__ph {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-size: 11px;
  letter-spacing: 0.16em;
  opacity: 0.5;
  background-image: repeating-linear-gradient(
    45deg, transparent 0 7px, rgba(128, 128, 128, 0.16) 7px 8px);
}
.work__ph i {
  display: block;
  width: 9px;
  height: 9px;
  background: var(--ink);
}
/* 名字帶：給一個最小高度，讓同一排卡片的圖片下緣大致落在同一條線上
   （名字長到換行的那幾張還是會高一點，那是內容本身的事） */
.work__caption {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 3px;
  min-height: 56px;
  padding: 10px 12px 11px;
  border-top: var(--hair);
  background: var(--paper-texture);
}
.work__name {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 15px;
  line-height: 1.4;
  letter-spacing: 0.02em;
  overflow-wrap: anywhere;
}
.work__sub {
  font-size: 11px;
  line-height: 1.55;
  opacity: 0.68;
  overflow-wrap: anywhere;
}

/* 背面：同色系的薄調，色相由上緣那條實色帶子撐住。
   原本這一面是一整塊 BL 紫／百合橘、字壓黑。色塊本身夠亮，黑字對它也過得了
   AA（紫 6.5:1、橘 8.4:1），但這一面的字是 13px 的中文、還要塞三、四行：
   中文筆畫密，壓在飽和色塊上讀起來就是吃力 —— 數字過關不等於讀得下去。
   所以油墨退成紙上一層薄調（字對底 15:1 以上），身份改由上緣 6px 的實色帶子講。
   帶子是背景的一層，不是多一個元素，所以不佔垂直空間、也不會逼 fitBackText
   把字再縮一階。正面的圖與名字帶完全不動。 */
.work__face--back {
  --work-ink: var(--hl);
  --work-wash: rgba(250, 197, 93, 0.18);
  --work-line: var(--hl-mark);
  transform: rotateY(180deg);
  justify-content: space-between;
  gap: 12px;
  padding: 16px 15px 15px;
  /* 三層：上緣色帶、薄調、紙。薄調底下一定要墊紙色 —— 半透明疊半透明會糊掉 */
  background:
    linear-gradient(var(--work-ink) 0 6px, transparent 6px),
    linear-gradient(var(--work-wash), var(--work-wash)),
    var(--cream);
  color: var(--ink);
}
.works__row--bl .work__face--back {
  --work-ink: var(--bl);
  --work-wash: rgba(122, 134, 241, 0.18);
  --work-line: #3f4790;
}
.works__row--gl .work__face--back {
  --work-ink: var(--gl);
  --work-wash: rgba(237, 137, 89, 0.18);
  --work-line: #8a4416;
}
/* 這裡的字級是「最大值」，不是定值 —— main.js 量過之後，話比較長的卡片會自己
   降一到兩階（見 initWorks 的 fitBackText）。所以之後補的引言不管長短都不會爆出卡片，
   也不必為了排版去修剪受訪者的話。overflow: hidden 是最後一道保險。 */
.work__change {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  font-size: 13px;
  line-height: 1.75;
  overflow-wrap: anywhere;
}
.work__tags {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
/* 標籤：底已經是薄調，白色小膠囊會消失在裡面 —— 改成描一圈同色系的線，
   字跟著紙走（--ink）。線用的是壓深過的同色相（--work-line，
   與 .quote--paper 署名同一組值）：純色相畫在薄調上只有 2:1，等於沒畫。 */
.work__tag {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1;
  padding: 6px 8px;
  border: 1px solid var(--work-line);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink);
}

/* ---------- 不跑動的情況 ----------
   偏好減少動態、或腳本沒跑到：兩排改成可以自己左右捲，內容一樣看得完。 */
@media (prefers-reduced-motion: reduce) {
  .works__track { animation: none; }
  .work__inner { transition: none; }
  .works__viewport {
    overflow-x: auto;
    scroll-snap-type: x proximity;
    /* 這個情境下橫向捲動是瀏覽器自己的（連慣性也是它的），
       所以把手勢還給它 —— main.js 的拖動在這裡也不會裝上去。 */
    touch-action: auto;
  }
  .work { scroll-snap-align: center; }
}
html:not(.js) .works__track { animation: none; }
html:not(.js) .works__viewport { overflow-x: auto; touch-action: auto; }
/* 無 JS 時翻不了牌，所以正反面直接上下並列，粉絲那句話不會不見 */
html:not(.js) .work { height: auto; }
html:not(.js) .work__inner {
  display: flex;
  flex-direction: column;
  height: auto;
  transform: none;
}
html:not(.js) .work__face {
  position: static;
  backface-visibility: visible;
  transform: none;
}
html:not(.js) .work__face--front { border-bottom: 0; border-radius: var(--r-card) var(--r-card) 0 0; }
html:not(.js) .work__face--back { border-radius: 0 0 var(--r-card) var(--r-card); }
html:not(.js) .work__img,
html:not(.js) .work__ph { height: var(--work-w); }

/* 手機：卡片反而要放大一點。可視寬度變小，但背面那句話的字數沒變 ——
   卡片太小的話長的那幾句會被自動縮到看不清楚，寬一點比多露出半張卡片重要。 */
@media (max-width: 640px) {
  .works__row { --work-w: clamp(166px, 48vw, 196px); }
  .work__change { font-size: 12.5px; line-height: 1.7; }
}

/* ============================================================
   群體聲音 — 一句一句 pop 進來，最後一片同時喊話（[data-shout]）
   ============================================================
   內文說「不少朋友回饋」，但「不少」沒有形狀。這一塊把那些話原封不動攤在一片
   舞台上，一句一句 pop 出來、越來越快，讀完畫面上是十四個人同時在喊。

   位置與姿態全部由 HTML 上的 inline 自訂屬性決定（跟長條圖的 --v 同一個做法）：
   --x／--y 中心座標、--s 字級倍率、--rot 傾角、--w 最大寬度。
   所以要搬動、增刪句子都只改 HTML，這裡不必動。

   顏色只用百合橘：三句最短最衝的印成實色油墨（喊得最大聲的先被看到），
   其餘是紙上一層薄調 —— 薄調的底一定要不透明，因為這些話本來就會互相疊到，
   兩層半透明疊起來會糊成一塊，讀不出是兩句話。

   DOM 順序＝pop 順序，所以後出場的自然疊在先出場的上面，不必發 z-index。 */
.shout {
  --shout-wash: rgba(237, 137, 89, 0.1);
  --shout-line: rgba(237, 137, 89, 0.5);
  display: flex;
  flex-direction: column;
  gap: var(--space-evidence);
}

/* 這一塊是上一段話的證據，不是新的概念 —— 間距跟圖表、並排比較同一級 */
.block > .shout { margin-top: calc(var(--space-evidence) - var(--space-component)); }

.shout__stage {
  position: relative;
  /* 高度跟著版面寬度長：字級是 px、位置是 %，寬螢幕上字大了、話會多折一行，
     舞台不跟著高一點的話最下面那幾排就會互相壓到。
     字級在 1500px 左右就頂到 15.5px 的上限、舞台寬度也停在 1144px，
     所以高度到 690px 就不必再長。 */
  min-height: clamp(640px, 22vw + 358px, 690px);
}

.shout__item {
  position: absolute;
  left: var(--x, 50%);
  top: var(--y, 50%);
  margin: 0;
  width: max-content;
  max-width: var(--w, 32%);
  padding: 0.5em 0.85em;
  border: 1px solid var(--shout-line);
  border-radius: 12px;
  /* 薄調疊在紙上：紙色墊在下面，這一塊才不透明（見上面的說明） */
  background:
    linear-gradient(var(--shout-wash), var(--shout-wash)),
    var(--cream);
  font-family: var(--font-sans);
  font-size: calc(clamp(13.5px, 0.5vw + 8px, 15.5px) * var(--s, 1));
  font-weight: 500;
  line-height: 1.85;
  letter-spacing: 0.03em;
  color: var(--ink);
  transform: translate(-50%, -50%) rotate(var(--rot, 0deg));
}

/* 實色油墨版：壓在百合橘上的字恆黑（全站規則），跟 .quote--gl 同一套 */
.shout__item--ink {
  background: var(--gl-ink);
  border-color: var(--gl-ink);
  color: var(--on-ink);
  font-weight: 700;
}

/* 選配的收束句：目前沒有用，喊完就停在那一片畫面上。要接一句研究者的話，
   在 .shout__stage 後面補一行 <p class="shout__close" data-shout-close>，
   它會在全部到位之後才浮上來（時間點在 main.js）。上緣那道短橘條跟
   .quote--paper 同一個記號，讀者一眼就知道說話的人換了。 */
.shout__close {
  max-width: 34em;
  margin-inline: auto;
  text-align: center;
  font-size: clamp(15.5px, 1.5vw, 18.5px);
  line-height: 2.05;
  letter-spacing: 0.04em;
}
.shout__close::before {
  content: "";
  display: block;
  width: 26px;
  height: 5px;
  margin: 0 auto 18px;
  background: var(--gl);
}

/* ---------- 動態：只在有 JS 時才藏起來（見 main.js 的 12.） ---------- */
.js .shout__item {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(var(--rot, 0deg)) scale(0.82);
  /* 尾巴帶一點過衝，才像「彈」出來而不是「淡」出來 */
  transition: opacity 0.3s ease, transform 0.42s cubic-bezier(0.22, 1.45, 0.38, 1);
}
.js .shout__item.is-in {
  opacity: 1;
  transform: translate(-50%, -50%) rotate(var(--rot, 0deg)) scale(1);
}
.js .shout__close {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.js .shout__close.is-in { opacity: 1; transform: none; }

/* ---------- 窄螢幕：沒有舞台可以散開，就排成一列一列錯開 ----------
   而且把五句最長的收起來（HTML 上的 data-shout-extra）。手機上九句就已經很擠，
   十四句會疊成一團誰都讀不到 —— JS 會自己跳過收起來的那幾句，時間軸跟著縮短。 */
@media (max-width: 860px) {
  .shout__stage {
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 14px;
  }
  .shout__item {
    position: static;
    max-width: min(100%, 25em);
    /* 手機上字級倍率要收斂：舞台上放大是為了在一片話裡分出主次，
       單欄排列已經有先後順序，再放那麼大只會把一句話撐成三行。 */
    font-size: calc(clamp(13.5px, 3.4vw, 15.5px) * min(var(--s, 1), 1.15));
    transform: rotate(var(--rot, 0deg));
  }
  .shout__item:nth-child(even) { align-self: flex-end; }
  .shout__item[data-shout-extra] { display: none; }

  .js .shout__item { transform: rotate(var(--rot, 0deg)) scale(0.82); }
  .js .shout__item.is-in { transform: rotate(var(--rot, 0deg)); }
}

/* ============================================================
   猜猜看 — 兩題選擇題，選完才翻開答案（.quiz）
   ============================================================
   性別分佈那張圖，讀者大多「以為自己知道答案」——BL 是女生看的，百合是男生看的。
   直接把長條圖攤開，他只會點頭走掉；先要他押一個答案，數字才會撞到他。
   所以這一塊擋在 1-3 前面：兩題、四個選項、押完才公布。

   為什麼印在牛皮紙（.stock）上：全站只有這裡要求讀者「做一件事」而不是「讀一段字」。
   換一種紙 = 換一種語氣，跟作品牆、換紙敘事同一套語彙，不必再多發明一個框。

   無 JS 時：選項是普通按鈕（點了沒反應），答案 .quiz__ans 直接攤在下面，
   一個字都不少 —— 跟名詞解釋（.gloss）同一個作法。JS 進來才加 .is-ready 收起答案。 */
.quiz__head {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.quiz__kicker {
  align-self: flex-start;
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.14em;
  border: var(--hair);
  border-radius: var(--r-pill);
  padding: 5px 14px;
}
/* ---------- 一題 ----------
   題目、選項、答案貼在一起（同一件事）；題與題之間才有一條 14% 黑的細線。
   細線上方的空隙由 .stock__content 的 gap 給（component），下方自己補 para ——
   兩邊差不多，線才會落在兩題中間，而不是黏在上一題的屁股上。 */
.quiz__q {
  display: flex;
  flex-direction: column;
  gap: 16px;
  border-top: var(--hair-soft);
  padding-top: var(--space-para);
}
.quiz__ask {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: clamp(17px, 2.2vw, 21px);
  line-height: 1.75;
  letter-spacing: 0.02em;
  max-width: var(--read);
}
.quiz__ask .tag { margin-right: 10px; vertical-align: 0.12em; }

/* ---------- 四個選項 ----------
   四欄等寬排開，讀者一眼看完全部再決定；窄螢幕落成兩欄（見最下方）。 */
.quiz__opts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}
.quiz__opt {
  border: var(--hair);
  border-radius: var(--r-btn);
  background: var(--cream);
  color: var(--ink);
  padding: 15px 10px;
  font-family: var(--font-round);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), background-color 0.2s ease;
}
.quiz__opt:hover { transform: translateY(-2px); background: var(--hl); }
.quiz__opt:active { transform: translateY(0); }
.quiz__opt:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* 押完之後：整組不再可點，正解填黃、押錯的那顆退成淺灰。
   「對／錯」不只靠顏色 —— ::before 補一個勾／叉的字符，色盲與黑白列印都讀得到。 */
.quiz__q[data-quiz-done] .quiz__opt {
  cursor: default;
  pointer-events: none;
  opacity: 0.45;
}
.quiz__q[data-quiz-done] .quiz__opt:hover { transform: none; background: var(--cream); }
.quiz__opt.is-correct {
  opacity: 1;
  background: var(--hl-ink);
  color: var(--on-ink);
}
.quiz__opt.is-wrong {
  opacity: 1;
  background: var(--mute-ink);
  color: var(--on-ink);
}
.quiz__opt.is-correct::before,
.quiz__opt.is-wrong::before {
  margin-right: 7px;
  font-weight: 900;
}
.quiz__opt.is-correct::before { content: "✓"; }
.quiz__opt.is-wrong::before { content: "✕"; }
/* 只給輔助科技的文字：看得到的地方不佔位，螢幕閱讀器照樣念得到。
   隨堂考的勾與叉是 CSS 畫的（聽不到），縮圖牆的說明也走這個 —— 通用工具類。 */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- 答案 ---------- */
.quiz__ans {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: var(--read);
  padding-left: 16px;
  border-left: 3px solid var(--hl-mark);
}
.quiz__verdict {
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.04em;
}
.quiz__verdict:empty { display: none; }
.quiz__fact { font-size: 15px; line-height: 1.95; }

/* ---------- 動態：只在有 JS 時才藏起來（見 main.js 的 11.） ---------- */
.quiz.is-ready .quiz__ans { display: none; }
.quiz.is-ready .quiz__q[data-quiz-done] .quiz__ans { display: flex; }

/* 掀開時帶一段短的展開，讀者才知道「剛剛那一下」有結果 */
@media (prefers-reduced-motion: no-preference) {
  .quiz.is-ready .quiz__q[data-quiz-done] .quiz__ans {
    animation: quiz-reveal 0.45s cubic-bezier(0.16, 1, 0.3, 1) both;
  }
}
@keyframes quiz-reveal {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* ---------- 押完之後：其他讀者怎麼猜（.quiz__poll） ----------
   正解公布完，讀者心裡還有一個問題沒被回答：「所以只有我猜錯嗎？」
   這排長條就是回答那一句 —— 不是新的資料，是一面鏡子，讓他看見自己站在人群的哪裡。

   刻意沿用圖表區那套 .bar / .fill：全站已經教過讀者「長條＝比例」這個語彙，
   在這裡再發明一種只會多一種要學的東西。差別只在尺度縮小一號，
   而且外框是細線圓角而非實線 —— 它是註腳，不是證據。

   自己押的那一項填黃（.fill--hl）並加粗標籤，其餘退成淺灰（.fill--mute）：
   顏色在這裡的意思不是「對／錯」，而是「你」。對錯已經由上面的按鈕講完了。

   數字由 JS 從 /.netlify/functions/vote 取回；沒有 JS 或後端不通時整塊不存在，
   讀者少的只是這面鏡子，正解一個字都不會少。 */
.quiz__poll {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-width: var(--read);
  padding: 16px 18px 14px;
  border: var(--hair-soft);
  border-radius: var(--r-card);
}
.quiz__poll-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 14px;
  padding-bottom: 10px;
  margin-bottom: 4px;
  border-bottom: var(--hair-soft);
  font-family: var(--font-round);
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.1em;
}
.quiz__poll-n {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 11px;
  letter-spacing: 0.08em;
  opacity: 0.6;
}
.quiz__poll .bar {
  grid-template-columns: 108px minmax(0, 1fr) 58px;
  gap: 12px;
  padding: 7px 0;
}
.quiz__poll .bar__track { height: 14px; }
.quiz__poll .bar__val { font-size: 14px; }

/* 長條是讀者押完之後才插進 DOM 的，趕不上 .reveal 那一次進場動畫，
   所以 .fill 原本的 scaleX 收展在這裡用不上 —— 改成從 0 掃出寬度。
   起點的 0 寫在這裡，實際寬度由 JS 在下一幀補上（見 main.js 的 11.）。 */
.js .quiz__poll .fill {
  transform: none;
  width: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .js .quiz__poll .fill { transition: width 0.85s cubic-bezier(0.16, 1, 0.3, 1); }
}

/* ---------- 窄螢幕：四欄擠不下，落成兩欄 ---------- */
@media (max-width: 640px) {
  .quiz__opts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 長條的標籤自己佔一整列，數字才留得住 */
  .quiz__poll { padding: 14px 15px 12px; }
  .quiz__poll .bar { grid-template-columns: minmax(0, 1fr) 56px; gap: 5px 10px; padding: 9px 0; }
  .quiz__poll .bar__label { grid-column: 1 / -1; }
}
