@import "tailwindcss"; @import "tw-animate-css"; @import "./shadcn-tailwind.css"; /* ───────────────────────── Tailwind configuration ───────────────────────── */ @custom-variant dark (&:is(.dark *), &:is([data-force-dark] *)); /* 悬停只给真鼠标:触屏(含被报告成鼠标的车机)点按后不留悬停态。覆盖 Tailwind 内置的 hover,group-hover / peer-hover 一并跟随 */ @custom-variant hover { @media (hover: hover) { &:not(:where([data-input="touch"] *)):hover { @slot; } } } /* 触屏:系统报告粗指针,或 (特斯拉车机等报告成鼠标的触屏,见 input-modality.ts) */ @custom-variant touch { @media (pointer: coarse) { @slot; } &:where([data-input="touch"] *) { @slot; } } @theme { --font-sans: "Inter Tight Variable", "Inter Tight", "SF Pro Display", "PingFang SC", "Microsoft YaHei", sans-serif; --font-display: "Space Grotesk Variable", "Space Grotesk", "Inter Tight Variable", "SF Pro Display", sans-serif; --color-ink-950: #040507; --color-ink-900: #080b12; --color-ink-800: #141925; --color-ink-700: #202637; --color-bone-50: #fbfaf7; --color-bone-100: #f1eee7; --color-bone-200: #dcd5c8; --color-bone-300: #bdb4a5; --color-bone-400: #918879; --color-bone-500: #6f675c; --color-gold-100: #fff0c4; --color-gold-200: #f7d98d; --color-gold-300: #e6b85c; --color-gold-400: #d49a4a; --color-gold-500: #af7133; --tracking-hero: 0; --shadow-card: 0 18px 40px -24px rgba(0, 0, 0, 0.9); --shadow-card-hover: 0 26px 54px -24px rgba(0, 0, 0, 1); --animate-fade-in: fade-in 520ms ease-out both; /* backwards 而不是 both:动画播完要撤掉。透明度动画一直挂着时,Chromium 把这个元素当成背景根, 里面的玻璃 / 磨砂只能采样到它自己,菜单就不糊了(账户菜单、播放器菜单都踩过) */ --animate-pg-pop: pg-pop 200ms var(--ease-pop) backwards; /* 播放器加载提示的滚动字幕:新一行从下方滚入,上一行向上滚出 */ --animate-ticker-in: ticker-in 360ms var(--ease-standard) both; --animate-ticker-out: ticker-out 360ms var(--ease-standard) both; --animate-blur-in: blur-in 560ms var(--ease-pop) backwards; --animate-hero-fade: hero-fade 740ms ease-out both; --animate-ken-burns: ken-burns 14s ease-out both; /* ─── 字号阶梯(见 docs/features/design-tokens.md)────────────────────── 只定字号不定行高,行为等同原来的 text-[Npx];自带行高的 text-xs / text-sm 继续用。 组件按角色引用,不写像素。正文阶:10 / 11 / 12 / 13 / 14 / 15 / 16 / 17。 */ --text-micro: 10px; --text-label: 11px; --text-meta: 12px; --text-caption: 13px; --text-body: 14px; --text-control: 15px; --text-lead: 16px; --text-lead-lg: 17px; /* 标题阶:18 / 20 / 22 / 24 / 26 / 28 / 30 / 32 / 34 / 42 / 44 / 52 / 56(现状值逐档保留,收敛另议) */ --text-title-xs: 18px; --text-title-sm: 20px; --text-title: 22px; --text-title-lg: 24px; --text-headline-xs: 26px; --text-headline-sm: 28px; --text-headline: 30px; --text-headline-lg: 32px; --text-display-xs: 34px; --text-display-sm: 42px; --text-display: 44px; --text-display-lg: 52px; --text-display-xl: 56px; /* 流式标题:每处 clamp 原值保留,按用途命名;要不要收成三档是设计决定 */ --text-hero-stream: clamp(32px, 9vw, 46px); --text-hero-stream-sm: clamp(40px, 7.5vw, 72px); --text-hero-stream-md: clamp(44px, 7.5vw, 88px); --text-detail-title: clamp(32px, 8vw, 82px); --text-notfound-code: clamp(7rem, 18vw, 11rem); --text-pricing-hero: clamp(2rem, 4.4vw, 4rem); --text-pricing-title: clamp(1.6rem, 2.4vw, 2.2rem); --text-landing-hero: clamp(2.1rem, 4.1vw, 3.9rem); --text-landing-platforms-title: clamp(1.8rem, 3.4vw, 2.8rem); --text-landing-immersive-title: clamp(2.25rem, 4.8vw, 5.4rem); --text-landing-service-hero: clamp(2rem, 4.4vw, 4.4rem); --text-landing-service-title: clamp(1.6rem, 2.4vw, 2.4rem); --text-landing-service-title-lg: clamp(1.6rem, 2.6vw, 2.6rem); --text-landing-service-sub: clamp(1.5rem, 2vw, 2rem); /* ─── 缓动(见 docs/features/design-tokens.md)。standard 是绝大多数过渡;spring 给 滑块 / 按压回弹;sheet 给抽屉;pop 给弹层出现。组件用 ease-standard 等,不写 bezier */ --ease-standard: cubic-bezier(0.4, 0, 0.2, 1); --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); --ease-spring-soft: cubic-bezier(0.34, 1.2, 0.64, 1); --ease-sheet: cubic-bezier(0.32, 0.72, 0, 1); --ease-pop: cubic-bezier(0.22, 1, 0.36, 1); } /* 过渡时长四档 + 两档特例。Tailwind 没有时长的主题命名空间,用 @utility 定义, 写法与内置 duration-N 完全一致(同时设 --tw-duration,tw-animate 的 animate-in 也读它)。 */ :root { --duration-micro: 150ms; --duration-base: 200ms; --duration-layout: 300ms; --duration-slow: 500ms; --duration-hero: 700ms; --duration-cinematic: 1000ms; } /* 横向滚动容器会连带裁掉纵向溢出(overflow-x:auto 时 overflow-y 不能是 visible), 里面胶囊、分段滑块的阴影与描边会被切成直边。四周向外借 12px 再用内边距还回来, 布局位置不变,阴影有地方画。放胶囊的横向滚动容器一律加它 */ @utility scroll-bleed { margin: -0.75rem; padding: 0.75rem; } /* 横滚标签条右端淡出:手机上分类标签滚到排序按钮跟前不再被硬切,也提示还能往右滑 */ @utility scroll-fade-end { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); } @utility duration-micro { --tw-duration: var(--duration-micro); transition-duration: var(--duration-micro); } @utility duration-base { --tw-duration: var(--duration-base); transition-duration: var(--duration-base); } @utility duration-layout { --tw-duration: var(--duration-layout); transition-duration: var(--duration-layout); } @utility duration-slow { --tw-duration: var(--duration-slow); transition-duration: var(--duration-slow); } @utility duration-hero { --tw-duration: var(--duration-hero); transition-duration: var(--duration-hero); } @utility duration-cinematic { --tw-duration: var(--duration-cinematic); transition-duration: var(--duration-cinematic); } @theme inline { --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); --radius-2xl: calc(var(--radius) + 8px); --radius-3xl: calc(var(--radius) + 12px); --radius-4xl: calc(var(--radius) + 16px); /* 角色型圆角:tight 给徽章 / 骨架屏这类小件(原来的裸 rounded),drawer 给手机端底部抽屉顶角, slab 给门户大卡。控件 md、输入与小按钮 lg、卡片 xl、面板 2xl、抽屉与大卡 3xl、药丸 full, 那些沿用 Tailwind 名,值随 --radius 一起缩放。 */ --radius-tight: 0.25rem; --radius-drawer: 28px; --radius-slab: 2.5rem; --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-muted: var(--muted); --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-success: var(--success); --color-success-foreground: var(--success-foreground); --color-warning: var(--warning); --color-warning-foreground: var(--warning-foreground); --color-destructive-foreground: var(--destructive-foreground); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); /* ─── 主题 token(见 docs/features/design-tokens.md)─────────────────── 组件只许用这些语义名,不许直接写 bone / ink / gold 原色、十六进制、rgba 或 white/black 透明度。值在下方各壳的 token 块里定义,主题包只覆盖值。 */ /* 文字层级(随日夜翻转) */ --color-content-strong: var(--content-strong); --color-content: var(--content); --color-content-secondary: var(--content-secondary); --color-content-tertiary: var(--content-tertiary); --color-content-muted: var(--content-muted); --color-content-faint: var(--content-faint); /* 面(随日夜翻转):页面底、普通面、抬起的卡、更高一层 */ --color-canvas: var(--canvas); --color-surface: var(--surface); --color-surface-raised: var(--surface-raised); --color-surface-high: var(--surface-high); /* 品牌色族(门户 = 墨水蓝族,流媒体 = 金,动漫版 = 品牌色) */ --color-brand-soft: var(--brand-soft); --color-brand-light: var(--brand-light); --color-brand: var(--brand); --color-brand-strong: var(--brand-strong); --color-brand-deep: var(--brand-deep); /* 透明"洗"层的底色:hover / 按压 / 分隔线等半透明层写成 `bg-wash/[0.07]`,透明度留在 调用处,底色随日夜翻转(暗底白洗,亮底黑洗)。 */ --color-wash: var(--wash); /* 压在视频 / 海报上的东西:不随日夜翻转,画面永远是暗的 */ --color-on-media-strong: var(--on-media-strong); --color-on-media: var(--on-media); --color-on-media-secondary: var(--on-media-secondary); --color-on-media-tertiary: var(--on-media-tertiary); --color-on-media-muted: var(--on-media-muted); --color-on-media-faint: var(--on-media-faint); --color-on-media-wash: var(--on-media-wash); /* 压暗画面的遮罩底色(黑),透明度留在调用处 */ --color-scrim: var(--scrim); } /* ─────────────────────────── Semantic tokens ─────────────────────────── */ :root { --radius: 0.85rem; color-scheme: light; /* Core surfaces */ --background: oklch(0.985 0.002 260); --foreground: oklch(0.18 0.006 260); --card: oklch(1 0 0 / 90%); --card-solid: oklch(1 0 0); --card-foreground: var(--foreground); --popover: oklch(1 0 0); --popover-foreground: var(--foreground); /* Actions and states */ /* 无彩主色(2026-09-26 拍板):日间是墨,夜间是白,和落地页的白色胶囊按钮同一个语言; 彩色只来自海报、剧照等内容,状态提示用下面的 success / warning / destructive */ --primary: oklch(0.2 0.006 260); --primary-foreground: oklch(0.99 0.002 260); --secondary: oklch(0.95 0.003 260); --secondary-foreground: oklch(0.26 0.006 260); --muted: oklch(0.955 0.003 260); --muted-foreground: oklch(0.47 0.008 260); --accent: oklch(0.935 0.004 260); --accent-foreground: oklch(0.2 0.006 260); --destructive: oklch(0.54 0.2 25); --destructive-foreground: oklch(0.99 0.005 25); /* 状态色:只用于状态提示,饱和度压低 */ --success: oklch(0.52 0.1 155); --success-foreground: oklch(0.99 0.002 260); --warning: oklch(0.6 0.12 70); --warning-foreground: oklch(0.99 0.002 260); /* Controls */ --border: oklch(0.88 0.003 260 / 85%); --input: oklch(0.93 0.003 260); --ring: var(--primary); /* App shell */ --sidebar: oklch(0.975 0.002 260); --sidebar-foreground: var(--foreground); --sidebar-primary: var(--primary); --sidebar-primary-foreground: var(--primary-foreground); --sidebar-accent: oklch(0.93 0.003 260); --sidebar-accent-foreground: var(--foreground); --sidebar-border: var(--border); --sidebar-ring: var(--primary); --shell-border: color-mix(in oklch, var(--border) 86%, transparent); --shell-hover: color-mix(in oklch, var(--accent) 68%, transparent); --shell-subtle: color-mix(in oklch, var(--muted) 72%, transparent); /* 主题 token:浅色门户。文字层级从 foreground 往淡推,面从 background 往上抬 */ --content-strong: oklch(0.13 0.006 260); --content: var(--foreground); --content-secondary: oklch(0.32 0.006 260); --content-tertiary: var(--muted-foreground); --content-muted: oklch(0.58 0.006 260); --content-faint: oklch(0.7 0.005 260); --canvas: var(--background); --surface: oklch(0.98 0.002 260); --surface-raised: var(--card-solid); --surface-high: oklch(0.955 0.003 260); --brand-soft: oklch(0.93 0.003 260); --brand-light: oklch(0.45 0.006 260); --brand: var(--primary); --brand-strong: oklch(0.1 0.004 260); --brand-deep: oklch(0.05 0.002 260); --wash: #000000; /* on-media 不分日夜:与流媒体壳的暗色文字层级同值(bone 阶) */ --on-media-strong: #fbfaf7; --on-media: #f1eee7; --on-media-secondary: #dcd5c8; --on-media-tertiary: #bdb4a5; --on-media-muted: #918879; --on-media-faint: #6f675c; --on-media-wash: #ffffff; --scrim: #000000; /* ─── 材质参数(见 docs/features/interface-materials.md)──────────────────── 一个材质 = 一份固定配方(底色 / 光泽 / 模糊 / 边 / 内高光 / 内暗线 / 外投影 / 辉光)+ 这里的参数。 class 只引用参数;浅色 / 深色 / 流媒体壳的差别只改参数,不再各自重写声明。 值与参数化前逐字相同。`--pg-surface-alpha` 是唯一给组件用的公开旋钮。 */ /* surface:贴边控制条 / header */ --mat-surface-rgb: 12, 13, 17; --mat-surface-blur: blur(24px) saturate(160%); --mat-surface-hairline: rgba(255, 255, 255, 0.08); --mat-surface-highlight: rgba(255, 255, 255, 0.07); --mat-surface-solid: rgba(12, 13, 17, 0.92); /* pill:药丸 HUD */ --mat-pill-bg: rgba(16, 17, 23, 0.58); --mat-pill-sheen: linear-gradient(180deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.04) 40%, rgba(255, 255, 255, 0) 70%); --mat-pill-blur: blur(16px) saturate(160%); --mat-pill-border: rgba(255, 255, 255, 0.06); --mat-pill-highlight: rgba(255, 255, 255, 0.34); --mat-pill-edge: rgba(0, 0, 0, 0.4); --mat-pill-shade: rgba(255, 255, 255, 0.1); --mat-pill-shadow: 0 2px 6px -2px rgba(0, 0, 0, 0.2), 0 12px 32px -14px rgba(0, 0, 0, 0.42); --mat-pill-solid: rgba(16, 17, 23, 0.88); /* slab:门户外层内容卡(浅色值;深色在 .dark 块) */ --mat-slab-bg: linear-gradient(155deg, rgba(255, 255, 255, 0.74) 0%, rgba(255, 255, 255, 0.58) 40%, rgba(255, 255, 255, 0.52) 100%); --mat-slab-border: rgba(255, 255, 255, 0.3); --mat-slab-blur: blur(20px) saturate(160%); /* 内容卡的边与全站玻璃同一套:左上亮、右下弱的 1px 边光 + 外侧 1px 暗线;面本身不变 */ --mat-slab-shadow: inset 1px 1px 0 -0.25px rgba(255, 255, 255, 0.95), inset -1px -1px 0 -0.25px rgba(255, 255, 255, 0.45), 0 0 0 1px rgba(20, 22, 28, 0.07), 0 1px 2px rgba(20, 22, 28, 0.05), 0 12px 28px -18px rgba(20, 22, 28, 0.16); /* 满高工作面板(文件管理的目录树 + 主面板)的实底与粘性表头:两块共用,背后的光斑不再让一块比另一块亮 */ --mat-slab-base: color-mix(in oklab, var(--background) 35%, transparent); --mat-slab-head: color-mix(in oklab, var(--background) 25%, white); --mat-slab-reflection: linear-gradient(105deg, transparent 0%, rgba(255, 255, 255, 0.14) 36%, rgba(255, 255, 255, 0.3) 44%, rgba(255, 255, 255, 0.07) 51%, transparent 62%); --mat-spotlight: rgba(255, 255, 255, 0.6); /* 卡片投影:日间轻,夜间沿用 @theme 里的深投影 */ --shadow-card: 0 1px 2px rgba(20, 22, 28, 0.06), 0 14px 32px -18px rgba(20, 22, 28, 0.28); --shadow-card-hover: 0 1px 2px rgba(20, 22, 28, 0.08), 0 20px 40px -20px rgba(20, 22, 28, 0.34); --mat-leak-opacity: 0.3; --mat-leak-blend: multiply; /* chrome:门户侧栏 / 顶栏 */ --mat-chrome-bg: rgba(255, 255, 255, 0.52); --mat-chrome-blur: blur(24px) saturate(160%); --mat-chrome-border: color-mix(in oklch, var(--primary) 11%, transparent); --mat-chrome-shadow: 0 8px 24px -20px rgba(20, 22, 28, 0.25); /* 竖直侧栏的边:内侧细亮边 + 外侧细暗线 + 很淡的投影,与玻璃同一套,不画硬分隔线 */ --mat-chrome-side-shadow: inset -1px 0 0 rgba(255, 255, 255, 0.9), 1px 0 0 rgba(20, 22, 28, 0.06), 10px 0 28px -22px rgba(20, 22, 28, 0.2); --mat-chrome-solid: rgba(255, 255, 255, 0.95); /* float:门户小型悬浮面板。SEARCH-4(2026-09-30)起不透明实底 = popover token,不做背景模糊: 半透明弹层压在资源列表上文字看不清(用户反馈) */ --mat-float-bg: var(--popover); --mat-float-blur: none; --mat-float-border: rgba(255, 255, 255, 0.3); /* 边与全站玻璃同一套(uhd_web 2026-10-07):左上亮、右下弱的 1px 边光 + 外侧 1px 暗线。底仍是 SEARCH-4 的实底 */ --mat-float-shadow: inset 1px 1px 0 -0.25px rgba(255, 255, 255, 0.95), inset -1px -1px 0 -0.25px rgba(255, 255, 255, 0.5), 0 0 0 1px rgba(20, 22, 28, 0.08), 0 2px 6px -2px rgba(20, 22, 28, 0.08), 0 20px 40px -20px rgba(20, 22, 28, 0.2); --mat-float-solid: rgb(251, 251, 252); /* 对话框 / 抽屉的底:uhd_web 的菜单是通透玻璃、对话框才换实底;本项目菜单本来就是实底(SEARCH-4),两者同值,留着这一层供换皮 */ --mat-float-modal-bg: var(--popover); /* 胶囊按钮:主操作是有填充的薄玻璃,次操作只描边。日夜对称——夜间白色薄玻璃配白字, 日间墨色薄玻璃配深字;不做实心黑 / 实心白 */ --mat-pill-primary-bg: linear-gradient(180deg, rgba(20, 22, 28, 0.02), rgba(20, 22, 28, 0.05)); --mat-pill-primary-bg-hover: linear-gradient(180deg, rgba(20, 22, 28, 0.04), rgba(20, 22, 28, 0.08)); --mat-pill-primary-fg: var(--content-strong); --mat-pill-primary-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7), 0 1px 2px rgba(20, 22, 28, 0.06); /* 主按钮的棱镜环(方案 A):亮度、彩度、环与内光的强度 */ --prism-l: 0.66; --prism-c: 0.15; --prism-ring: 1; --prism-glow: 0.14; /* 选中态(分页当前页、角标、选中的选项):静态半透明 + 稍深描边,不转动、不实心 */ --mat-pill-selected-bg: rgba(20, 22, 28, 0.08); --mat-pill-selected-border: rgba(20, 22, 28, 0.22); --mat-pill-secondary-bg: rgba(20, 22, 28, 0.03); --mat-pill-secondary-bg-hover: rgba(20, 22, 28, 0.07); --mat-pill-secondary-border: rgba(20, 22, 28, 0.12); /* lens:液态玻璃小控件(次按钮、图标键;主按钮只用 edge / sheen)。meniscus 的 lens 档: 本体几乎透明,靠左上亮右下暗的 1px 边光(内阴影)和外侧 1px 暗线成形 */ --mat-lens-fill: rgba(255, 255, 255, 0.08); --mat-lens-fill-hover: rgba(255, 255, 255, 0.3); --mat-lens-rim: inset 1px 1px 0 -0.25px rgba(255, 255, 255, 0.95), inset -1px -1px 0 -0.25px rgba(255, 255, 255, 0.55), inset 0 0 0 1px rgba(255, 255, 255, 0.25); --mat-lens-edge: 0 0 0 1px rgba(20, 22, 28, 0.1); --mat-lens-sheen: inset 1px 1px 0 -0.5px rgba(255, 255, 255, 0.7); --mat-lens-shadow: 0 6px 16px -10px rgba(20, 22, 28, 0.28); --mat-lens-blur: blur(2px) saturate(160%); /* field:输入框 / 下拉选择的触发器,与按钮同一套边光;底比按钮实一点,保证字和占位符好读 */ /* 输入框是填充型:靠比卡片略深的底色区分,边线按 WCAG 非文本对比 3:1 给(压在白卡片上) */ --mat-field-bg: rgba(20, 22, 28, 0.045); --mat-field-edge: rgba(20, 22, 28, 0.46); --mat-field-edge-focus: rgba(20, 22, 28, 0.78); /* 登录页的表单卡片:实在的底,先把卡片和页面分开 */ --mat-auth-card-bg: rgba(255, 255, 255, 0.84); --mat-field-ring: rgba(20, 22, 28, 0.06); --mat-field-highlight: rgba(255, 255, 255, 0.08); /* 小玻璃圆片的烟色玻璃:白色图标坐在上面。日间烟墨、夜间淡白;压在图片上的恒用 media 档 */ --mat-chip-glass: rgba(20, 22, 28, 0.56); /* media-hero:详情页头图。剧照铺在内容区顶部、渐隐到页面底色;左侧文字区压近乎不透明的底色,右侧露出剧照。 窄屏海报与文字上下排,改为自上而下压底色 */ --mat-hero-image-opacity: 1; --mat-hero-scrim-side: linear-gradient(90deg, var(--background) 0%, color-mix(in oklab, var(--background) 96%, transparent) 38%, color-mix(in oklab, var(--background) 82%, transparent) 55%, color-mix(in oklab, var(--background) 40%, transparent) 72%, transparent 92%); --mat-hero-scrim-stack: linear-gradient(180deg, color-mix(in oklab, var(--background) 30%, transparent) 0%, color-mix(in oklab, var(--background) 72%, transparent) 45%, color-mix(in oklab, var(--background) 92%, transparent) 75%, var(--background) 100%); /* 分段控件的滑块(侧栏当前项、SegmentedTabs):日间是托起的白片,夜间是薄白玻璃 */ --mat-seg-thumb-bg: rgba(255, 255, 255, 0.62); --mat-seg-thumb-border: transparent; --mat-seg-thumb-shadow: inset 1px 1px 0 -0.25px rgba(255, 255, 255, 1), inset -1px -1px 0 -0.25px rgba(255, 255, 255, 0.6), 0 0 0 1px rgba(20, 22, 28, 0.08), 0 3px 12px -3px rgba(20, 22, 28, 0.18); /* Scrollbars */ --scrollbar-thumb: color-mix( in oklch, var(--muted-foreground) 26%, transparent ); --scrollbar-thumb-hover: color-mix( in oklch, var(--muted-foreground) 42%, transparent ); --scrollbar-thumb-active: color-mix( in oklch, var(--muted-foreground) 58%, transparent ); } .dark, :root:has([data-force-dark]) { color-scheme: dark; --background: oklch(0.15 0.004 265); --foreground: oklch(0.96 0.003 260); --card: oklch(0.21 0.004 265 / 88%); --card-solid: oklch(0.21 0.004 265); --card-foreground: var(--foreground); --popover: oklch(0.2 0.004 265); --popover-foreground: var(--foreground); /* 深色档主色是白(见 :root 处注释) */ --primary: oklch(0.97 0.002 260); --primary-foreground: oklch(0.16 0.004 265); --secondary: oklch(0.27 0.004 265); --secondary-foreground: var(--foreground); --muted: oklch(0.26 0.004 265); --muted-foreground: oklch(0.7 0.004 260); --accent: oklch(0.29 0.004 265); --accent-foreground: var(--foreground); --destructive: oklch(0.7 0.15 25); --destructive-foreground: oklch(0.16 0.004 265); --success: oklch(0.78 0.1 158); --success-foreground: oklch(0.2 0.03 158); --warning: oklch(0.82 0.1 78); --warning-foreground: oklch(0.22 0.03 78); --border: oklch(0.36 0.004 265 / 70%); --input: oklch(0.3 0.004 265); --ring: var(--primary); --sidebar: oklch(0.17 0.004 265); --sidebar-foreground: var(--foreground); --sidebar-primary: var(--primary); --sidebar-primary-foreground: var(--primary-foreground); --sidebar-accent: oklch(0.27 0.004 265); --sidebar-accent-foreground: var(--foreground); --sidebar-border: var(--border); --sidebar-ring: var(--primary); --shell-border: rgba(255, 255, 255, 0.08); --shell-hover: rgba(255, 255, 255, 0.08); --shell-subtle: rgba(255, 255, 255, 0.05); /* 主题 token:深色门户 */ --content-strong: oklch(0.99 0.002 260); --content: var(--foreground); --content-secondary: oklch(0.85 0.004 260); --content-tertiary: var(--muted-foreground); --content-muted: oklch(0.58 0.004 260); --content-faint: oklch(0.46 0.004 260); --canvas: var(--background); --surface: oklch(0.18 0.004 265); --surface-raised: var(--card-solid); --surface-high: oklch(0.26 0.004 265); --brand-soft: oklch(0.27 0.004 265); --brand-light: oklch(1 0 0); --brand: var(--primary); --brand-strong: oklch(0.88 0.003 260); --brand-deep: oklch(0.78 0.003 260); --wash: #ffffff; /* 材质参数:深色门户 */ --mat-slab-bg: linear-gradient(155deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.04) 30%, rgba(255, 255, 255, 0.03) 75%, rgba(255, 255, 255, 0.04) 100%); --mat-slab-border: rgba(255, 255, 255, 0.04); --mat-slab-shadow: inset 1px 1px 0 -0.25px rgba(255, 255, 255, 0.22), inset -1px -1px 0 -0.25px rgba(255, 255, 255, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.2), 0 12px 28px -18px rgba(0, 0, 0, 0.4); --mat-slab-base: color-mix(in oklab, var(--background) 78%, transparent); --mat-slab-head: color-mix(in oklab, var(--background) 94%, white); --mat-slab-reflection: linear-gradient(105deg, transparent 0%, rgba(255, 255, 255, 0.006) 36%, rgba(255, 255, 255, 0.013) 44%, rgba(255, 255, 255, 0.003) 51%, transparent 62%); --mat-spotlight: rgba(255, 255, 255, 0.07); --shadow-card: 0 18px 40px -24px rgba(0, 0, 0, 0.9); --shadow-card-hover: 0 26px 54px -24px rgba(0, 0, 0, 1); --mat-leak-opacity: 0.3; --mat-leak-blend: normal; --mat-chrome-bg: color-mix(in oklch, var(--card-solid) 48%, transparent); --mat-chrome-border: color-mix(in oklch, var(--primary) 13%, transparent); --mat-chrome-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06); --mat-chrome-side-shadow: inset -1px 0 0 rgba(255, 255, 255, 0.08), 1px 0 0 rgba(0, 0, 0, 0.45), 10px 0 28px -22px rgba(0, 0, 0, 0.55); --mat-chrome-solid: rgba(12, 13, 17, 0.92); --mat-float-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0) 40%), var(--popover); --mat-float-solid: rgb(22, 23, 27); --mat-float-modal-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0) 40%), var(--popover); --mat-float-blur: none; --mat-float-border: rgba(255, 255, 255, 0.06); /* 胶囊按钮:夜间主操作是白色玻璃 */ --mat-pill-primary-bg: rgba(255, 255, 255, 0.05); --mat-pill-primary-bg-hover: rgba(255, 255, 255, 0.09); --mat-pill-primary-fg: #ffffff; --mat-pill-primary-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 1px 2px rgba(0, 0, 0, 0.2); --prism-l: 0.82; --prism-c: 0.13; --prism-ring: 1; --prism-glow: 0.2; --mat-pill-selected-bg: rgba(255, 255, 255, 0.12); --mat-pill-selected-border: rgba(0, 0, 0, 0.45); --mat-pill-secondary-bg: rgba(255, 255, 255, 0.04); --mat-pill-secondary-bg-hover: rgba(255, 255, 255, 0.1); --mat-pill-secondary-border: rgba(255, 255, 255, 0.15); --mat-lens-fill: rgba(0, 0, 0, 0.14); --mat-lens-fill-hover: rgba(255, 255, 255, 0.08); --mat-lens-rim: inset 1px 1px 0 -0.25px rgba(255, 255, 255, 0.42), inset -1px -1px 0 -0.25px rgba(255, 255, 255, 0.16), inset 0 0 0 1px rgba(255, 255, 255, 0.06); --mat-lens-edge: 0 0 0 1px rgba(0, 0, 0, 0.35); --mat-lens-sheen: inset 1px 1px 0 -0.5px rgba(255, 255, 255, 0.28); --mat-lens-shadow: 0 6px 16px -10px rgba(0, 0, 0, 0.55); /* 夜间:底比卡片略亮,外线是浅色且对比 3:1(黑线压在深色卡片上看不见) */ --mat-field-bg: rgba(255, 255, 255, 0.075); --mat-field-edge: rgba(255, 255, 255, 0.36); --mat-field-edge-focus: rgba(255, 255, 255, 0.78); --mat-auth-card-bg: rgba(26, 27, 32, 0.74); --mat-field-ring: rgba(255, 255, 255, 0.06); --mat-chip-glass: rgba(255, 255, 255, 0.12); --mat-hero-image-opacity: 0.85; --mat-hero-scrim-side: linear-gradient(90deg, var(--background) 0%, color-mix(in oklab, var(--background) 94%, transparent) 38%, color-mix(in oklab, var(--background) 78%, transparent) 55%, color-mix(in oklab, var(--background) 36%, transparent) 72%, transparent 92%); --mat-hero-scrim-stack: linear-gradient(180deg, color-mix(in oklab, var(--background) 30%, transparent) 0%, color-mix(in oklab, var(--background) 72%, transparent) 45%, color-mix(in oklab, var(--background) 92%, transparent) 75%, var(--background) 100%); --mat-seg-thumb-bg: rgba(255, 255, 255, 0.08); --mat-seg-thumb-border: transparent; --mat-seg-thumb-shadow: inset 1px 1px 0 -0.25px rgba(255, 255, 255, 0.42), inset -1px -1px 0 -0.25px rgba(255, 255, 255, 0.14), 0 0 0 1px rgba(0, 0, 0, 0.35), 0 4px 18px -6px rgba(0, 0, 0, 0.4); --mat-float-shadow: inset 1px 1px 0 -0.25px rgba(255, 255, 255, 0.32), inset -1px -1px 0 -0.25px rgba(255, 255, 255, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.45), 0 2px 6px -2px rgba(0, 0, 0, 0.22), 0 18px 40px -20px rgba(0, 0, 0, 0.4); } /* ───────────────────────────── Base styles ───────────────────────────── */ @layer base { * { @apply border-border outline-ring/50; } html, body { min-height: 100%; } /* Light app shell */ body { @apply bg-background text-foreground antialiased; background-image: linear-gradient(180deg, oklch(1 0 0), oklch(0.97 0.002 260)); } /* Dark app shell, including fixed-dark public and stream routes */ .dark body, :root:has([data-force-dark]) body { background-image: linear-gradient(180deg, oklch(0.16 0.004 265), oklch(0.12 0.004 265)); } /* 流媒体壳:html / body 整块铺成壳的 canvas,不用上面门户的渐变底。 桌面上永远看不到 body,但手机上地址栏收起、橡皮筋回弹、内容不够一屏、崩溃页这些 "壳没铺满"的时刻会把 body 露出来。夜间 html 也一并铺:iOS 回弹露出来的是 html 不是 body。 */ :root.dark:has([data-stream-shell]), :root:has([data-stream-shell="play"]) { background: var(--canvas); } :root.dark:has([data-stream-shell]) body, :root:has([data-stream-shell="play"]) body, :root:not(.dark):has([data-stream-shell="page"]) body { background-image: none; background-color: var(--canvas); } /* 触屏点按时不要系统自带的半透明高亮(Android 是一层蓝灰),按压反馈由 卡片 / 按钮自己的 active:scale 给。该属性可继承,挂在壳上即可。 */ [data-stream-shell] { -webkit-tap-highlight-color: transparent; } a { @apply transition-colors; } } /* ────────────────────────────── Utilities ────────────────────────────── */ @layer utilities { /* Typography */ .font-display { font-family: var(--font-display); letter-spacing: 0.01em; } /* Scrolling */ .no-scrollbar { scrollbar-width: none; } .no-scrollbar::-webkit-scrollbar { display: none; } :root:has(.app-scrollbars), :root:has(.app-scrollbars) *:not(.no-scrollbar):not(.scrollbar-none) { scrollbar-color: var(--scrollbar-thumb) transparent; scrollbar-width: thin; } :root:has(.app-scrollbars) *:not(.no-scrollbar):not(.scrollbar-none):hover { scrollbar-color: var(--scrollbar-thumb-hover) transparent; } :root:has(.app-scrollbars)::-webkit-scrollbar, :root:has(.app-scrollbars) *:not(.no-scrollbar):not(.scrollbar-none)::-webkit-scrollbar { width: 6px; height: 6px; } :root:has(.app-scrollbars)::-webkit-scrollbar-track, :root:has(.app-scrollbars) *:not(.no-scrollbar):not(.scrollbar-none)::-webkit-scrollbar-track { background: transparent; } :root:has(.app-scrollbars)::-webkit-scrollbar-thumb, :root:has(.app-scrollbars) *:not(.no-scrollbar):not(.scrollbar-none)::-webkit-scrollbar-thumb { min-height: 36px; border: 1px solid transparent; border-radius: 999px; background-color: var(--scrollbar-thumb); background-clip: padding-box; } :root:has(.app-scrollbars) *:not(.no-scrollbar):not(.scrollbar-none):hover::-webkit-scrollbar-thumb { background-color: var(--scrollbar-thumb-hover); } :root:has(.app-scrollbars)::-webkit-scrollbar-thumb:hover, :root:has(.app-scrollbars) *:not(.no-scrollbar):not(.scrollbar-none)::-webkit-scrollbar-thumb:hover { background-color: var(--scrollbar-thumb-active); } /* Player controls */ .volume-slider { -webkit-appearance: none; appearance: none; width: 100%; height: 4px; border-radius: 999px; outline: none; cursor: pointer; background: linear-gradient( to right, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.9) var(--val, 100%), rgba(255, 255, 255, 0.12) var(--val, 100%), rgba(255, 255, 255, 0.12) 100% ); } .volume-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 13px; height: 13px; border-radius: 50%; background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.45); cursor: pointer; border: 0; } .volume-slider::-moz-range-thumb { width: 13px; height: 13px; border-radius: 50%; background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.45); cursor: pointer; border: 0; } /* App shell backgrounds */ /* 门户 shell 背景光斑(user/unsubscribe 共用)。2026-09-26 主色改为无彩后,光斑也去掉色相, 只留明暗层次:日间顶部一层柔和的白与一抹极淡的灰,夜间顶部一抹微光。 玻璃卡背后要有明暗变化才读得出是玻璃,不能是一整块平涂。 */ /* 门户页背景:无彩的明暗光斑铺满整页;棱镜漏光是单独一层(.prism-leak)。 卡片是磨砂面,背景只需给它柔和的明暗与淡彩,不需要纹理 */ .bg-page-glow { background: radial-gradient(ellipse 60% 50% at 12% 4%, rgba(20, 22, 28, 0.09) 0%, transparent 70%), radial-gradient(ellipse 45% 40% at 88% 18%, rgba(255, 255, 255, 0.9) 0%, transparent 70%), radial-gradient(ellipse 50% 45% at 70% 62%, rgba(20, 22, 28, 0.07) 0%, transparent 70%), radial-gradient(ellipse 45% 40% at 20% 88%, rgba(20, 22, 28, 0.06) 0%, transparent 70%), linear-gradient(180deg, rgba(255, 255, 255, 0.42), rgba(246, 246, 248, 0.72)); } /* 棱镜漏光(全站,落地页与播放页除外):左上角斜进来一束已分好色的光,大幅虚化、只占 一角,与落地页的棱镜叙事呼应;卡片压在上面时透出淡彩。日间用 multiply 叠在浅底上, 避免发灰;浓度见 --mat-leak-opacity。由 渲染,固定在视口上 */ .prism-leak { position: fixed; inset: -10%; pointer-events: none; background: linear-gradient( 118deg, transparent 6%, oklch(0.75 0.15 25) 13%, oklch(0.8 0.14 65) 17%, oklch(0.87 0.14 100) 21%, oklch(0.8 0.14 150) 25%, oklch(0.78 0.12 205) 29%, oklch(0.68 0.15 265) 33%, oklch(0.62 0.16 305) 37%, transparent 44% ); filter: blur(48px); opacity: var(--mat-leak-opacity); mix-blend-mode: var(--mat-leak-blend); -webkit-mask-image: radial-gradient(ellipse 75% 70% at 8% 0%, #000 0%, rgba(0, 0, 0, 0.5) 45%, transparent 78%); mask-image: radial-gradient(ellipse 75% 70% at 8% 0%, #000 0%, rgba(0, 0, 0, 0.5) 45%, transparent 78%); } .dark .bg-page-glow, [data-force-dark] .bg-page-glow { background: radial-gradient(ellipse 60% 50% at 12% 4%, rgba(255, 255, 255, 0.075) 0%, transparent 70%), radial-gradient(ellipse 45% 40% at 88% 22%, rgba(255, 255, 255, 0.05) 0%, transparent 70%), radial-gradient(ellipse 50% 45% at 68% 64%, rgba(255, 255, 255, 0.055) 0%, transparent 70%), radial-gradient(ellipse 45% 40% at 18% 90%, rgba(255, 255, 255, 0.04) 0%, transparent 70%), linear-gradient(180deg, rgba(16, 17, 20, 0.76), rgba(17, 18, 21, 0.86)); } } /* ───────────────────────────── Components ───────────────────────────── */ @layer components { /* Player subtitles */ [data-subtitles-hidden] .ASS-box { display: none !important; } .ASS-box { transition: transform 200ms ease; } /* 抬多少由 Player 按字幕层与控件常驻面的实际重叠量写进 --uhd-sub-lift(负值 px); 量不到时退回固定 5.5rem(约等于控件常驻面高度)。 */ [data-controls-visible] .ASS-box { transform: translate3d(0, var(--uhd-sub-lift, -5.5rem), 0); } .ASS-box .ASS-dialogue [data-text] { paint-order: stroke fill; -webkit-text-stroke: 1.5px rgba(0, 0, 0, 0.95); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6); } /* 字幕字号档位:Player 在根节点上写 --uhd-sub-scale(见 subtitleScale.ts), 在 ass.js 自己算出的字号上再乘一个倍率。ass.js 的样式表是不分层的 (#ASS-global-style),这里在 @layer 里按普通优先级会输给它,所以三条都加 !important —— 分层内的 !important 高于未分层的普通声明。只动字号 / 行高 / 字距,定位与描边仍由 ass.js 的 --ass-scale 控制。 */ .ASS-box .ASS-dialogue [data-text] { font-size: calc(var(--ass-scale) * var(--ass-real-fs) * var(--uhd-sub-scale, 1) * 1px) !important; line-height: calc(var(--ass-scale) * var(--ass-tag-fs) * var(--uhd-sub-scale, 1) * 1px) !important; letter-spacing: calc(var(--ass-scale) * var(--ass-tag-fsp) * var(--uhd-sub-scale, 1) * 1px) !important; } /* ─── 玻璃三档 tokens(全站 dark chrome 统一配方)────────────────── 配方来源是 btn-glass 的语言 + Glass UI 的思路:① 底色不透明度压到 0.55~0.70,blur 真正透出后面的内容才有玻璃感(旧 .glass/.glass-panel 的 0.86+ 基本是实心板,已删除并全量迁移);② inset 顶部高光,玻璃 上沿"接光"。边框与投影一并收进 class,组件侧不再各写各的。 使用范围:播放器全部浮层 + 媒体区 header/筛选栏/弹层/卡片徽章。 */ /* 两族分治(2026-08-01 实测校准): - 贴边 chrome(header/筛选栏/播放器底栏)= pg-surface,融入页面: 只有 blur + 底色,不加泛光和接光线 —— 贴屏幕边缘的面没有"上方 光源",加亮线会把它从页面上切下来,恰好破坏融为一体的感觉。 - 悬浮物(弹层/对话框)= pg-float,画面中央的药丸 HUD = pg-pill,材质发光: 四周有留白,光学上浮在页面上方,泛光层 + 双内高光 + 亮边框成立。 暗底上"更透"读不出来,能读出来的是这些材质要素;底色反而要实, 内容才好读。 */ .pg-surface { /* 常驻贴边大面:播放器底部控制条(0.6)。站点 header/筛选栏压在 高亮海报上,文字对比要求更高,用 [--pg-surface-alpha:0.7] 收紧 */ background: rgba(var(--mat-surface-rgb), var(--pg-surface-alpha, 0.6)); backdrop-filter: var(--mat-surface-blur); -webkit-backdrop-filter: var(--mat-surface-blur); border-color: var(--mat-surface-hairline); box-shadow: inset 0 1px 0 var(--mat-surface-highlight); } .pg-pill { /* 画面中央短暂浮层:seek 进度环、播放/暂停 flash、toast、手势 HUD */ background: var(--mat-pill-sheen), var(--mat-pill-bg); backdrop-filter: var(--mat-pill-blur); -webkit-backdrop-filter: var(--mat-pill-blur); border: 1px solid var(--mat-pill-border); /* 液态玻璃语言:左上亮、右下暗的边光 + 外侧 1px 暗线 */ box-shadow: inset 1px 1px 0 -0.25px var(--mat-pill-highlight), inset -1px -1px 0 -0.25px var(--mat-pill-shade), 0 0 0 1px var(--mat-pill-edge), var(--mat-pill-shadow); } /* 第四档:内容卡片,双主题(门户与 /speed 共用)。薄白/薄亮底 + 亮棱边 + 顶部内高光 + 斜反光,背景模糊由 --mat-slab-blur 给;/speed 的卡片贴着 高频重绘的实时区,在 .spd-bg 里把它关掉,零合成开销优先。 */ .pg-slab { position: relative; /* 建立层叠上下文,把 ::before 的 z-index:-1 关在自己内部 */ isolation: isolate; /* 磨砂面,不追求透明:内容卡以好读为先,背景模糊只让漏光与明暗柔和地渗进来。 不做折射——背后没有细节可弯折,Chromium 专属的 SVG 折射也不值得 */ background: var(--mat-slab-bg); backdrop-filter: var(--mat-slab-blur); -webkit-backdrop-filter: var(--mat-slab-blur); /* 立体感靠亮棱边与顶部内高光,不靠投影:投影只有贴边一层 + 很淡的环境一层, 越透的东西影子越淡,重投影会让玻璃读成实心板 */ border: 1px solid var(--mat-slab-border); box-shadow: var(--mat-slab-shadow); } /* 实底 slab:同一套玻璃面,下面垫一层底色,只让光斑淡淡渗进来(满高工作面板用,几块并排时明暗一致) */ .pg-slab-solid { background: var(--mat-slab-bg), var(--mat-slab-base); } /* slab 里的粘性表头:与卡片同色系的实底,不是一条纯黑 / 纯白的条 */ .pg-slab-head { background: var(--mat-slab-head); } .pg-slab::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none; /* 斜掠反光,收窄且不对称 —— 对称高光读成"渐变背景"而不是"反射"。 浅色下卡片本身大面积偏白,反光峰值可以略高;作用仍是"察觉有一层 膜",能被明确看成光带就过了 */ background: var(--mat-slab-reflection); } /* 贴边 chrome 的双主题版(/speed 页头)。浅色:白磨砂 + 蓝调底缘投影; 深色:等同 pg-surface [--pg-surface-alpha:0.7] 的配方。只设边框颜色, 宽度由 border-b utility 给。 */ /* 2026-08-02 统一校准:① 暗色底从硬编码墨黑(rgba 12,13,17,流媒体 继承)改为 token 混色 —— 门户暗色是 271° 蓝紫调,chrome 必须同色相 否则读成另一种材质;② 边框掺 primary,与卡片"蓝棱线"同语言; ③ 竖直侧栏用 .pg-chrome-side:内侧细亮边 + 外侧细暗线 + 投影转向右侧,不画硬分隔线。 */ .pg-chrome { background: var(--mat-chrome-bg); backdrop-filter: var(--mat-chrome-blur); -webkit-backdrop-filter: var(--mat-chrome-blur); border-color: var(--mat-chrome-border); box-shadow: var(--mat-chrome-shadow); } .pg-chrome-side { box-shadow: var(--mat-chrome-side-shadow); } /* 全站唯一的悬浮层材质(2026-09-26 起):下拉菜单、弹出框、下拉选择、对话框、抽屉, 门户与流媒体、播放器共用;日夜跟随,播放页恒为夜间。圆角分两档:菜单类 rounded-2xl, 对话框 rounded-3xl。2026-09-30(SEARCH-4)起底色是不透明的 popover 实底、不做背景模糊, 立体感只靠边框与投影;组件侧不要再给弹层加半透明底或 backdrop-blur。 */ .pg-float { background: var(--mat-float-bg); backdrop-filter: var(--mat-float-blur); -webkit-backdrop-filter: var(--mat-float-blur); border: 1px solid var(--mat-float-border); box-shadow: var(--mat-float-shadow); } /* 对话框、确认框、抽屉:要专心阅读和填写,底比菜单实。压在半透明遮罩上时,通透的白底会变成脏灰 */ .pg-float-modal { --mat-float-bg: var(--mat-float-modal-bg); } /* 嵌在另一层磨砂里的菜单(页头、筛选栏、卡片内的下拉):外层磨砂是 backdrop 根, 里面的菜单糊不到页面,半透明底会透出没糊过的内容 —— 这类一律用近实底(动漫站同一做法)。 挂在 body 上的对话框、shadcn 弹出框不需要 */ .pg-float-solid { --mat-float-bg: var(--mat-float-solid); } /* /speed 页面背景:玻璃要"有东西可透"才成立,这几团光斑就是卡片背后的内容。 纯静态渐变、零重绘成本。2026-09-26 主色改为无彩后光斑也去掉色相,只留明暗: 日间是几团极淡的墨,夜间是几团微光。强度照原来校准过的档位,玻璃仍读得出来。 */ .spd-bg { /* 测速页的卡片贴着高频重绘的实时区,不开背景模糊 */ --mat-slab-blur: none; background-color: var(--background); background-image: radial-gradient( 120% 80% at 12% -8%, rgba(20, 22, 28, 0.08) 0%, transparent 55% ), radial-gradient( 90% 65% at 96% -6%, rgba(20, 22, 28, 0.06) 0%, transparent 52% ), radial-gradient( 56% 44% at 38% 52%, rgba(20, 22, 28, 0.04) 0%, transparent 62% ), radial-gradient( 80% 60% at 50% 112%, rgba(20, 22, 28, 0.05) 0%, transparent 60% ); } .dark .spd-bg, [data-force-dark] .spd-bg { background-image: radial-gradient( 120% 80% at 15% -10%, rgba(255, 255, 255, 0.06) 0%, transparent 55% ), radial-gradient( 100% 70% at 95% 0%, rgba(255, 255, 255, 0.04) 0%, transparent 50% ); } /* blur 不可用(老内核/省电模式)时透明底会让文字压在画面上没法读, 退回近实心 */ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .pg-surface { background: var(--mat-surface-solid); } .pg-pill { background: var(--mat-pill-solid); } .pg-chrome { background: var(--mat-chrome-solid); } .pg-float { background: var(--mat-float-solid); } .dark .pg-float, [data-force-dark] .pg-float { background: rgba(20, 21, 25, 0.96); } } /* Stream library layout */ /* 手机三列:两列时单张海报 190px,信息密度只有主流客户端的一半;三列 约 120px,一屏能看 9 张,标题字号在 MovieCard 里随之收到 15px */ .lib-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 0.5rem; row-gap: 1.25rem; } @media (min-width: 480px) { .lib-grid { column-gap: 0.75rem; row-gap: 2rem; } } @media (min-width: 768px) { .lib-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); column-gap: 1.25rem; row-gap: 2.5rem; } } @media (min-width: 1024px) { .lib-grid { /* 定宽 220 + 左对齐会在平板/宽屏右侧留大片空白(横屏 iPad 只排 4 列、 右边空 ~200px)。改成弹性列:每列 200px 起、用 1fr 拉伸铺满整行, 列数随宽度自适应,不再有右侧留白。 */ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); } } /* 玻璃族的动效成员:沿元素边框匀速流动的一段高亮弧。用法:宿主已有 圆角与边框,挂 .pg-beam 即可;弧色取 var(--primary) 自动双主题。 克制档:1.5px 细、弧长约 15% 周长、5.5s 一圈;动画的是注册过的 自定义属性(角度),仅小面积重绘。reduced-motion 时静止为常亮弧。 */ .pg-beam { position: relative; } .pg-beam::after { content: ""; position: absolute; inset: -2px; padding: 1.5px; border-radius: inherit; pointer-events: none; /* 弧的亮度与巡边周期可在使用处经 CSS 变量收弱(常驻元素建议弱档, 一次性 CTA 用默认档) */ background: conic-gradient( from var(--pg-beam-angle), transparent 0%, transparent 74%, color-mix(in oklch, var(--primary) var(--pg-beam-strength, 88%), transparent) 87%, transparent 100% ); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask-composite: exclude; animation: pg-beam-spin var(--pg-beam-duration, 5.5s) linear infinite; } @media (prefers-reduced-motion: reduce) { .pg-beam::after { animation: none; } } /* Segmented tabs */ .tab-slider { transition: transform 380ms var(--ease-spring-soft), width 380ms var(--ease-spring-soft), top 380ms var(--ease-spring-soft), height 380ms var(--ease-spring-soft); will-change: transform, width, top, height; } /* 分段控件滑块的材质,位置与尺寸由组件量测后写进 style */ .seg-thumb { background: var(--mat-seg-thumb-bg); border: 1px solid var(--mat-seg-thumb-border); box-shadow: var(--mat-seg-thumb-shadow); backdrop-filter: blur(12px); } .tab-color { transition: color 320ms var(--ease-standard); } /* Glass buttons */ /* 门户胶囊按钮(2026-09-26):主操作 pill-primary 是带棱镜环的半透明胶囊,次操作 pill-secondary 是描边胶囊。 只管底、边、字色与投影,形状尺寸(rounded-full、内边距、字号)由调用处给。 日夜差别全在 --mat-pill-* 参数里;以后要换回实底或调透明度只改参数。 */ .pill-secondary { /* 液态玻璃 lens:几乎透明的填充 + 内阴影画的方向性边光 + 外侧暗线 */ background: var(--mat-lens-fill); border: 1px solid transparent; box-shadow: var(--mat-lens-rim), var(--mat-lens-edge), var(--mat-lens-shadow); color: var(--content); -webkit-backdrop-filter: var(--mat-lens-blur); backdrop-filter: var(--mat-lens-blur); transition: background-color var(--duration-base) var(--ease-standard), transform 220ms var(--ease-spring); } .pill-secondary:hover { background: var(--mat-lens-fill-hover); } /* 主操作(方案 A,2026-09-26):和其他按钮一样是半透明胶囊,不做实心;靠沿边框缓慢流转的 一整圈棱镜光谱突出,内侧再透一层很淡的同色光。门户 .pill-primary 与流媒体 .btn-glass-primary 共用;减少动态效果时停转,只留彩色边框 */ .pill-primary, .btn-glass.btn-glass-primary { position: relative; isolation: isolate; overflow: visible; background: var(--mat-lens-fill); border: 1px solid transparent; color: var(--mat-pill-primary-fg); /* 液态玻璃:彩虹环就是它的边光,这里只补左上内高光和外侧暗线 */ box-shadow: var(--mat-lens-sheen), var(--mat-lens-edge), var(--mat-lens-shadow); -webkit-backdrop-filter: var(--mat-lens-blur); backdrop-filter: var(--mat-lens-blur); transition: background-color var(--duration-base) var(--ease-standard), transform 220ms var(--ease-spring); } .pill-primary:hover, .btn-glass.btn-glass-primary:hover { background: var(--mat-lens-fill-hover); } /* 棱镜高光(2026-10-07 液态玻璃方案 2,替代整圈转动的光谱环):光从左上照来,在玻璃棱边上 分出一段光谱,右下是一段更淡的回光。静止不转,悬停时高光沿边扫过一小段。 ::before = 棱边上的光谱弧;::after = 同一段光谱的柔光,透进玻璃本体、略洒出边外。 渐变直接写在伪元素上:--prism-angle 不继承,写进 :root 的变量会在根上就被算死 */ .pill-primary::before, .btn-glass.btn-glass-primary::before, .prism-ring::before { content: ""; position: absolute; inset: -1px; border-radius: inherit; padding: 1.75px; pointer-events: none; background: conic-gradient( from calc(var(--prism-angle) + 225deg), transparent 0deg, oklch(var(--prism-l) var(--prism-c) 25) 22deg, oklch(var(--prism-l) var(--prism-c) 70) 40deg, oklch(calc(var(--prism-l) + 0.06) var(--prism-c) 105) 58deg, oklch(var(--prism-l) var(--prism-c) 155) 76deg, oklch(var(--prism-l) var(--prism-c) 205) 94deg, oklch(calc(var(--prism-l) - 0.04) var(--prism-c) 265) 112deg, oklch(calc(var(--prism-l) - 0.04) var(--prism-c) 305) 128deg, transparent 152deg, transparent 196deg, oklch(var(--prism-l) var(--prism-c) 205 / 0.4) 226deg, oklch(calc(var(--prism-l) - 0.04) var(--prism-c) 305 / 0.4) 254deg, transparent 290deg ); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask-composite: exclude; opacity: var(--prism-ring); transition: --prism-angle 700ms var(--ease-pop), opacity var(--duration-base) var(--ease-standard); } .pill-primary::after, .btn-glass.btn-glass-primary::after, .prism-ring::after { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none; background: conic-gradient( from calc(var(--prism-angle) + 225deg), transparent 0deg, oklch(var(--prism-l) var(--prism-c) 25) 22deg, oklch(var(--prism-l) var(--prism-c) 70) 40deg, oklch(calc(var(--prism-l) + 0.06) var(--prism-c) 105) 58deg, oklch(var(--prism-l) var(--prism-c) 155) 76deg, oklch(var(--prism-l) var(--prism-c) 205) 94deg, oklch(calc(var(--prism-l) - 0.04) var(--prism-c) 265) 112deg, oklch(calc(var(--prism-l) - 0.04) var(--prism-c) 305) 128deg, transparent 152deg, transparent 196deg, oklch(var(--prism-l) var(--prism-c) 205 / 0.4) 226deg, oklch(calc(var(--prism-l) - 0.04) var(--prism-c) 305 / 0.4) 254deg, transparent 290deg ); filter: blur(5px); opacity: var(--prism-glow); transition: --prism-angle 700ms var(--ease-pop), opacity var(--duration-base) var(--ease-standard); } .pill-primary:hover::before, .btn-glass.btn-glass-primary:hover::before, .group:hover .prism-ring::before, .prism-ring:hover::before { --prism-angle: 32deg; opacity: 1; } .pill-primary:hover::after, .btn-glass.btn-glass-primary:hover::after, .group:hover .prism-ring::after, .prism-ring:hover::after { --prism-angle: 32deg; opacity: calc(var(--prism-glow) * 1.8); } .pill-primary:disabled::before, .pill-primary:disabled::after, .btn-glass.btn-glass-primary:disabled::before, .btn-glass.btn-glass-primary:disabled::after { --prism-angle: 0deg; filter: saturate(0.4); } @media (prefers-reduced-motion: reduce) { .pill-primary::before, .pill-primary::after, .btn-glass.btn-glass-primary::before, .btn-glass.btn-glass-primary::after, .prism-ring::before, .prism-ring::after { transition: opacity var(--duration-base) var(--ease-standard); } } /* 只要棱镜彩环与内侧淡光、不要胶囊底的宿主(如侧栏"前往流媒体"的播放键):彩环画在 宿主外沿,宿主本身不能 overflow:hidden;放在 .group 里时悬停整组也会点亮 */ .prism-ring { position: relative; isolation: isolate; } /* 侧栏"前往流媒体":点下去从播放键往外扩一圈七彩光再跳转(动漫站同一做法,光换成棱镜色) */ .stream-entry__burst { opacity: 0; transform: scale(1); background: conic-gradient( oklch(0.8 0.14 25), oklch(0.85 0.13 105), oklch(0.8 0.13 205), oklch(0.72 0.15 305), oklch(0.8 0.14 25) ); } .stream-entry--leaving .stream-entry__play { transform: scale(0.92); } .stream-entry--leaving .stream-entry__burst { animation: stream-entry-burst 360ms var(--ease-standard) both; } /* 流光图标:图标形状做遮罩,里面填和主按钮同一套的旋转光谱(如账户菜单里"流媒体"的三角)。 形状由 --prism-icon 给(SVG data URL),尺寸由调用处给 */ .prism-icon { display: block; flex-shrink: 0; background: conic-gradient( from var(--prism-angle), oklch(var(--prism-l) var(--prism-c) 25), oklch(var(--prism-l) var(--prism-c) 70), oklch(calc(var(--prism-l) + 0.06) var(--prism-c) 105), oklch(var(--prism-l) var(--prism-c) 155), oklch(var(--prism-l) var(--prism-c) 205), oklch(calc(var(--prism-l) - 0.04) var(--prism-c) 265), oklch(calc(var(--prism-l) - 0.04) var(--prism-c) 305), oklch(var(--prism-l) var(--prism-c) 25) ); -webkit-mask: var(--prism-icon) center / contain no-repeat; mask: var(--prism-icon) center / contain no-repeat; animation: prism-spin 6s linear infinite; } @media (prefers-reduced-motion: reduce) { .prism-icon { animation: none; } } /* 选中态:分页当前页、角标、选中的选项等"不是按钮但要标出来"的地方。静态、不实心 */ /* 选中态 = 有填充的 lens 玻璃:比次按钮多一层填充,边由方向性边光 + 加深的外侧暗线给 */ .pill-selected { background: var(--mat-pill-selected-bg); border: 1px solid transparent; box-shadow: var(--mat-lens-rim), 0 0 0 1px var(--mat-pill-selected-border); color: var(--content-strong); } /* 详情页头图(MediaHero):剧照层上下、右缘渐隐成透明,露出页面底色与光斑,不留硬边; ::after 是压在剧照上的底色渐变(左侧文字区近乎不透明),参数见 --mat-hero-* */ .media-hero-backdrop { -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 14%, #000 55%, transparent 100%), linear-gradient(to right, #000 0%, #000 90%, transparent 100%); -webkit-mask-composite: source-in; mask-image: linear-gradient(to bottom, transparent 0%, #000 14%, #000 55%, transparent 100%), linear-gradient(to right, #000 0%, #000 90%, transparent 100%); mask-composite: intersect; } .media-hero-backdrop > img { opacity: var(--mat-hero-image-opacity); } .media-hero-backdrop::after { content: ""; position: absolute; inset: 0; background: var(--mat-hero-scrim-stack); } @media (min-width: 640px) { .media-hero-backdrop::after { background: var(--mat-hero-scrim-side); } } /* 折叠的长文本(ClampText):最后一行行尾渐隐,「展开」压在渐隐处;行数由 --clamp-lines 给 */ .clamp-fade { max-height: calc(var(--clamp-lines, 3) * 1lh); overflow: hidden; -webkit-mask-image: linear-gradient(#000, #000), linear-gradient(to right, #000 62%, transparent 88%); -webkit-mask-size: 100% calc(100% - 1lh), 100% 1lh; -webkit-mask-position: top, bottom; -webkit-mask-repeat: no-repeat; mask-image: linear-gradient(#000, #000), linear-gradient(to right, #000 62%, transparent 88%); mask-size: 100% calc(100% - 1lh), 100% 1lh; mask-position: top, bottom; mask-repeat: no-repeat; } /* 按下回弹,与 .btn-glass 同一手感 */ .pill-primary:active, .pill-secondary:active { transform: scale(0.97); } /* 卡片聚光:鼠标所在处的卡面微微提亮(借鉴 Aceternity Card Spotlight)。 宿主挂 .pg-spotlight 并用 rippleMove 写入 --mx/--my;只在能悬停的设备上出现。 宿主的 ::after 归它用,亮度见 --mat-spotlight */ .pg-spotlight { isolation: isolate; } /* z-index:-1 + isolate:光铺在卡面底色之上、文字之下,不洗淡内容 */ .pg-spotlight::after { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none; background: radial-gradient(320px circle at var(--mx, 50%) var(--my, 50%), var(--mat-spotlight), transparent 70%); opacity: 0; transition: opacity var(--duration-layout) var(--ease-standard); } @media (hover: hover) { .pg-spotlight:hover::after { opacity: 1; } } /* 流媒体按钮(2026-09-26 起与门户胶囊同一外观):.btn-glass = 次操作(描边胶囊), .btn-glass-primary = 主操作(棱镜胶囊),.btn-glass-icon = 圆形图标钮。只保留各自的 尺寸与排版,底、边、字色、投影全部引用 --mat-pill-*,改外观只改那组参数 */ .btn-glass { @apply relative isolate inline-flex items-center gap-2 rounded-full px-6 py-2.5 text-[15px] font-medium tracking-tight cursor-pointer select-none overflow-hidden focus:outline-none focus-visible:ring-2 focus-visible:ring-content-strong/40; } .btn-glass, .btn-glass-icon { background: var(--mat-lens-fill); border: 1px solid transparent; box-shadow: var(--mat-lens-rim), var(--mat-lens-edge), var(--mat-lens-shadow); color: var(--content-strong); -webkit-backdrop-filter: var(--mat-lens-blur); backdrop-filter: var(--mat-lens-blur); transition: background-color var(--duration-base) var(--ease-standard), transform 220ms var(--ease-spring); } .btn-glass:hover, .btn-glass-icon:hover { background: var(--mat-lens-fill-hover); } /* LiquidSurface 只模糊不折射时(触屏、测速页、frost 面板):包在玻璃层顶部画的 50% 白光泽太亮, 夜间会压住第一行字。普通档收到很淡,frost(字多的面板)去掉 */ .liquid-surface-blur > :first-child { background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0) 35%) !important; } .liquid-surface-blur.liquid-surface-frost > :first-child { background-image: none !important; } /* 输入框 / 下拉选择触发器:淡底 + 1px 实边框,聚焦时边框加深并带一圈淡光晕; 调用处只给尺寸与内边距,不再各写底色、边框、阴影(由 Input / SelectTrigger 挂上) */ .field-glass { background: var(--mat-field-bg); /* 实打实的 1px 边框(不用阴影画线):阴影线太细,部分屏幕和浏览器上看不清输入框在哪 */ border: 1px solid var(--mat-field-edge); box-shadow: inset 0 1px 0 var(--mat-field-highlight); transition: box-shadow var(--duration-base) var(--ease-standard), background-color var(--duration-base) var(--ease-standard); } .field-glass:focus-visible, .field-glass:focus-within, .field-glass[data-state="open"] { outline: none; border-color: var(--mat-field-edge-focus); box-shadow: 0 0 0 3px var(--mat-field-ring); } .field-glass[aria-invalid="true"] { border-color: color-mix(in oklch, var(--destructive) 65%, transparent); } /* 登录类页面的表单卡片:内容卡的配方,但底换成实在的磨砂(夜间内容卡几乎透明,卡片、输入框、页面三层挤在一起分不开) */ .auth-card { --mat-slab-bg: var(--mat-auth-card-bg); --mat-slab-blur: blur(24px) saturate(160%); } /* 同 btn-glass 的 lens 玻璃外观,不带布局:尺寸会动画变化、不适合套 LiquidLens 折射的自定义控件 */ .lens-glass { background: var(--mat-lens-fill); box-shadow: var(--mat-lens-rim), var(--mat-lens-edge), var(--mat-lens-shadow); -webkit-backdrop-filter: var(--mat-lens-blur); backdrop-filter: var(--mat-lens-blur); } /* 小玻璃圆片 + 白色图标:glass-chip 跟随日夜(页面底上);glass-chip-media 恒为深烟色, 用于一切压在图片上的小控件(海报 / 缩略图的角标、状态圆片、悬停出现的操作键) */ .glass-chip, .glass-chip-media { display: grid; place-items: center; border-radius: 9999px; color: #ffffff; background: var(--mat-chip-glass); -webkit-backdrop-filter: blur(6px) saturate(160%); backdrop-filter: blur(6px) saturate(160%); box-shadow: inset 1px 1px 0 -0.25px rgba(255, 255, 255, 0.42), inset -1px -1px 0 -0.25px rgba(255, 255, 255, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.22); } .glass-chip-media { background: rgba(0, 0, 0, 0.32); } /* 套在 LiquidLens 里的按钮:玻璃由外层画(真折射),按钮自己不再铺底、不再模糊、不画边光 */ .btn-glass.btn-liquid, .btn-glass-icon.btn-liquid, .pill-primary.btn-liquid, .pill-secondary.btn-liquid { background: transparent; border-color: transparent; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; } .btn-glass.btn-liquid:hover, .btn-glass-icon.btn-liquid:hover, .btn-glass.btn-glass-primary.btn-liquid, .btn-glass.btn-glass-primary.btn-liquid:hover, .pill-primary.btn-liquid, .pill-primary.btn-liquid:hover, .pill-secondary.btn-liquid:hover { background: transparent; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; } .btn-glass.btn-liquid:hover, .btn-glass-icon.btn-liquid:hover, .btn-glass.btn-glass-primary.btn-liquid:hover, .pill-primary.btn-liquid:hover, .pill-secondary.btn-liquid:hover { background: rgba(255, 255, 255, 0.06); } .btn-glass:active, .btn-glass-icon:active { transform: scale(0.97); } .btn-glass-icon { @apply relative isolate grid place-items-center rounded-full w-11 h-11 cursor-pointer overflow-hidden focus:outline-none focus-visible:ring-2 focus-visible:ring-content-strong/40; } /* Stream image overlays */ /* 大图压暗层,取页面底色:夜间压暗、日间提亮(文字随主题深 / 浅) */ .hero-vignette { background: radial-gradient( circle at 70% 42%, transparent 0%, color-mix(in oklch, var(--canvas) 8%, transparent) 36%, color-mix(in oklch, var(--canvas) 92%, transparent) 100% ), linear-gradient( 90deg, color-mix(in oklch, var(--canvas) 92%, transparent) 0%, color-mix(in oklch, var(--canvas) 56%, transparent) 32%, color-mix(in oklch, var(--canvas) 10%, transparent) 66%, color-mix(in oklch, var(--canvas) 46%, transparent) 100% ), linear-gradient( 180deg, color-mix(in oklch, var(--canvas) 18%, transparent) 0%, transparent 36%, color-mix(in oklch, var(--canvas) 96%, transparent) 100% ); } /* 横向滚动行两侧的渐隐,取页面底色(日间原来是一道黑条) */ .row-fade-left { background: linear-gradient(90deg, var(--canvas) 0%, transparent 100%); } .row-fade-right { background: linear-gradient(270deg, var(--canvas) 0%, transparent 100%); } } /* ───────────────────────────── Animations ────────────────────────────── */ /* .pg-beam 的旋转角:注册为 才能被动画插值(普通自定义属性 只能离散跳变);@property 不允许出现在 @layer 内,故放此处 */ @property --pg-beam-angle { syntax: ""; initial-value: 0deg; inherits: false; } /* 主按钮棱镜环的旋转角,同理需注册 */ @property --prism-angle { syntax: ""; initial-value: 0deg; inherits: false; } @keyframes prism-spin { to { --prism-angle: 360deg; } } @keyframes stream-entry-burst { from { opacity: 0.6; transform: scale(1); } to { opacity: 0; transform: scale(2.6); } } @keyframes pg-beam-spin { to { --pg-beam-angle: 360deg; } } @keyframes fade-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } /* 播放器弹出层:比 fade-in 快得多(200ms)并带轻微 scale,从触发按钮方向 "弹"出来(配 origin-bottom-right)。菜单是高频操作,520ms 的入场太拖 */ @keyframes ticker-in { from { opacity: 0; transform: translateY(100%); } to { opacity: 1; transform: none; } } @keyframes ticker-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-100%); } } @keyframes pg-pop { from { opacity: 0; transform: translateY(6px) scale(0.97); } to { opacity: 1; transform: translateY(0) scale(1); } } /* 页面入场:从轻微失焦到清晰,只播一次(借鉴 Arc 的 blur-in;调用处用 motion-safe: 前缀,减少动态效果时直接显示)。填充模式用 backwards 而不是 both: 播完不能留下 filter/transform,否则页面里 position:fixed 的元素会改以这层为参照 */ @keyframes blur-in { from { opacity: 0; filter: blur(6px); transform: translateY(8px); } to { opacity: 1; filter: blur(0); transform: translateY(0); } } @keyframes hero-fade { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } } @keyframes ken-burns { from { transform: translateY(var(--parallax, 0)) scale(1.02); } to { transform: translateY(var(--parallax, 0)) scale(1.08); } } @keyframes shiny-text { 0%, 90%, 100% { background-position: calc(-100% - var(--shiny-width)) 0; } 30%, 60% { background-position: calc(100% + var(--shiny-width)) 0; } } @keyframes fadeUp { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } } @keyframes player-flash { 0% { opacity: 0; transform: scale(0.55); } 12% { opacity: 1; transform: scale(1.06); } 18%, 75% { opacity: 1; transform: scale(1); } 100% { opacity: 0; transform: scale(1.15); } } .animate-shiny-text { animation: shiny-text 8s infinite; } .animate-player-flash { animation: player-flash var(--player-flash-dur, 1500ms) var(--ease-standard) forwards; } ::view-transition-old(play-card), ::view-transition-new(play-card) { animation-duration: 360ms; animation-timing-function: var(--ease-sheet); } /* 主题切换的渐进过渡(theme-toggle.tsx):走 View Transitions 默认的 交叉淡化(plus-lighter 混合),这里只把 UA 默认的 250ms 放缓到 420ms 并换成标准减速曲线,让明暗互换从容一些。scoped 在 .theme-vt 下, 不影响其它 view transition(play-card 的导航过渡仍走默认时长)。 */ :root.theme-vt::view-transition-old(root), :root.theme-vt::view-transition-new(root) { animation-duration: 420ms; animation-timing-function: var(--ease-standard); }