/* ═══════════════════════════════════════════════════════════
   年轮同款交互动画
     ① 柔光呼吸：悬停那张，硬边淡出、换成两圈用**照片自己主色**的光，
        外圈缓慢明灭（一呼一吸）—— 规格与年轮页 .car-fig 完全一致
     ② 悬停让位：只改 transform 变量，布局不动、卡片宽高不变
        （网格与上传页交给 hover-grid.js 算量；立牌/扇面写在 layouts.js 里）
     ③ Flip to Detail：点封面 → 飞到屏幕中心 → 绕 Y 翻到背面（引擎在 flip-detail.js）
   本文件被**相册页与上传页**一起加载：
     · 相册页三样都用（网格 .cell / 立牌 .lay-tile / 扇面 .t-fan）
     · 上传页只用前两样（.tile）——那边点击仍是"放点／删除"的活，先生 2026-09-24 定的
   年轮页（rings.html）**不加载本文件**，它自己那一份在 rings.css 里，两边互不影响。
   ═══════════════════════════════════════════════════════════ */

/* ── ① 柔光呼吸 ──
   ⚠️ 光必须能漫出卡片的框：`.cell` / `.lay-tile` / `.tile` 原来都是 overflow:hidden，
      光被裁在框里就成了一根压在照片上的白线（年轮那边也踩过同一个坑：
      折射/光效只能在大面上用，被封在小盒子里就是坏的画面）。
      所以裁切下沉到内层 .cell-clip / .lay-clip / .tile-clip，卡片本身 overflow:visible。 */
.cell,
.lay-tile,
.tile { overflow: visible; }
.cell-clip,
.lay-clip,
.tile-clip {
  position: absolute; inset: 0; border-radius: inherit; overflow: hidden;
}
.cell-clip { pointer-events: none; }
.cell-clip img { pointer-events: auto; }
/* ⚠️ 上传页的 .tile-clip **不设** pointer-events:none —— 里面的「放点／删除」两个按钮
   还要先生点得着（祥在相册那边图省事写了 none，那是那边没有按钮可点）。 */

.cell::after,
.lay-tile::after,
.tile::after {
  content: ''; position: absolute; inset: -3px; border-radius: calc(var(--r-tile, 12px) + 2px);
  pointer-events: none; opacity: 0;
  border: 2.5px solid rgba(255, 255, 255, .95);
  box-shadow: 0 0 8px 1px rgba(255, 255, 255, .7),
    0 0 24px 5px var(--glow, rgba(166, 79, 99, .38)),
    inset 0 0 14px rgba(255, 252, 251, .45);
  filter: blur(5px);
  transition: opacity 320ms cubic-bezier(.22, .7, .25, 1);
}
.cell::before,
.lay-tile::before,
.tile::before {
  content: ''; position: absolute; inset: -6px; border-radius: calc(var(--r-tile, 12px) + 5px);
  pointer-events: none; opacity: 0;
  box-shadow: 0 0 32px 10px var(--glow2, rgba(166, 79, 99, .5));
  filter: blur(9px);
  transition: opacity 380ms cubic-bezier(.22, .7, .25, 1);
}
.cell.hot::after,
.lay-tile.hot::after,
.tile.hot::after { opacity: 1; animation: glowBreathIn 2600ms cubic-bezier(.45, 0, .55, 1) infinite; }
.cell.hot::before,
.lay-tile.hot::before,
.tile.hot::before { opacity: .95; animation: glowBreathOut 2600ms cubic-bezier(.45, 0, .55, 1) infinite; }
/* 外圈胀得多一点、里圈少一点，光就像一呼一吸地往外漾 */
@keyframes glowBreathOut { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
@keyframes glowBreathIn { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.028); } }
@media (prefers-reduced-motion: reduce) {
  .cell.hot::after, .cell.hot::before,
  .lay-tile.hot::after, .lay-tile.hot::before,
  .tile.hot::after, .tile.hot::before { animation: none; }
}
/* 只给"正在动的那几张"提升合成层（给几十张都挂 will-change 会掉到 7fps） */
.cell.anim, .lay-tile.anim, .tile.anim { will-change: transform; }

/* ── ② 悬停让位：变量驱动的位移（hover-grid.js 只写变量，过渡交给 CSS）── */
/* 相册网格 .cell 与上传页 .tile 共用同一套量（--px/--py/--csc） */
.cell,
.tile {
  transform: translate3d(var(--px, 0px), var(--py, 0px), 0) scale(var(--csc, 1));
  transition: transform 300ms cubic-bezier(.22, .7, .25, 1), box-shadow 280ms ease, border-color 280ms ease;
}
.cell.hot,
.tile.hot { --csc: 1.045; --py: -6px; z-index: 5; }
/* 按下那一下的反馈：也用同一套变量写（原来在 ui.css 里是一条固定的 transform，
   与 .hot 抢同一个属性）。写在这条**之后**，同优先级下后写的赢，于是按住时是"沉下去"，
   松开又回到抬起 —— 不再有第二个属性主人。 */
.tile:active { --csc: 1; --py: -2px; }
/* 上传页原本有一条 `.tile:hover { transform: translateY(-3px) scale(1.015) }`（写在 ui.css 里），
   已删——同一个属性两处管会打架，抬升一律由 .hot 说了算（见文件头注释）。 */
html[data-quality="smooth"] .cell,
html[data-quality="smooth"] .tile { transition-duration: 200ms; }
html[data-quality="smooth"] .cell.hot,
html[data-quality="smooth"] .tile.hot { --csc: 1.015; --py: -3px; }
.lay-stage.hover-lite .cell.hot { --csc: 1; --py: -6px; }

/* 扇面：沿弧滑开（--dth 是角度，由 layouts.js 按当前开合算）＋ 抬起 */
.t-fan {
  transform:
    translate(-50%, -50%)
    rotate(calc(var(--th, 0deg) + var(--dth, 0deg) + var(--rot, 0) * 1deg))
    translateY(calc(-1 * var(--R, 320px)))
    rotate(calc((var(--th, 0deg) + var(--dth, 0deg) + var(--rot, 0) * 1deg) * -1))
    rotate(calc(var(--th, 0deg) * .62 + var(--lean, 0deg)))
    translateY(var(--hy, 0px))
    scale(var(--sc, 1));
  transition: transform 300ms cubic-bezier(.22, .7, .25, 1);
}
.t-fan.hot { --hy: -12px; --sc: 1.06; z-index: 3000 !important; }
html[data-quality="smooth"] .t-fan { transition-duration: 200ms; }
html[data-quality="smooth"] .t-fan.hot { --hy: -6px; --sc: 1.025; }
.lay-stage.hover-lite .t-fan { transition-duration: 180ms; }
.lay-stage.hover-lite .t-fan.hot { --hy: -12px; --sc: 1; }
@media (prefers-reduced-motion: reduce) { .t-fan { transition-duration: 110ms; } }

/* 立牌那张的悬停姿态原在 layouts.css（.t-tilt.hot），这里只补它的柔光已由上面的 ::after/::before 接管 */

/* ── ③ Flip to Detail ──
   样式与年轮页那一份逐条对齐（rings.css 的 #flip 段），只把"背景模糊层"从写死的
   #carousel 换成由 JS 传入的 bgEl（网格传 #stream、版式传 .lay-stage）。 */
/* 飞走之后原位不再显示那张照片（同一张不能同时出现在两处）。
   ⚠️ .lay-tile 带着 `animation: layIn ... forwards`，动画会压过普通声明的 opacity，
      所以这里必须 !important —— 否则立牌/扇面点开后原位那张还在（年轮那边是 figure
      没有入场动画，所以它不需要这一条）。 */
.flip-hidden { opacity: 0 !important; pointer-events: none; }
.cell.flip-hidden, .lay-tile.flip-hidden { transition: opacity 220ms ease; }

/* 3D 卡片手感：倾斜期间卡片带一条 200ms linear 的过渡（与"原作"同一曲线）；
   没有这个类时不加过渡，免得和翻转动画抢同一个属性。 */
#flip.tilting .flip-card { transition: transform 200ms linear; }

#flip { position: fixed; inset: 0; z-index: 900; display: none; }
#flip.on { display: block; }
.flip-scrim {
  position: absolute; inset: 0; background: rgba(68, 48, 47, .42);
  opacity: 0;                                      /* 浓度由 flip-detail.js 的 bgRide() 驱动 */
}
/* 舞台：left/top/width/height 由 JS 按"卡片当前所在的位置与大小"写入 —— 这就是 FLIP 的起点 */
.flip-stage {
  position: absolute; perspective: 1400px;
  transform-origin: 50% 50%; will-change: transform;
}
.flip-card {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: rotateY(0deg); transform-origin: 50% 50%;
  will-change: transform;
}
.flip-face {
  position: absolute; inset: 0; margin: 0; overflow: hidden; border-radius: 14px;
  backface-visibility: hidden; -webkit-backface-visibility: hidden;
}
/* 正面：照片（整张按比例，不裁不拉）——只占上半，下半留给"拓展面板"，
   面板在背面，所以飞行途中看不见（正面是干净的）。 */
.flip-front {
  left: 0; right: 0; top: 0; bottom: auto; height: var(--ph, 400px);
  background: #f7ece9 center / contain no-repeat;
  border: 1px solid rgba(255, 255, 255, .8);
  box-shadow: 0 26px 64px rgba(96, 60, 58, .34);
}
.flip-front img { width: 100%; height: 100%; object-fit: contain; display: block; }
/* 背面 = 同一张照片（上半，比例不变）+ **在照片底部加出来的拓展面板**（下半） */
.flip-back {
  transform: rotateY(180deg);
  background: transparent;
  box-shadow: 0 26px 64px rgba(96, 60, 58, .34);
}
/* ── 3D 卡片的「另一半」：内层元素浮在不同深度（先生 2026-09-24 夜要的）──
   ⚠️ 关键在下面第一行：`.flip-face` 原本带 `overflow: hidden`，而那是**分组属性** ——
      有它在，子元素的 translateZ 会被直接压平（3D 完全失效）。
      所以把背面这一面放开裁切、并开启 preserve-3d，照片与面板才浮得起来。
      （背面里的照片与面板各自都带圆角，放开裁切不会漏边。）
   ⚠️ 只在"翻层停在台面上"时（.tilting）才浮：静止时归零，不干扰飞行与翻转。
   ⚠️ 第二处坑：preserve-3d 必须**一路不断**。`.flip-exif` / `.flip-ctrl` 原先没开，
      于是药丸和按钮的 translateZ 在它们那一层就被压平了 —— 算出来的矩阵里 Z 明明是 22/46，
      屏幕上却几乎不动（实测只挪 0.85px）。整条链开齐，视差才真的落到像素上。 */
.flip-back, .flip-meta, .flip-exif, .flip-ctrl { transform-style: preserve-3d; }
.flip-back { overflow: visible; }
/* 视差强度就拧这三颗旋钮（先生要"再大一点"只改这三个数；透视 1400px 不动，
   免得连带改了开合翻转的手感）。
   比例仍是 按钮 > 标题 > 药丸：按钮是伸手要点的，浮得最靠前。
   代价写在明处：Z 越大，元素被透视放得越大（Z=84 时约 +6.4%），这是真 3D 的必然。 */
.flip-stage {
  --z-btn: 84px;
  --z-title: 62px;
  --z-exif: 40px;
}
#flip.tilting .flip-when { transform: translateZ(var(--z-title)); }
#flip.tilting .flip-exif span { transform: translateZ(var(--z-exif)); }
#flip.tilting .flip-ctrl button { transform: translateZ(var(--z-btn)); }
.flip-when, .flip-exif span { transition: transform 200ms linear; }
/* 按钮自己本来有 background/color 的过渡，这里把 transform 并进去，别把它挤掉 */
.flip-ctrl button { transition: transform 200ms linear, background 180ms ease, color 180ms ease; }
.flip-backimg {
  position: absolute; left: 0; right: 0; top: 0; height: var(--ph, 400px);
  width: 100%; object-fit: cover; display: block;
  background: #f7ece9; border-radius: 14px 14px 0 0;
  border: 1px solid rgba(255, 255, 255, .8);
}
/* 实况照片那段小视频：与背面图同一个位置、同一套圆角（不能让它参与流式布局） */
video.flip-live {
  position: absolute; left: 0; right: 0; top: 0; height: var(--ph, 400px); width: 100%;
  object-fit: cover; display: block; background: #f7ece9;
  border-radius: 14px 14px 0 0; border: 1px solid rgba(255, 255, 255, .8);
}
.flip-meta {
  position: absolute; left: 0; right: 0; top: var(--ph, 400px); bottom: 0;
  display: flex; flex-direction: column; justify-content: center; gap: 12px; padding: 18px 20px;
  background: linear-gradient(160deg, var(--bg-1), var(--bg-0));
  border: 1px solid var(--stroke); border-top: 0; border-radius: 0 0 14px 14px;
}
.flip-when { margin: 0; font-size: 13px; color: var(--text-2); font-variant-numeric: tabular-nums; user-select: text; }
.flip-when b { color: var(--text); font-weight: 700; font-size: 16px; }
.flip-exif { display: flex; flex-wrap: wrap; gap: 7px; }
.flip-exif span {
  padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 600;
  color: var(--text-2); background: rgba(255, 252, 251, .92);
  border: 1px solid var(--stroke); font-variant-numeric: tabular-nums;
}
.flip-exif span.cam { color: var(--warm); border-color: rgba(156, 90, 70, .35); }
.flip-ctrl { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.flip-ctrl button {
  font: inherit; font-size: 13px; min-height: 44px; min-width: 44px; padding: 8px 16px;
  border-radius: 999px; cursor: pointer; color: var(--text-2);
  background: rgba(255, 252, 251, .92); border: 1px solid var(--stroke-hi);
  transition: background 180ms ease, color 180ms ease;
}
.flip-ctrl button:hover, .flip-ctrl button:focus-visible { background: var(--a1); color: var(--on-accent); border-color: transparent; }
.flip-ctrl button:disabled { opacity: .4; cursor: default; }
/* 实况那颗按钮沿用相册页的暖色描边 */
.flip-ctrl button.live-btn {
  color: var(--warm); background: rgba(240, 162, 74, .12);
  border-color: rgba(240, 162, 74, .45); font-weight: 700;
}
.flip-ctrl button.live-btn:hover { background: rgba(240, 162, 74, .24); color: var(--warm); border-color: rgba(240, 162, 74, .6); }
/* 站长专属那颗（相册页递进来的"删除这一张"，2026-10-06）：同族的按钮，只把颜色压成玫红。
   墙的世界里 --danger 已经指向 --wl-rose，所以跟着主题走，不用另写一套。 */
.flip-ctrl button.flip-extra {
  color: var(--danger); background: rgba(178, 58, 72, .08);
  border-color: rgba(178, 58, 72, .38); font-weight: 700;
}
.flip-ctrl button.flip-extra:hover, .flip-ctrl button.flip-extra:focus-visible { background: var(--danger); color: #fff; border-color: transparent; }
.flip-ctrl button.flip-extra[disabled] { opacity: .5; }
.flip-close {
  position: fixed; right: 22px; top: 18px; z-index: 2;
  width: 44px; height: 44px; border-radius: 999px; cursor: pointer; font-size: 18px;
  color: var(--a1); background: rgba(255, 252, 251, .94); border: 1px solid rgba(122, 90, 86, .16);
}
.flip-close:hover, .flip-close:focus-visible { background: var(--a1); color: var(--on-accent); border-color: transparent; }
/* 动效期间背景柔和下来：只模糊 JS 指定的那一层（顶栏与导航条保持清楚，只被压暗） */
body.flipping { cursor: default; }
