/* ═══════════════════════════════════════════════════════════
   專案區塊 — sticky 線稿 + 捲動文字
   ═══════════════════════════════════════════════════════════ */

/* 描繪進度 0→1。註冊成真正的數字型別，mini 專案才能對它做轉場；
   scrub 的專案不設 transition，才能跟手指/滾輪即時同步、隨時反向。 */
@property --d {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

/* 收筆位置：內容中心走到畫面這個高度時，那一層剛好畫完。lineart.js 會讀這個值。
   放在這裡是因為它跟版面綁死 —— 桌機兩欄，文字有整個畫面高可用，中央就是 50%；
   手機單欄，上面 52svh 被釘住的線稿佔走了，真正的「中央」是剩下那段的中間。
   線稿高度改了，這個值要一起改，不然標題會滑到圖底下去。 */
:root { --draw-end: 0.5; }
@media (max-width: 62rem) { :root { --draw-end: 0.72; } }

.project {
  position: relative;
  padding-block: var(--sp-6);
}

.project__grid {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "visual head"
    "visual body";
  column-gap: var(--sp-4);
}

/* ── 釘住的線稿 ───────────────────────────────────────── */
.project__visual {
  grid-area: visual;
  position: sticky;
  top: 0;
  align-self: start;
  height: 100svh;
  display: grid;
  justify-items: center;
  align-content: center;
  gap: var(--sp-2);
}
.project__pin {
  position: relative;
  z-index: 1;                       /* 疊在 .project__visual 的光暈之上 */
  width: min(100%, 44rem, 76svh);
  aspect-ratio: 1;
  /* 最後一拍圖往前靠一點 —— 尺度上的重音，收尾才不會跟前三拍一樣平 */
  transform: scale(calc(1 + 0.08 * var(--s4, 0)));
}
/* 製圖紙墊在底下，線稿畫在上面 —— 兩張圖用同一個 viewBox，完全對齊 */
.project__pin > .sheet,
.project__pin > .lineart {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* ── 標題區 ───────────────────────────────────────────── */
.project__head {
  grid-area: head;
  display: grid;
  align-content: center;
  gap: var(--sp-2);
  min-height: 100svh;
  padding-block: var(--sp-4);
}
/* 抵達一個專案是一個「到站」的時刻，名字就該佔住畫面。
   原本用 --t-h2 跟其他小標同級，讀起來像文件的一個小節而不是一個章節。 */
.project__head h2 {
  font-size: clamp(2.5rem, 5vw, 4.5rem);
  text-wrap: balance;
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: -0.045em;
}
.project__meta {
  display: flex; gap: 0.6rem; align-items: baseline; flex-wrap: wrap;
}
/* 編號用強調色 —— 跟 hero 精選卡、bento 是同一個「第幾號」的語言 */
.project__meta .eyebrow:first-child { color: var(--accent); }
.project__meta .eyebrow + .eyebrow::before {
  content: "·";
  margin-right: 0.6rem;
  color: var(--ink-faint);
}
.project__tagline {
  font-size: var(--t-h3);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.015em;
  color: var(--ink-muted);
  text-wrap: pretty;
}
/* Apple 的一主一次：第一個連結是實心膠囊，其餘是描邊膠囊。
   HTML 不用改 —— 還是一排 <a>，順序決定誰是主要動作。 */
.project__links {
  display: flex; gap: 0.6rem; flex-wrap: wrap;
  margin-top: var(--sp-1);
}
.project__links a {
  display: inline-flex; align-items: center; gap: 0.35em;
  padding: 0.62em 1.15em;
  border-radius: 999px;
  font-size: var(--t-small);
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
  box-shadow: inset 0 0 0 1px #ffffff40;
  transition: background var(--dur-ui) var(--ease-out),
              transform var(--dur-tap) var(--ease-out);
}
.project__links a:hover { background: #ffffff14; }
.project__links a:active { transform: scale(0.97); }
.project__links a:first-child {
  background: var(--ink);
  color: #000;
  box-shadow: none;
}
.project__links a:first-child:hover { background: #fff; }
.project__links a span { opacity: 0.6; }

/* ── 四段內文，每一段對應線稿的一個生長階段 ─────────────── */
/* 尾巴要留一段空白：sticky 的線稿只能黏到「容器底部減自己的高度」為止，
   而最後一段是在它的內容走到畫面正中央時才收筆 —— 差的就是這半個畫面。
   不留的話，最後一段文字定位時線稿已經開始往上跑掉了。
   順帶好處：畫完的整張圖有一拍可以被完整看見，然後才換下一個專案。 */
.project__narrative { grid-area: body; position: relative; padding-bottom: 28svh; }

/* 高度刻意貼近「描繪一段所需的捲動距離」（約 0.42 個畫面高 + 半個內容高）。
   給多了，每段畫完後會空轉快半個畫面才輪到下一段；這裡只多留一點點，
   讓文字定位、線畫完之後有一小拍停頓可以讀，然後下一段就接上。 */
.project__stage {
  display: grid;
  align-content: center;
  gap: var(--sp-1);
  min-height: 62svh;
  padding-block: var(--sp-3);
}
/* 每一拍的內容外面包一層（由 site.js 加上）：
   材質面板要貼著內容，不是貼著整個 62svh 的格子。 */
.beat {
  display: grid;
  gap: var(--sp-1);
}

.project__stage h3 {
  display: grid; gap: 0.35rem;
  color: var(--ink);
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.03em;
}
.project__stage h3::before {
  content: counter(stage, decimal-leading-zero);
  font-size: var(--t-small);
  font-weight: 600;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}
.project__narrative { counter-reset: stage; }
.project__stage { counter-increment: stage; }

.project__stage p {
  color: var(--ink-muted);
  font-size: clamp(1.0625rem, 1.3vw, 1.1875rem);
  line-height: 1.6;
  letter-spacing: -0.005em;
}

/* 最後一段（結果）跟線稿的強調色呼應 */
.project__stage:last-child h3::before { color: var(--accent); }

/* ═══════════════════════════════════════════════════════════
   三種版面節奏
   ───────────────────────────────────────────────────────────
   同一個模組連跑六次，形式本身就不帶資訊了 —— 滾到第三個，
   讀者已經知道接下來會發生什麼。用 data-layout 在 section 上標一個字
   就換一種節奏，剪貼換順序的維護性完全不變。

     （不標）  split  ：線稿在左、文字在右。適合資訊密的圖。
     mirror          ：左右對調。整頁滾下來會是 Z 字形的節奏。
     focus           ：線稿置中放大並侵入文字欄，文字變窄、浮在圖上面，
                       用真的半透明材質 —— 這是全站唯一有層疊的地方。
   ═══════════════════════════════════════════════════════════ */

.project[data-layout="mirror"] .project__grid {
  grid-template-columns: 1fr 1.35fr;
  grid-template-areas:
    "head visual"
    "body visual";
}

.project[data-layout="focus"] .project__grid {
  grid-template-columns: 1fr minmax(0, 26rem);
  column-gap: 0;
}
/* 線稿欄往右長出去，鑽到文字底下 —— 有真的重疊，材質才有存在的理由 */
.project[data-layout="focus"] .project__visual { margin-right: -18rem; }
/* 88svh 會讓底下的進度點撞到導航膠囊。focus 的張力來自置中與重疊，
   不是單純更大，所以高度上限跟其他版面拉齊就好。 */
.project[data-layout="focus"] .project__pin { width: min(100%, 56rem, 78svh); }
.project[data-layout="focus"] .project__head { margin-left: -8rem; }
.project[data-layout="focus"] :is(.project__head, .project__narrative) {
  position: relative;
  z-index: 2;
}

/* 浮在線稿上的材質：模糊 + 半透明 + 上緣一道亮邊（光打在材質邊上）。
   只有 focus 用 —— 沒有重疊的地方就不該有材質，那只是裝飾。 */
.project[data-layout="focus"] .project__stage .beat {
  padding: var(--sp-4) var(--sp-3) calc(var(--sp-4) - 0.25rem);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, #1d1d1f 55%, transparent);
  box-shadow: inset 0 1px 0 #ffffff1f, inset 0 0 0 1px #ffffff12,
              0 30px 70px #0000008c;
  backdrop-filter: blur(30px) saturate(180%);
  -webkit-backdrop-filter: blur(30px) saturate(180%);
}
/* 浮在會變的背景上，文字要再清楚一點（vibrancy） */
.project[data-layout="focus"] .project__stage .beat p { color: #d2d2d7; }

/* 降低動態偏好：線稿一開始就是畫完的狀態，標題那一屏沒有「紙」可以讓位，
   完整的圖會直接壓在專案名字底下。focus 就收回自己的欄位、不再往文字欄鑽。 */
@media (prefers-reduced-motion: reduce) and (min-width: 62.0625rem) {
  .project[data-layout="focus"] .project__visual { margin-right: 0; }
  .project[data-layout="focus"] .project__head { margin-left: 0; }
}

@media (prefers-reduced-transparency: reduce) {
  .project[data-layout="focus"] .project__stage .beat {
    background: var(--bg);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* 手機：三種版面一律收回單欄。選擇器要跟上面 data-layout 那一組同級，
   才蓋得過去（所以這裡不能只寫 .project__grid）。 */
@media (max-width: 62rem) {
  .project[data-layout] .project__grid,
  .project .project__grid {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto 1fr;
    grid-template-areas: "head" "visual" "body";
    column-gap: 0;
  }
  /* 特異度要跟 .project[data-layout="focus"] 那組同級，不然負邊界會留著，
     線稿在手機上會被推出畫面外。 */
  .project[data-layout] .project__visual,
  .project .project__visual { margin-right: 0; }
  .project[data-layout] .project__head,
  .project .project__head { margin-left: 0; }
  .project[data-layout] .project__pin { width: min(100%, 18rem); }
  .project[data-layout="focus"] .project__stage .beat {
    padding: 0; background: none; border: 0; box-shadow: none;
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  .project__head { min-height: 0; padding-block: var(--sp-4) var(--sp-2); }
  /* 線稿貼在畫面上緣，文字從它底下滑過去 ——
     下緣用漸層遮罩淡出，避免出現一條硬切線。 */
  .project__visual {
    height: 52svh;
    gap: var(--sp-1);
    z-index: 2;
    background: var(--bg);
    -webkit-mask-image: linear-gradient(to bottom, #000 93%, transparent);
            mask-image: linear-gradient(to bottom, #000 93%, transparent);
  }
  .project__pin { width: min(100%, 22rem, 38svh); }
  .project__narrative { z-index: 1; padding-bottom: var(--sp-5); }
  /* focus 在桌機把文字抬到 z-index 2（要浮在線稿上面），那條選擇器特異度比上面高，
     手機會沿用下來 —— 跟 sticky 線稿同一層、又排在它後面，文字就蓋到圖上了。
     手機沒有重疊的設計，文字一律回到線稿底下。 */
  .project[data-layout="focus"] :is(.project__head, .project__narrative) { z-index: 1; }
  /* 單欄時文字不要垂直置中 —— 置中會在線稿和文字之間留一大塊空白 */
  .project__stage {
    min-height: 62svh;
    align-content: start;
    padding-block: var(--sp-2) var(--sp-4);
  }
}

/* ═══════════════════════════════════════════════════════════
   線稿本體
   ═══════════════════════════════════════════════════════════ */

.lineart {
  width: 100%; height: 100%;
  display: block;
  overflow: visible;
}

/* ⚠️ 這裡刻意「不」用 vector-effect: non-scaling-stroke。
   它會讓瀏覽器改用螢幕像素計算虛線圖樣，pathLength="1" 的正規化就失效，
   描繪動畫整個壞掉。要在縮放的群組裡維持線粗，改用下面的 --sw 倍率。 */
.lineart {
  --sw: 1;
}
.lineart * {
  fill: none;
  stroke: var(--stroke);
  stroke-width: calc(var(--w-line) * var(--sw));
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 每個階段吃對應的進度變數 */
.lineart [data-draw="1"] { --d: var(--s1, 0); }
.lineart [data-draw="2"] { --d: var(--s2, 0); }
.lineart [data-draw="3"] { --d: var(--s3, 0); }
.lineart [data-draw="4"] { --d: var(--s4, 0); }

/* 預設：沿著路徑一筆畫出來。
   --len 是 lineart.js 在首次繪製前量好的路徑長度（見那支檔案的註解），
   所以 --d 就是「已經畫出來的比例」，跟形狀實際多長無關。 */
.lineart [data-draw] :is(path, rect, circle, ellipse, line, polyline, polygon) {
  /* 間隔刻意比實線長 4 個單位，offset 再多推 2 個 —— 這樣 --d 為 0 時，
     整條路徑穩穩落在間隔正中間，不會停在 dash 與 gap 的交界上。
     停在交界上會因為浮點誤差畫出一段長度 0 的實線，配上圓端點就變成一個點：
     那就是「還沒開始畫就先看到一堆點」的成因。 */
  stroke-dasharray: var(--len, 1) calc(var(--len, 1) + 4);
  stroke-dashoffset: calc((var(--len, 1) + 2) * (1 - var(--d)));
}

/* ── 修飾類 ───────────────────────────────────────────────
   每條都寫成 :is(.x, .x *) —— 因為上面的 .lineart * 直接替每個圖形
   指定了 stroke / fill，繼承就被切斷了。只寫 .x 的話，掛在 <g> 上的
   修飾類傳不進裡面的圖形（症狀：整組該變橘的還是白的）。          */

/* 不描繪、改用淡入：虛線、雜訊軌跡、文字標籤 */
:is(.la-fade, .la-fade *) {
  stroke-dasharray: none !important; stroke-dashoffset: 0 !important;
}
.la-fade { opacity: var(--d); }

:is(.la-dash, .la-dash *) {
  stroke-dasharray: 4 5 !important; stroke-dashoffset: 0 !important;
  stroke: var(--stroke-dim);
}
.la-dash { opacity: var(--d); }

:is(.la-dim, .la-dim *)     { stroke: var(--stroke-dim); }
:is(.la-faint, .la-faint *) { stroke: var(--stroke-faint);
                              stroke-width: calc(var(--w-thin) * var(--sw)); }
:is(.la-thin, .la-thin *)   { stroke-width: calc(var(--w-thin) * var(--sw)); }

/* 強調：全站只有「結果」那一層用得到 */
:is(.la-accent, .la-accent *) { stroke: var(--accent);
                                stroke-width: calc(var(--w-bold) * var(--sw)); }
:is(.la-accent-thin, .la-accent-thin *) { stroke: var(--accent); }

:is(.la-fill, .la-fill *)               { fill: var(--stroke); stroke: none; }
/* 用底色當遮罩的形狀（桌面、外管、卡片）：遮罩要跟著描繪進度才出現。
   固定填底色的話，形狀還沒畫出來就已經在擋東西了 —— 在平黑底上看不出來，
   但線稿底下一有環境光（見 depth.css），它們會變成一塊塊深色的影子。 */
:is(.la-fill-bg, .la-fill-bg *)         { fill: var(--bg); fill-opacity: var(--d); }
:is(.la-fill-accent, .la-fill-accent *) { fill: var(--accent); stroke: none; }

/* 直接掛在圖形上的修飾類，特異度要高過祖先群組傳下來的 */
.lineart .la-dim   { stroke: var(--stroke-dim); }
.lineart .la-faint { stroke: var(--stroke-faint); stroke-width: calc(var(--w-thin) * var(--sw)); }
.lineart .la-thin  { stroke-width: calc(var(--w-thin) * var(--sw)); }
.lineart .la-accent { stroke: var(--accent); stroke-width: calc(var(--w-bold) * var(--sw)); }
.lineart .la-accent-thin { stroke: var(--accent); }
.lineart .la-fill  { fill: var(--stroke); stroke: none; }

/* ── 標籤文字 ───────────────────────────────────────────
   文字一律只用 fill 上色、絕不描邊 —— 11px 的字配上 1.4px 的邊會糊成一團。
   [class] 那條是為了壓過上面「直接掛在圖形上的修飾類」那一組的特異度。 */
.lineart text {
  fill: var(--ink-muted);
  stroke: none;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  opacity: var(--d);
}
.lineart text[class] { stroke: none; }

/* ── 標籤什麼時候出現 ─────────────────────────────────────
   標註是讓一張圖讀起來像「圖三」而不是「主視覺」的東西。
   所以先畫乾淨的結構，標籤等這一拍快走完才淡入 ——
   大部分的捲動過程畫面上只有線，資訊一點也沒少，只是晚到。

   而且下一拍開始時，上一拍的標籤退到 34%：
   任何時刻只有「現在在講的那組」是全亮的，其餘還讀得到但不搶。

   數字的意思：自己這一拍走到 62% 才開始浮現、92% 全滿（剛好在文字定位前
   就位），下一拍每推進 1，自己就退掉 0.66（退到 34%：直視還讀得到，但不搶）。 */
.lineart [data-draw="1"] text {
  opacity: calc(clamp(0, calc((var(--s1, 0) - 0.62) / 0.3), 1) * (1 - 0.66 * var(--s2, 0)));
}
.lineart [data-draw="2"] text {
  opacity: calc(clamp(0, calc((var(--s2, 0) - 0.62) / 0.3), 1) * (1 - 0.66 * var(--s3, 0)));
}
.lineart [data-draw="3"] text {
  opacity: calc(clamp(0, calc((var(--s3, 0) - 0.62) / 0.3), 1) * (1 - 0.66 * var(--s4, 0)));
}
.lineart [data-draw="4"] text {
  opacity: clamp(0, calc((var(--s4, 0) - 0.62) / 0.3), 1);
}
/* 輕量專案吃的是 --d（一次畫完），不是 --s1..4 */
.project-mini .lineart text {
  opacity: clamp(0, calc((var(--d) - 0.62) / 0.3), 1);
}
.lineart text.la-dim, .lineart text.la-faint { fill: var(--stroke-dim); }
.lineart text.la-accent, .lineart text.la-accent-thin { fill: var(--accent); }

/* 探索用的半透明軌跡群（大量疊加的失敗嘗試） */
:is(.la-swarm, .la-swarm *) {
  stroke: var(--stroke-dim);
  stroke-width: calc(var(--w-thin) * var(--sw));
  stroke-dasharray: none !important; stroke-dashoffset: 0 !important;
}
.la-swarm { opacity: calc(var(--d) * 0.42); }

/* ═══════════════════════════════════════════════════════════
   輕量專案（一圖一句）
   ═══════════════════════════════════════════════════════════ */

.minis {
  padding-block: var(--sp-6);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-4);
}
@media (max-width: 62rem) { .minis { grid-template-columns: 1fr; gap: var(--sp-5); } }

.project-mini {
  display: grid;
  gap: var(--sp-2);
  align-content: start;
}
.project-mini__art {
  /* 線稿裡「用底色當遮罩」的形狀要跟這塊材質同色，不是跟頁面同色 */
  --bg: #19191a;
  aspect-ratio: 320 / 220;
  border-radius: var(--r-lg);
  padding: var(--sp-3);
  background: linear-gradient(180deg, var(--bg-lift), var(--bg-raised) 75%);
}
.project-mini h3 {
  font-size: var(--t-h3);
  font-weight: 700;
  letter-spacing: -0.025em;
  margin-top: var(--sp-1);
}
.project-mini p { color: var(--ink-muted); font-size: var(--t-body); line-height: 1.55; }

/* 進場時一次畫完，不跟捲動綁在一起 */
.project-mini .lineart [data-draw] { --d: 0; }
.project-mini.is-in .lineart [data-draw] {
  --d: 1;
  transition: --d 1.4s var(--ease-out) var(--delay, 0s);
}

@media (prefers-reduced-motion: reduce) {
  .project-mini .lineart [data-draw] { --d: 1; }
  .project-mini.is-in .lineart [data-draw] { transition: none; }
}

/* 輕量專案的第二層（強調色那一筆）晚一點才畫，讓它有個收尾的感覺 */
.project-mini.is-in .lineart [data-draw="2"] {
  transition-delay: calc(var(--delay, 0s) + 0.45s);
}
