@import "tailwindcss"; @import "tw-animate-css"; @import "shadcn/tailwind.css"; /* ───────────────────────── Tailwind configuration ───────────────────────── */ @custom-variant dark (&:is(.dark *), &:is([data-force-dark] *)); @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; --animate-pg-pop: pg-pop 200ms var(--ease-pop) both; /* 播放器加载提示的滚动字幕:新一行从下方滚入,上一行向上滚出 */ --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-auth-title: clamp(2rem, 3.4vw, 3.4rem); --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 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.68); --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.16); --mat-pill-highlight: rgba(255, 255, 255, 0.18); --mat-pill-shade: rgba(0, 0, 0, 0.25); --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.7); --mat-slab-blur: blur(20px) saturate(160%); --mat-slab-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85), 0 0 0 1px rgba(20, 22, 28, 0.04), 0 1px 2px rgba(20, 22, 28, 0.05), 0 12px 28px -18px rgba(20, 22, 28, 0.16); --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: 8px 0 24px -20px rgba(20, 22, 28, 0.25); --mat-chrome-solid: rgba(255, 255, 255, 0.95); /* float:门户小型悬浮面板 */ --mat-float-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.82) 100%); --mat-float-blur: blur(28px) saturate(170%); --mat-float-border: rgba(255, 255, 255, 0.75); --mat-float-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 0 0 1px rgba(20, 22, 28, 0.05), 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); /* 胶囊按钮:主操作是有填充的薄玻璃,次操作只描边。日夜对称——夜间白色薄玻璃配白字, 日间墨色薄玻璃配深字;不做实心黑 / 实心白 */ --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: 0.9; --prism-glow: 0.16; /* 选中态(分页当前页、角标、选中的选项):静态半透明 + 稍深描边,不转动、不实心 */ --mat-pill-selected-bg: rgba(20, 22, 28, 0.07); --mat-pill-selected-border: rgba(20, 22, 28, 0.28); --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); /* 分段控件的滑块(侧栏当前项、SegmentedTabs):日间是托起的白片,夜间是薄白玻璃 */ --mat-seg-thumb-bg: rgba(255, 255, 255, 0.8); --mat-seg-thumb-border: rgba(20, 22, 28, 0.06); --mat-seg-thumb-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95), 0 3px 12px -3px rgba(20, 22, 28, 0.18); /* notice:更新提示胶囊 */ --mat-notice-fg: var(--foreground); --mat-notice-bg: rgba(255, 255, 255, 0.78); --mat-notice-blur: blur(24px) saturate(160%); --mat-notice-border: rgba(255, 255, 255, 0.85); --mat-notice-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95), 0 0 0 1px color-mix(in oklch, var(--primary) 12%, transparent), 0 14px 36px -14px rgba(20, 22, 28, 0.35), 0 3px 10px -4px rgba(20, 22, 28, 0.12); --mat-notice-sub-fg: var(--muted-foreground); --mat-notice-icon-fg: var(--primary); --mat-notice-icon-bg: color-mix(in oklch, var(--primary) 12%, transparent); --mat-notice-ring: 0 0 0 0 color-mix(in oklch, var(--primary) 45%, transparent); --mat-notice-cta-fg: var(--primary-foreground); --mat-notice-cta-bg: var(--primary); --mat-notice-cta-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 6px 16px -8px color-mix(in oklch, var(--primary) 70%, transparent); --mat-notice-close-fg: var(--muted-foreground); --mat-notice-close-hover-fg: var(--foreground); --mat-notice-close-hover-bg: rgba(0, 0, 0, 0.06); /* 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.1); --mat-slab-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), inset 0 -1px 0 rgba(255, 255, 255, 0.03), 0 1px 2px rgba(0, 0, 0, 0.2), 0 12px 28px -18px rgba(0, 0, 0, 0.4); --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.04); --mat-chrome-solid: rgba(12, 13, 17, 0.92); --mat-float-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.035) 32%, rgba(255, 255, 255, 0) 62%), rgba(20, 21, 25, 0.9); --mat-float-solid: rgb(22, 23, 27); --mat-float-blur: blur(36px) saturate(180%); --mat-float-border: rgba(255, 255, 255, 0.14); /* 胶囊按钮:夜间主操作是白色玻璃 */ --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: 0.85; --prism-glow: 0.22; --mat-pill-selected-bg: rgba(255, 255, 255, 0.1); --mat-pill-selected-border: rgba(255, 255, 255, 0.32); --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-seg-thumb-bg: rgba(255, 255, 255, 0.08); --mat-seg-thumb-border: rgba(255, 255, 255, 0.15); --mat-seg-thumb-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 4px 18px -6px rgba(0, 0, 0, 0.4); --mat-float-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), inset 0 -1px 0 rgba(255, 255, 255, 0.03), 0 2px 6px -2px rgba(0, 0, 0, 0.22), 0 18px 40px -20px rgba(0, 0, 0, 0.4); --mat-notice-bg: rgba(255, 255, 255, 0.08); --mat-notice-border: rgba(255, 255, 255, 0.14); --mat-notice-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), inset 0 -1px 0 rgba(0, 0, 0, 0.25), 0 16px 40px -16px rgba(0, 0, 0, 0.55); --mat-notice-close-hover-bg: rgba(255, 255, 255, 0.08); } /* ───────────────────────────── 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; } /* 流媒体手机端有 3.5rem 的底部 Tab Bar:全局右下角浮层(更新提示)按这个 变量再垫高,免得压在 Tab Bar 上。播放页不渲染 Tab Bar,不设。 */ @media (max-width: 767px) { :root:has([data-stream-shell="page"]) { --uhd-bottom-dock: 3.5rem; } } 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); box-shadow: inset 0 1px 0 var(--mat-pill-highlight), inset 0 -1px 0 var(--mat-pill-shade), var(--mat-pill-shadow); } /* ─── 更新提示胶囊(app/components/update-notice.tsx)────────────── 三处材质各归各:浅色门户 = 白磨砂玻璃 + 蓝调投影(pg-slab 浅色配方的 简化版);深色门户 = 白透玻璃(侧栏药丸同款);流媒体壳 = 同深色配方, 动作钮换金色 —— 那边的强调色是金不是蓝。 */ .update-pill { color: var(--mat-notice-fg); background: var(--mat-notice-bg); backdrop-filter: var(--mat-notice-blur); -webkit-backdrop-filter: var(--mat-notice-blur); border: 1px solid var(--mat-notice-border); box-shadow: var(--mat-notice-shadow); } .update-pill__sub { color: var(--mat-notice-sub-fg); } .update-pill__icon { color: var(--mat-notice-icon-fg); background: var(--mat-notice-icon-bg); } .update-pill__icon--stale { color: var(--warning); background: color-mix(in oklch, var(--warning) 14%, transparent); } /* 一圈慢呼吸的光环,提醒但不催 */ .update-pill__ring { box-shadow: var(--mat-notice-ring); animation: update-pill-ring 2.4s ease-out infinite; } .update-pill__cta { color: var(--mat-notice-cta-fg); background: var(--mat-notice-cta-bg); box-shadow: var(--mat-notice-cta-shadow); } .update-pill__close { color: var(--mat-notice-close-fg); } .update-pill__close:hover { color: var(--mat-notice-close-hover-fg); background: var(--mat-notice-close-hover-bg); } @media (prefers-reduced-motion: reduce) { .update-pill__ring { animation: none; } } /* 第四档:内容卡片,双主题(门户与 /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); } .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。悬浮物打开时是静态的,可以放心用 backdrop-filter。 */ .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); } /* 嵌在另一层磨砂里的菜单(页头、筛选栏、卡片内的下拉):外层磨砂是 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); } } /* 吸顶筛选条与顶栏之间的接缝:一条无彩细线,两端淡出,随日夜取 --wash */ .chrome-seam-top { position: relative; } .chrome-seam-top::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 1px; background: linear-gradient( 90deg, transparent 0%, color-mix(in oklch, var(--wash) 8%, transparent) 12%, color-mix(in oklch, var(--wash) 12%, transparent) 50%, color-mix(in oklch, var(--wash) 8%, transparent) 88%, transparent 100% ); pointer-events: none; } /* 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 { background: var(--mat-pill-secondary-bg); border: 1px solid var(--mat-pill-secondary-border); color: var(--content); -webkit-backdrop-filter: blur(20px) saturate(160%); backdrop-filter: blur(20px) saturate(160%); transition: background-color var(--duration-base) var(--ease-standard), transform 220ms var(--ease-spring); } .pill-secondary:hover { background: var(--mat-pill-secondary-bg-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-pill-primary-bg); border: 1px solid transparent; color: var(--mat-pill-primary-fg); box-shadow: var(--mat-pill-primary-shadow); -webkit-backdrop-filter: blur(20px) saturate(160%); backdrop-filter: blur(20px) saturate(160%); 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-pill-primary-bg-hover); } .pill-primary::before, .btn-glass.btn-glass-primary::before, .prism-ring::before { content: ""; position: absolute; inset: -1px; border-radius: inherit; padding: 1.5px; pointer-events: none; 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: 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: opacity var(--duration-base) var(--ease-standard); animation: prism-spin 6s linear infinite; } .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 var(--prism-angle), 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) ); filter: blur(10px); opacity: var(--prism-glow); transition: opacity var(--duration-base) var(--ease-standard); animation: prism-spin 6s linear infinite; } .pill-primary:hover::before, .btn-glass.btn-glass-primary:hover::before, .group:hover .prism-ring::before, .prism-ring:hover::before { opacity: 1; } .pill-primary:hover::after, .btn-glass.btn-glass-primary:hover::after, .group:hover .prism-ring::after, .prism-ring:hover::after { opacity: calc(var(--prism-glow) * 1.6); } .pill-primary:disabled::before, .pill-primary:disabled::after, .btn-glass.btn-glass-primary:disabled::before, .btn-glass.btn-glass-primary:disabled::after { animation: none; } @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 { animation: none; } } /* 只要棱镜彩环与内侧淡光、不要胶囊底的宿主(如侧栏"前往流媒体"的播放键):彩环画在 宿主外沿,宿主本身不能 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; } } /* 选中态:分页当前页、角标、选中的选项等"不是按钮但要标出来"的地方。静态、不实心 */ .pill-selected { background: var(--mat-pill-selected-bg); border: 1px solid var(--mat-pill-selected-border); color: var(--content-strong); } /* 按下回弹,与 .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-pill-secondary-bg); border: 1px solid var(--mat-pill-secondary-border); color: var(--content-strong); -webkit-backdrop-filter: blur(20px) saturate(160%); backdrop-filter: blur(20px) saturate(160%); transition: background-color var(--duration-base) var(--ease-standard), transform 220ms var(--ease-spring); } .btn-glass:hover, .btn-glass-icon:hover { background: var(--mat-pill-secondary-bg-hover); } .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); } @keyframes update-pill-ring { 0% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--primary) 45%, transparent); opacity: 1; } 70% { box-shadow: 0 0 0 10px color-mix(in oklch, var(--primary) 0%, transparent); opacity: 0; } 100% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--primary) 0%, transparent); opacity: 0; } }