/* Senxe — architecture brief.
   版式移植自 podium.global 的 WORK 索引（ProjectList）。下面凡是带「原版」注释
   的数值都是从它的 chunk 里量出来的，不是估的：
     0y15hfs1xi6x..css  → 栅格、行高、过渡、渐变
     081f64dmupv9q.js   → 悬停两级状态、opacity .2、160ms 延迟、scale(1.015)
   字体不跟：用站上自己的 Anton / IBM Plex Mono，页面因此仍是同一个嗓音。 */

/* 字体声明、共用 token 与盒模型重置在 base.css，brief.html 先引它再引本文件 */

:root {
  --text: #F1F3EE;
  --rule: #cacaca;   /* 原版分隔线 */
  --pixel: #d9d9d9;  /* 原版线两端的方点 */
  --ease: cubic-bezier(.16, 1, .3, 1); /* 原版 --ease-out-expo */

  /* 原版所有尺寸都是 calc(100vw / 151.2 * N)，N 以 1512px 宽的设计稿为基准。
     照抄这个式子，比例就与原版一致而与本站 16px 的 rem 基准无关 */
  --u: calc(100vw / 151.2);
  --grid-margin: clamp(1.2rem, .78rem + 1.07vw, 2.4rem);
  --grid-gutter: clamp(1.6rem, 1.32rem + .71vw, 2.4rem);
  /* 原版行高 6.8u、上边距 11.6u。它只有 8 行、且上方要让开更高的菜单；本页 10 行，
     照抄会让最后三行掉到折线以下（1512x801 实测总高 906 > 801）。行高改成同时受
     视口高约束，上边距按本站更矮的导航收到 7u —— 只有这两个数没照抄 */
  --row-h: min(calc(var(--u) * 6.8), 7vh);
  --panel-top: calc(var(--u) * 7);
  /* 原版 26–36rem，钉在视口底边。它的列表永远在滚，那条渐变是用来盖住滚上来的
     内容的；本页十行一屏放得下，同样的高度只会把最后几行压成灰的。
     这里收成 4rem 的一道提示，并且锚在列表自己的底边（不是视口底边），
     只在还有内容没露出来时由 brief.js 打开 */
  --gradient-h: 4rem;

}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-optical-sizing: auto; /* Fraunces 是可变字：大字号自动取 display 的 opsz，
                                与首页 style.css 的 body 同一处理 */
  -webkit-font-smoothing: antialiased;
  min-height: 100svh;
  overflow: hidden; /* 列表自己滚，页面不滚（原版同样） */
}
::selection { background: var(--accent); color: var(--bg); }
a { color: inherit; text-decoration: none; }

/* ---------- nav（与首页同一套） ---------- */
.topnav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  padding: calc(1.6rem + env(safe-area-inset-top, 0px)) max(1.5rem, env(safe-area-inset-right, 0px)) 1.6rem max(1.5rem, env(safe-area-inset-left, 0px));
  pointer-events: none;
}
.topnav .brand, .topnav .nav-links { pointer-events: auto; }
.topnav .brand svg { height: 17px; width: auto; display: block; fill: var(--text); }
/* 与左侧列表标题同款 Syne 800。Syne 本身就宽，字距从等宽的 .28em 收到 .12em，
   否则全大写 + 宽字 + 宽字距会散得读不成一个词 */
/* line-height 必须写死 1.7：首页 style.css 的 body 是 1.7，这里的 body 没写、
   继承的是 normal。同样 11px 的 CONTACT，行盒一个 18.7px 一个 13.2px，
   而导航是 align-items:center —— 两页之间字就差了约 2px，站标也跟着错开 */
.nav-links { display: flex; gap: 1.8rem; font-family: "Syne", var(--font); font-weight: 800; font-size: 11px; line-height: 1.7; letter-spacing: 0.12em; text-transform: uppercase; }
.nav-links a { color: hsl(0 0% 100% / .62); transition: color .2s ease; }
.nav-links a:hover { color: #fff; }

/* ---------- 两层：列表 z10 / 底部渐变 z20（原版还有一层 z0 的预览图，已去掉） ---------- */
.brief { position: fixed; inset: 0; }

/* ---------- 右侧说明（悬停模式） ----------
   原来列表后面有一块预览图（podium 的做法），十张图各带一种调色，和站上的黑、灰白、
   荧光绿对不上。换成右侧第 9–12 栏的一段大字说明，说明跟着当前行上下走（brief.js 算
   位置），读的顺序是先看标题、再往右读说明。
   进页面时列表在正中；第一次悬停后（.is-reading）列表滑到左边第 1–7 栏、左缘与站标
   对齐，右侧才出说明。两种状态列表都是 7 栏宽，只靠平移切换，所以是一段连贯的滑动。
   只在真有悬停的桌面宽度上成立，由 brief.js 给 .brief 加 .has-reader；
   没有这个类时（窄屏、触屏、无脚本）说明照旧留在每行中间那一栏 */
.reader { display: none; }
.has-reader .panel-col {
  grid-column: 1 / span 7;
  /* 居中 = 向右平移 2.5 栏；一栏的步长 = (视口宽 − 两侧边距 + 一道栏距) / 12 */
  transform: translateX(calc((100vw - 2 * var(--grid-margin) + var(--grid-gutter)) / 12 * 2.5));
  transition: transform .7s var(--ease);
}
.has-reader.is-reading .panel-col { transform: none; }
.has-reader .reader {
  display: block;
  grid-column: 9 / span 4; grid-row: 1; align-self: start;
  opacity: 0;
  /* 淡入晚 .2s：列表刚开始往左滑时右边还压着它的尾巴，等它让开再出字 */
  transition: opacity .58s var(--ease) .2s, transform .48s var(--ease);
  will-change: transform;
}
.has-reader .reader.placing { transition: opacity .58s var(--ease) .2s; } /* 第一次出现直接落到当前行 */
.has-reader .reader.on { opacity: 1; }
.reader-num { font-family: var(--mono); font-size: .7rem; letter-spacing: .14em; text-transform: uppercase; color: hsl(0 0% 100% / .6); margin-bottom: .9rem; }
.reader-desc { font-family: var(--font); font-size: clamp(1.35rem, 2.1vw, 2.3rem); line-height: 1.22; color: var(--text); }
.has-reader .row-content { grid-template-columns: minmax(0, 1fr) 4rem; }
/* 行内说明只在视觉上收起：不能用 display:none，读屏会连同右侧阅读区（aria-hidden）
   一起读不到。绝对定位后它也不占网格，标题和序号不受影响 */
.has-reader .row-content .desc {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- 列表 ---------- */
.panel {
  position: relative; z-index: 10;
  height: 100%;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--grid-gutter);
  /* 原版下边距 12.4u。它列表长、永远在滚，留白无所谓；本页要让十行 + 尾链
     一屏装下（装下了才轮不到那条渐变去压最后一行），收到 5u */
  padding: var(--panel-top) var(--grid-margin) calc(var(--u) * 5);
  overflow: hidden;
}
/* 标题与列表必须同属一个网格项，否则 .panel-head 会被自动排到第 1 栏
   （1/12 宽），正文会窄到一行一个词 */
.panel-col {
  grid-column: 3 / span 8;   /* 原版 md:col-start-3 md:col-span-8 */
  min-height: 0;
  display: flex;
  flex-direction: column;
  position: relative;        /* 底部渐变锚在这里，不是视口 */
}
.list-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  margin-inline: -4px; padding-inline: 4px; /* 给方点留出溢出的 4px */
}
.list-scroll::-webkit-scrollbar { display: none; }

.panel-head { margin-bottom: calc(var(--u) * 3.2); }
/* 返回就是这行小标题本身：箭头在左，整行是一个链接 */
.back { display: inline-flex; align-items: baseline; gap: 0.55rem; }
.back-arrow {
  font-family: var(--mono); font-size: 0.7rem; line-height: 1;
  color: hsl(0 0% 100% / .5);
  transition: color .2s ease, transform .2s var(--ease);
}
.kicker {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: hsl(0 0% 100% / .5);
  transition: color .2s ease;
}
.back:hover .back-arrow { color: #fff; transform: translateX(-3px); }
.back:hover .kicker { color: #fff; }
.topnav a:focus-visible, .back:focus-visible, .row:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 5px;
}
.row:focus-visible { outline-offset: -2px; }

.list { list-style: none; }
.row { position: relative; height: var(--row-h); }

/* 分隔线：0.5px 线 + 两端 4×4 方点（原版的三件套） */
.divider {
  position: absolute; top: 0; left: -4px; right: -4px; height: 4px;
  pointer-events: none;
  transition: opacity .48s var(--ease);
}
.divider.bottom { top: auto; bottom: 0; }
.divider .line { position: absolute; left: 4px; right: 4px; top: 2px; height: 0.5px; background: var(--rule); transform-origin: 50% 50%; }
.divider .px { position: absolute; top: 0; width: 4px; height: 4px; background: var(--pixel); }
.divider .px.l { left: 0; }
.divider .px.r { right: 0; }

.row-content {
  height: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 28% 4rem; /* 标题 / 说明 / 序号
     —— Syne 比 Anton 宽得多，说明栏从 34% 让到 28% 给标题腾地方 */
  column-gap: clamp(1.6rem, 2.4vw, 2.4rem);
  align-items: center; align-content: center;
  transform: translateY(2px);                     /* 原版 .project-list-row-content */
  transition: opacity .48s var(--ease);           /* 原版 .project-list-hover-fade */
}
.mask { overflow: hidden; }                        /* 原版 .project-list-text-mask */
.mask .inner { display: block; }
/* 行标题：Syne 800 全大写。
   Syne 天生就宽（单字约 1.76:1），不需要 scaleX —— 之前那道 1.3 是给 Anton
   补宽度用的，窄字硬拉会让竖干变粗而横画不变，这里不再需要。
   字号与 preview-demo 对齐：clamp(20px, 2.2vw, 34px) / weight 800。
   注意这与首页字带的 Anton 不是同一款：字带只能用 Anton（Syne 铺进那个盒子
   要纵拉 5.91 倍，横画会粗成竖干的六倍，见 tools/make-title-svg.py），
   所以站上会同时存在两款展示字 —— 这是明知的取舍，不是疏漏 */
.row-content h2 {
  font-family: "Syne", var(--font);
  font-weight: 800; text-transform: uppercase;
  /* 字号被最长的两词标题卡住：CULTURE INTERFACE 在 Syne 800 下 33px 要 601px，
     而标题栏只有 496px，会折行、撞进分隔线（行高是定值）。
     nowrap 保证一行，字号按最窄的桌面宽度定 */
  font-size: clamp(15px, 1.78vw, 28px); line-height: 1;
  letter-spacing: 0;
  white-space: nowrap;
  width: max-content;
  max-width: 100%;
}/* 说明文字：默认在 CSS 里是可见的 —— 无脚本 / 窄屏 / 触屏都读得到全文。
   桌面开了悬停之后（.has-reader）每行的说明收起，改由右侧阅读区显示当前行那一句，
   见上方「右侧说明」 */
.desc {
  font-size: clamp(0.82rem, .95vw, 1rem); line-height: 1.35;
  color: hsl(0 0% 100% / .78);
  transition: opacity .58s var(--ease);
}
.num { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.1em; text-align: right; color: hsl(0 0% 100% / .6); }

/* 悬停时当前行留 1、其余压到 .2 —— 那个 .2 由 brief.js 写成行内 opacity
   （原版同样是行内 style），这里只负责过渡曲线，见上方 .row-content / .divider */


/* 底部渐变（原版 .project-list-gradient-h 的第二条，两段式更深）。
   默认关着：列表装得下时它没有存在的理由，只会压暗最后几行 */
.gradient-h {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 20;
  height: var(--gradient-h);
  pointer-events: none;
  opacity: 0;
  transition: opacity .3s var(--ease);
  background: linear-gradient(#0000 0%, #0000001f 22%, #00000094 58%, #000000eb 84%, #000 100%);
}
.gradient-h.on { opacity: 1; }

/* 触屏平板同样不能依赖悬停；短横屏也让正文自然滚动，避免把说明挤进定高行。 */
@media (max-width: 900px), (max-height: 500px), (hover: none), (pointer: coarse), (pointer: none) {
  body { overflow-x: hidden; overflow-y: auto; }
  .brief { position: static; }
  .gradient-h { display: none; }
  .panel {
    display: block; height: auto; overflow: visible;
    padding: calc(6.5rem + env(safe-area-inset-top, 0px)) max(var(--grid-margin), env(safe-area-inset-right, 0px)) calc(4rem + env(safe-area-inset-bottom, 0px)) max(var(--grid-margin), env(safe-area-inset-left, 0px));
  }
  .list-scroll { overflow: visible; margin-inline: 0; padding-inline: 0; }
  .row { height: auto; padding: 1.6rem 0; }
  .row-content { grid-template-columns: minmax(0, 1fr) auto; row-gap: .6rem; transform: none; }
  .row-content h2 {
    grid-column: 1; width: auto; white-space: normal;
    font-size: clamp(18px, 2.2vw, 28px); line-height: 1.15;
    overflow-wrap: break-word;
  }
  .num { grid-column: 2; }
  .desc { grid-column: 1 / -1; font-size: 1rem; line-height: 1.45; }
  /* 这一档开始整页自己滚（body overflow:auto），固定导航又没有底色：
     站标与 CONTACT 会一路压在列表上，读不出来也点不准。与首页同样处理，
     窄屏改成跟着页面滚走的静态头 */
  .topnav { position: absolute; }

  /* 触摸热区扩到 44px，做法与首页 style.css 同一套：透明 ::after 只吃事件、
     不占布局，字号与位置一个像素不动。站标 17px、CONTACT 19px、返回链接
     15px，都远低于指尖的最小可靠尺寸 */
  /* .back 要额外抬一层：它的热区下半会伸进第一行 .divider 的范围，
     分隔线在它之上时热区被截到 38px。伪元素是透明的，抬层不改观感 */
  .topnav .brand, .nav-links a, .back { position: relative; }
  .back { z-index: 2; }
  .topnav .brand::after,
  .nav-links a::after,
  .back::after {
    content: "";
    position: absolute;
    left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    min-width: 44px; min-height: 44px;
    width: 100%; height: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .reader, .panel-col, .row-content, .divider, .desc { transition-duration: 0s; transition-delay: 0s; }
}
