/* ==========================================================================
   pize-grid.css — 全站共用的网格背景行为（聚光 / 视差 / 呼吸）

   任何页面只要满足两点即可获得完全一致的效果：
     1. DOM 里有一个 .pize-grid 元素（首页与文档页都已具备）
     2. <head> 里引入本文件与 pize-grid.js

   设计约束：
   - 渐进增强。JS 未执行时 :root 上没有 .pize-grid-live，本文件的 :root 规则
     不生效，页面回落成原来的静态网格，不依赖脚本。编辑器画布把
     .pize-grid-live 写在网格节点上，不依赖 iframe 的 html class。
   - 不与 app/globals.css 冲突。:root.pize-grid-live 选择器特指度高于
     globals 的 .pize-grid，无论加载顺序谁先都能覆盖。
   - 只动 opacity / background-position / mask，全部落在合成层，不触发重排。
     绝不逐格生成 DOM：72px 网格在整页尺度上有近两万个交点。
   ========================================================================== */

:root {
  /* 网格几何与配色，取自 app/globals.css 的现有值 */
  --pize-grid-cell: 72px;
  --pize-grid-line: rgba(9, 9, 11, 0.045);
  --pize-grid-wash: rgba(9, 9, 11, 0.04);

  /* 视差系数：网格以内容一半的速度滚动 */
  --pize-parallax: 0.5;

  /* 聚光。紫线刻意压得很淡：正文是 #52525b，亮一点就开始跟文字抢注意力 */
  --pize-spot-radius: 230px;
  --pize-spot-line: rgba(124, 58, 237, 0.2);
  --pize-spot-max: 0.62;
  --pize-spot-fade: 900ms;

  /* 由 pize-grid.js 写入。--pize-mx/my 是文档坐标，不是视口坐标 */
  --pize-scroll: 0px;
  --pize-mx: 50vw;
  --pize-my: 40vh;
  /* Canvas helper writes 0/1; homepage script still toggles .pize-spot-on */
  --pize-spot-opacity: 0;
}

/* 元素本身只保留顶部那层渐变（不参与视差，否则页首会露出接缝） */
:root.pize-grid-live .pize-grid,
.pize-grid.pize-grid-live {
  background-image: linear-gradient(180deg, var(--pize-grid-wash), transparent 22%);
  opacity: 1;
}

/* ---------- 两层共用的几何 ----------

   聚光层与线网层的定位方式、盒子、单元格尺寸、视差位移完全相同，只有颜色不同。
   紫线因此逐像素落在灰线上 —— 它点亮的就是背景里已经存在的那些线，
   而不是另画一套再去对齐。这是结构上的保证，不依赖任何补偿计算。            */

:root.pize-grid-live .pize-grid::before,
:root.pize-grid-live .pize-grid::after,
.pize-grid.pize-grid-live::before,
.pize-grid.pize-grid-live::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* 图案是 72px 周期的，位移取模后无缝，视差不会「用完」 */
  background-position: 0 calc(var(--pize-scroll) * var(--pize-parallax));
}

/* ---------- 线网：视差 + 呼吸 ---------- */

:root.pize-grid-live .pize-grid::before,
.pize-grid.pize-grid-live::before {
  background-image:
    repeating-linear-gradient(90deg, var(--pize-grid-line) 0 1px, transparent 1px var(--pize-grid-cell)),
    repeating-linear-gradient(180deg, var(--pize-grid-line) 0 1px, transparent 1px var(--pize-grid-cell));
  opacity: 0.8;
  animation: pize-grid-breathe 14s ease-in-out infinite;
  will-change: opacity, background-position;
}

/* 呼吸：0.8 上下浮动约 ±0.1，折算成线条实际透明度是 0.032–0.041，
   足以让页面「活着」，又不到会被注意到的程度 */
@keyframes pize-grid-breathe {
  0%, 100% { opacity: 0.72; }
  50% { opacity: 0.92; }
}

/* ---------- 聚光：点亮光标附近的那几条线 ---------- */

:root.pize-grid-live .pize-grid::after,
.pize-grid.pize-grid-live::after {
  background-image:
    repeating-linear-gradient(90deg, var(--pize-spot-line) 0 1px, transparent 1px var(--pize-grid-cell)),
    repeating-linear-gradient(180deg, var(--pize-spot-line) 0 1px, transparent 1px var(--pize-grid-cell));
  /* 遮罩圆心用文档坐标，与图层同一坐标空间；边缘收得很软，避免出现一个圆形轮廓 */
  -webkit-mask-image: radial-gradient(
    circle var(--pize-spot-radius) at var(--pize-mx) var(--pize-my),
    #000 0%, rgba(0, 0, 0, 0.55) 34%, rgba(0, 0, 0, 0.16) 62%, transparent 84%);
  mask-image: radial-gradient(
    circle var(--pize-spot-radius) at var(--pize-mx) var(--pize-my),
    #000 0%, rgba(0, 0, 0, 0.55) 34%, rgba(0, 0, 0, 0.16) 62%, transparent 84%);
  opacity: calc(var(--pize-spot-opacity, 0) * var(--pize-spot-max));
  transition: opacity var(--pize-spot-fade) ease;
  /* will-change 不支持 mask-image，去掉以避免无效声明 */
  will-change: opacity;
}

:root.pize-grid-live.pize-spot-on .pize-grid::after {
  opacity: var(--pize-spot-max);
}

/* ---------- 降级 ---------- */

/* 触屏与粗指针设备：pointermove 只在按下时才有，聚光会变成「点一下才亮」的怪行为 */
@media (hover: none), (pointer: coarse) {
  :root.pize-grid-live .pize-grid::after,
  .pize-grid.pize-grid-live::after { display: none; }
}

/* 与站点既有的 prefers-reduced-motion 开关保持同一套行为：
   停呼吸、停视差、去聚光，只留静态网格 */
@media (prefers-reduced-motion: reduce) {
  :root {
    --pize-parallax: 0;
  }

  :root.pize-grid-live .pize-grid::before,
  .pize-grid.pize-grid-live::before {
    animation: none;
    opacity: 0.8;
  }

  :root.pize-grid-live .pize-grid::after,
  .pize-grid.pize-grid-live::after { display: none; }
}
