/* ==========================================================================
   动效层：关键帧与进场动画
   --------------------------------------------------------------------------
   性能约定（很重要，改动时请遵守）：
   1. 只动 transform / opacity / filter，这三者走显卡合成，不触发重排。
   2. 元素进场用 IntersectionObserver 加类名，绝不在 scroll 事件里逐帧读布局。
   3. 动画播完由 JS 摘掉 will-change，避免图层长期驻留吃显存。
   4. 尊重系统的「减弱动态效果」设置。
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. 关键帧
   -------------------------------------------------------------------------- */

@keyframes tide-noise-shift {
	0%   { transform: translate3d(0, 0, 0); }
	20%  { transform: translate3d(-3%, 2%, 0); }
	40%  { transform: translate3d(2%, -3%, 0); }
	60%  { transform: translate3d(-2%, -2%, 0); }
	80%  { transform: translate3d(3%, 1%, 0); }
	100% { transform: translate3d(0, 0, 0); }
}

@keyframes tide-caret {
	0%, 49%   { opacity: 1; }
	50%, 100% { opacity: 0; }
}

@keyframes tide-hint-run {
	0%   { transform: translateY(0); opacity: 0; }
	35%  { opacity: 1; }
	100% { transform: translateY(300%); opacity: 0; }
}

@keyframes tide-slide-in {
	from {
		opacity: 0;
		transform: translateX(24px);
	}
	to {
		opacity: 1;
		transform: translateX(0);
	}
}

/* 头像外圈光环的呼吸感 */
@keyframes tide-breathe {
	0%, 100% {
		transform: scale(1);
		opacity: 0.45;
	}
	50% {
		transform: scale(1.045);
		opacity: 0.95;
	}
}

/* 404 大数字的缓慢浮动 */
@keyframes tide-float {
	0%, 100% { transform: translateY(0); }
	50%      { transform: translateY(-14px); }
}

@keyframes tide-toast-in {
	from {
		opacity: 0;
		transform: translateY(18px) scale(0.94);
	}
	to {
		opacity: 1;
		transform: translateY(0) scale(1);
	}
}

@keyframes tide-toast-out {
	to {
		opacity: 0;
		transform: translateY(10px) scale(0.96);
	}
}

@keyframes tide-spin {
	to { transform: rotate(360deg); }
}

/* 渐变色文字的流光：让标题的渐变缓慢流动 */
@keyframes tide-shimmer {
	0%   { background-position: 0% 50%; }
	100% { background-position: 200% 50%; }
}

/* 骨架屏（图片加载前的占位） */
@keyframes tide-skeleton {
	0%   { background-position: -140% 0; }
	100% { background-position: 240% 0; }
}

@keyframes tide-draw-line {
	from { transform: scaleX(0); }
	to   { transform: scaleX(1); }
}

/* --------------------------------------------------------------------------
   2. 滚动进场
   -------------------------------------------------------------------------- */

[data-tide-reveal] {
	opacity: 0;
	transform: translate3d(0, var(--tide-reveal-y, 28px), 0);
	transition:
		opacity var(--tide-dur-reveal) var(--tide-ease-out) var(--tide-delay, 0s),
		transform var(--tide-dur-reveal) var(--tide-ease-out) var(--tide-delay, 0s),
		filter var(--tide-dur-reveal) var(--tide-ease-out) var(--tide-delay, 0s);
	will-change: opacity, transform;
}

/* 需要更强的「镜头对焦」感时加 data-tide-reveal="blur"；
   模糊滤镜开销比纯位移大，所以只给少量关键元素用。 */
[data-tide-reveal="blur"] {
	filter: blur(5px);
}

[data-tide-reveal].is-revealed {
	opacity: 1;
	transform: translate3d(0, 0, 0);
	filter: blur(0);
	/* 动画结束立刻交还图层，避免长时间占用显存 */
	will-change: auto;
}

/* 横向进场的位移必须限幅在容器左右内边距之内。
   .tide-container 的 padding-inline 是 clamp(1rem, 4vw, 2.5rem)，
   而 min(位移, 4vw) 在任何视口下都不会超过这个内边距，
   因此元素在「未进场」状态下也绝不会把页面撑出横向滚动。 */
[data-tide-reveal="left"] {
	transform: translate3d(calc(-1 * min(var(--tide-reveal-y, 28px), 4vw)), 0, 0);
}

[data-tide-reveal="right"] {
	transform: translate3d(min(var(--tide-reveal-y, 28px), 4vw), 0, 0);
}

[data-tide-reveal="scale"] {
	transform: scale(0.94);
}

/* 首屏不做进场动画，否则首帧内容不可见，观感反而变差 */
.tide-hero [data-tide-reveal] {
	animation: tide-hero-in calc(1s * var(--tide-speed)) var(--tide-ease-out) both;
	opacity: 1;
	transform: none;
	filter: none;
	will-change: auto;
	transition: none;
}

@keyframes tide-hero-in {
	from {
		opacity: 0;
		transform: translate3d(0, 26px, 0);
		filter: blur(8px);
	}
	to {
		opacity: 1;
		transform: translate3d(0, 0, 0);
		filter: blur(0);
	}
}

.tide-hero [data-tide-delay="1"] { animation-delay: 0.08s; }
.tide-hero [data-tide-delay="2"] { animation-delay: 0.18s; }
.tide-hero [data-tide-delay="3"] { animation-delay: 0.28s; }
.tide-hero [data-tide-delay="4"] { animation-delay: 0.38s; }
.tide-hero [data-tide-delay="5"] { animation-delay: 0.48s; }

/* --------------------------------------------------------------------------
   3. 首页 Hero 点缀
   -------------------------------------------------------------------------- */

/* 首屏标题的渐变流光 */
.tide-hero__title em {
	background-size: 200% auto;
	animation: tide-shimmer calc(9s * var(--tide-speed)) linear infinite;
}

/* --------------------------------------------------------------------------
   4. 卡片微交互
   -------------------------------------------------------------------------- */

/* 3D 倾斜由 JS 写 --tide-tilt-x / --tide-tilt-y */
.tide-tilt-enabled .tide-card,
.tide-tilt-enabled .tide-work,
.tide-tilt-enabled .tide-album-card {
	transform-style: preserve-3d;
}

.tide-tilt-enabled .tide-card.is-tilting,
.tide-tilt-enabled .tide-work.is-tilting,
.tide-tilt-enabled .tide-album-card.is-tilting {
	transform: perspective(900px) rotateX(var(--tide-tilt-x, 0deg)) rotateY(var(--tide-tilt-y, 0deg)) translateY(-6px);
	transition: transform 0.12s linear;
}

/* 卡片内层元素做轻微反向位移，强化层次 */
.tide-tilt-enabled .tide-card__media.is-tilting-media {
	transform: translateZ(24px);
}

/* --------------------------------------------------------------------------
   5. 图片加载完成后的淡入，避免「啪」地弹出来
   -------------------------------------------------------------------------- */

.tide-card__img,
.tide-work__media img,
.tide-album-card__media img,
.tide-masonry__item img {
	background: linear-gradient(
		100deg,
		var(--tide-surface) 30%,
		var(--tide-surface-2) 50%,
		var(--tide-surface) 70%
	);
	background-size: 240% 100%;
	animation: tide-skeleton 1.6s linear infinite;
}

.tide-card__img.is-loaded,
.tide-work__media img.is-loaded,
.tide-album-card__media img.is-loaded,
.tide-masonry__item img.is-loaded {
	animation: none;
	background: none;
}

/* --------------------------------------------------------------------------
   6. 加载指示器（图片懒加载出错或异步请求时用）
   -------------------------------------------------------------------------- */

.tide-spinner {
	width: 22px;
	height: 22px;
	border: 2px solid var(--tide-border-strong);
	border-top-color: var(--tide-accent);
	border-radius: 50%;
	animation: tide-spin 0.8s linear infinite;
}

/* --------------------------------------------------------------------------
   7. 全局动效开关
   -------------------------------------------------------------------------- */

/* 后台把「开启滚动进场动画」关掉时，页面直接静态呈现 */
body.tide-no-anim [data-tide-reveal],
body.tide-no-anim .tide-hero [data-tide-reveal] {
	opacity: 1;
	transform: none;
	filter: none;
	animation: none;
	transition: none;
	will-change: auto;
}

body.tide-no-anim *,
body.tide-no-anim *::before,
body.tide-no-anim *::after {
	animation-duration: 0.01ms !important;
	animation-iteration-count: 1 !important;
	transition-duration: 0.01ms !important;
}

/* 系统级「减弱动态效果」：无条件遵从，这是无障碍底线 */
@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}

	[data-tide-reveal] {
		opacity: 1 !important;
		transform: none !important;
		filter: none !important;
	}

	.tide-cursor,
	.tide-hero__hint-track::after,
	body::after {
		display: none;
	}
}

/* --------------------------------------------------------------------------
   8. 按压反馈
   --------------------------------------------------------------------------
   iOS 上所有可点元素在按下的瞬间都会缩一点，松开再弹回。触屏没有 hover，
   这个反馈就是「我收到了」的唯一信号，比变色更重要。
   只给小尺寸元素用：卡片本身有悬停抬升，再叠缩放会显得抖。 */

.tide-btn.is-pressed,
.tide-iconbtn.is-pressed,
.tide-top.is-pressed {
	transform: scale(0.952);
	transition: transform 0.1s var(--tide-ease-ios);
}

/* 触屏上按得更狠一点：没有指针悬停做铺垫，反馈要更明确 */
@media (hover: none) {
	.tide-btn.is-pressed,
	.tide-iconbtn.is-pressed,
	.tide-top.is-pressed {
		transform: scale(0.94);
	}
}

/* --------------------------------------------------------------------------
   9. 跨页过渡（View Transitions API）
   --------------------------------------------------------------------------
   Chrome 126+ / Safari 18+ 支持同源「跨文档」过渡：点链接离开页面时，
   浏览器会拿旧页快照和新页快照做一次原生过渡，观感接近 App 的页面切换，
   而不是白屏一闪。Firefox 目前忽略这几条，行为与之前完全一致。
   只在真机上才看得出差别，属于纯粹的渐进增强。 */

@view-transition {
	navigation: auto;
}

@keyframes tide-vt-leave {
	to {
		opacity: 0;
		transform: scale(0.992);
	}
}

@keyframes tide-vt-enter {
	from {
		opacity: 0;
		transform: translate3d(0, 16px, 0) scale(0.995);
	}
}

::view-transition-old(root) {
	animation: tide-vt-leave calc(0.26s * var(--tide-speed)) var(--tide-ease-ios-in) both;
}

::view-transition-new(root) {
	animation: tide-vt-enter calc(0.44s * var(--tide-speed)) var(--tide-ease-ios) both;
}

/* 系统开了减弱动态效果：不播过渡 */
@media (prefers-reduced-motion: reduce) {
	::view-transition-old(root),
	::view-transition-new(root) {
		animation: none;
	}
}

/* 站长在后台关掉动效时（body.tide-no-anim）也不播。
   ::view-transition 挂在根元素上，只能借 :has() 反查 body 的类名，
   所以整组规则包在 @supports 里，老浏览器直接跳过。 */
@supports selector(:has(*)) {
	html:has(body.tide-no-anim)::view-transition-old(root),
	html:has(body.tide-no-anim)::view-transition-new(root) {
		animation: none;
	}
}