/* 浏览器街机 —— 设计系统 来自 Claude Design「浏览器街机 · 试玩站首页」。变量名与数值保持一致, 便于日后与设计稿对照。 */ *, *::before, *::after { box-sizing: border-box; } :root { --void: oklch(0.21 0.035 295); --void-2: oklch(0.27 0.045 295); --panel: oklch(0.32 0.05 295); --edge: oklch(0.43 0.055 295); --ink: oklch(0.93 0.02 295); --dim: oklch(0.70 0.035 295); --neon-a: oklch(0.72 0.25 350); --neon-b: oklch(0.72 0.25 195); --neon-c: oklch(0.72 0.25 95); --live: oklch(0.78 0.2 150); --latin: "Space Grotesk", sans-serif; --cjk: "PingFang SC", "Microsoft YaHei", "Noto Sans SC", sans-serif; --mono: "IBM Plex Mono", ui-monospace, Consolas, monospace; --shell: 1180px; } body { margin: 0; background: var(--void); color: var(--ink); font-family: var(--cjk); -webkit-font-smoothing: antialiased; } a { color: var(--neon-b); text-decoration: none; } a:hover { color: var(--neon-a); } button { font: inherit; } /* CRT 扫描线与暗角。fixed + pointer-events:none,不影响任何交互。 * * 两张渐变抽成变量,是因为**全屏时要再画一遍**:全屏元素会被提升到顶层 * (top layer),渲染在普通文档流之上,而这两个伪元素挂在页面级的 .crt 上、 * 不属于那一层,于是整个被压在画面底下 —— 表现就是一进全屏画面突然变"生"。 * 补画的那份在 playroom.html 的 .stage-wrap:fullscreen 里。 * 抄一遍数值迟早会分岔,所以让两处引用同一个来源。 */ /* 扫描线的四个尺寸抽成变量,好让有画布的页面按**画面的实际放大倍数**改写它们 * (见 assets/crt-scan.js)。周期钉死在屏幕像素上时,一进全屏 320×224 被放大 * 五六倍,一条扫描线就横跨三四行源像素,条纹与游戏自己的像素网格错开 —— 那才是 * "全屏显得生"的真正原因。 * * 这里的默认值**逐像素等于改动之前**(0~2 透明、2~3 过渡、3~4 实心,周期 4), * 所以没有画布的页面(首页、论坛、排行…)观感一点没变。 */ :root { --crt-scan-period: 4px; /* 一个明暗周期 */ --crt-scan-dark: 1px; /* 其中实心暗带的厚度 */ --crt-scan-ramp: 1px; /* 暗带前面那段渐变过渡,去掉会显得像栅栏 */ /* 2026-08-11 整体调亮一档。原来是 0.26 / 暗角 0.52,合起来把页面边缘压到只剩 底色的 43%(--void 的 L 本来就只有 0.12,是设计稿定的,不该动)。 效果层是我们自己加的,要提亮就动它 —— 别去改设计系统的配色。 现在:扫描线平均遮蔽 9.8% → 7.5%,边缘保留 43% → 61%。 */ --crt-scan-alpha: 0.20; --crt-scan-phase: 0px; /* 纵向相位,用来把暗带对齐到源像素行的交界 */ --crt-scanlines: repeating-linear-gradient(to bottom, rgba(0,0,0,0) 0px, rgba(0,0,0,0) calc(var(--crt-scan-period) - var(--crt-scan-dark) - var(--crt-scan-ramp)), rgba(0,0,0,var(--crt-scan-alpha)) calc(var(--crt-scan-period) - var(--crt-scan-dark)), rgba(0,0,0,var(--crt-scan-alpha)) var(--crt-scan-period)); /* 暗角的浓度也抽出来:纯 CSS 那档做不了桶形畸变,「边缘曲面度」这个滑块 在那一档只能落到它能做的边缘效果上 —— 暗角浓度加圆角。 */ --crt-vig-alpha: 0.32; --crt-vignette: radial-gradient(ellipse 80% 70% at 50% 42%, rgba(0,0,0,0) 42%, rgba(0,0,0,var(--crt-vig-alpha)) 100%); } .crt::before { content: ""; position: fixed; inset: 0; z-index: 90; pointer-events: none; /* 用 background-image 而不是 background 简写:简写会把 background-position 一并重置成 0 0,相位就永远对不上了。 */ background-image: var(--crt-scanlines); background-position: 0 var(--crt-scan-phase); mix-blend-mode: multiply; } .crt::after { content: ""; position: fixed; inset: 0; z-index: 91; pointer-events: none; background: var(--crt-vignette); } .fx { display: flex; } .col { flex-direction: column; } .ac { align-items: center; } .g6{gap:6px} .g10{gap:10px} .g14{gap:14px} .g16{gap:16px} .g20{gap:20px} .g28{gap:28px} .g32{gap:32px} .shell { width: 100%; max-width: var(--shell); margin: 0 auto; padding: 0 32px; } .nav { display:flex; align-items:center; justify-content:space-between; padding:22px 0; flex-wrap:wrap; gap:14px; } .nav-logo { font-family:"Monoton", var(--latin); font-size:19px; color:var(--neon-a); text-shadow:0 0 4px oklch(0.72 0.25 350 / .8); white-space:nowrap; flex-shrink:0; } .nav-logo .b { color:var(--neon-b); text-shadow:0 0 4px oklch(0.72 0.25 195 / .8); } .nav-links { display:flex; gap:26px; align-items:center; font-family:var(--mono); font-size:11.5px; letter-spacing:.1em; text-transform:uppercase; } .nav-links a, .nav-links button { color:var(--dim); white-space:nowrap; background:none; border:0; cursor:pointer; font-family:var(--mono); font-size:11.5px; letter-spacing:.1em; text-transform:uppercase; padding:0; } .nav-links a:hover, .nav-links button:hover { color:var(--neon-b); } .nav-links a.active { color:var(--ink); } .nav-me { color:var(--ink) !important; } .wordmark { font-family:"Monoton", var(--latin); font-size:clamp(40px,7.4vw,88px); line-height:.98; letter-spacing:.02em; color:var(--neon-a); text-shadow:0 0 6px oklch(0.72 0.25 350 / .9),0 0 22px oklch(0.72 0.25 350 / .55),0 0 56px oklch(0.72 0.25 350 / .32); } .wordmark .b { color:var(--neon-b); text-shadow:0 0 6px oklch(0.72 0.25 195 / .9),0 0 22px oklch(0.72 0.25 195 / .55),0 0 56px oklch(0.72 0.25 195 / .32); } .pitch { font-size:23px; font-weight:500; line-height:1.5; letter-spacing:.02em; max-width:24ch; text-wrap:pretty; } .instant { font-family:var(--mono); font-size:13px; letter-spacing:.12em; color:var(--neon-c); } .live-bar { display:flex; align-items:center; gap:22px; flex-wrap:wrap; font-family:var(--mono); font-size:12.5px; color:var(--dim); letter-spacing:.06em; } .dot { width:7px; height:7px; border-radius:50%; background:var(--live); box-shadow:0 0 8px var(--live); display:inline-block; } .dot.off { background:var(--dim); box-shadow:none; } .live-n { color:var(--live); font-weight:500; } .coin { display:inline-flex; align-items:center; gap:14px; padding:18px 36px; border:1px solid var(--neon-c); font-size:17px; font-weight:700; color:var(--void); background:var(--neon-c); cursor:pointer; clip-path:polygon(13px 0,100% 0,100% calc(100% - 13px),calc(100% - 13px) 100%,0 100%,0 13px); box-shadow:0 0 26px oklch(0.72 0.25 95 / .45),0 0 68px oklch(0.72 0.25 95 / .2); transition:box-shadow .18s ease, transform .18s ease; } .coin:hover { color:var(--void); box-shadow:0 0 10px oklch(0.72 0.25 95 / .7); transform:translateY(2px); } .coin .slot { font-family:var(--mono); font-size:12px; letter-spacing:.18em; opacity:.7; } .ghost { display:inline-flex; align-items:center; padding:17px 28px; border:1px solid var(--edge); color:var(--ink); font-size:15px; font-weight:500; cursor:pointer; background:none; transition:border-color .18s ease, color .18s ease; } .ghost:hover { border-color:var(--neon-b); color:var(--neon-b); } .sect-label { font-family:var(--mono); font-size:11px; letter-spacing:.3em; text-transform:uppercase; color:var(--dim); display:flex; align-items:center; gap:14px; } .sect-label::after { content:""; height:1px; flex:1; background:var(--edge); } .sect-cn { font-size:19px; font-weight:700; letter-spacing:.04em; } .sect-note { font-size:13.5px; color:var(--dim); } .btn { font-size:13px; font-weight:500; padding:9px 14px; border:1px solid var(--edge); color:var(--ink); background:none; cursor:pointer; white-space:nowrap; flex-shrink:0; transition:border-color .16s ease,color .16s ease,background .16s ease; } .btn:hover { border-color:var(--neon-b); color:var(--neon-b); } .btn.hot { border-color:var(--neon-a); color:var(--neon-a); } .btn.hot:hover { background:var(--neon-a); color:var(--void); } .btn.big { padding:15px 30px; font-size:14.5px; font-weight:700; } .btn[disabled] { opacity:.4; cursor:not-allowed; } .btn[disabled]:hover { border-color:var(--edge); color:var(--ink); background:none; } .foot { font-family:var(--mono); font-size:11.5px; color:var(--dim); letter-spacing:.06em; } /* 游戏墙 */ .wall-cols { display:grid; grid-template-columns:repeat(auto-fit,minmax(420px,1fr)); gap:40px; } .col-h { display:flex; align-items:baseline; gap:10px; padding-bottom:10px; border-bottom:1px solid var(--edge); } .col-h-cn { font-size:16px; font-weight:700; } .col-h-en { font-family:var(--mono); font-size:10px; letter-spacing:.2em; text-transform:uppercase; color:var(--dim); } .col-h-hint { font-size:11.5px; color:var(--dim); margin-left:auto; } .b-feat { border:1px solid var(--edge); border-left:2px solid var(--edge); overflow:hidden; background:var(--void-2); } .b-feat-img { height:190px; position:relative; } .b-marq { padding:16px 18px; display:flex; align-items:center; justify-content:space-between; gap:14px; flex-wrap:wrap; border-top:1px solid var(--edge); } .b-nm { font-size:16px; font-weight:700; line-height:1.25; } .gname-en { font-family:var(--mono); font-size:10px; letter-spacing:.13em; text-transform:uppercase; color:var(--dim); line-height:1.5; } .b-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:10px; } .b-tile { border:1px solid var(--edge); overflow:hidden; background:var(--void-2); transition:border-color .18s ease; } .b-tile:hover { border-color:var(--neon-a); } .b-tile.off:hover { border-color:var(--edge); } .b-tile-img { height:108px; position:relative; } .b-tile-marq { padding:9px 11px; display:flex; align-items:center; justify-content:space-between; gap:8px; border-top:1px solid var(--edge); } .b-nm-s { font-size:13px; font-weight:700; line-height:1.25; } .live { display:inline-flex; align-items:center; gap:6px; font-family:var(--mono); font-size:11px; color:var(--dim); } .live b { color:var(--live); font-weight:500; } /* 整张截图就是入口。截图本身没有任何「这能点」的信号,鼠标悬上去压一层 半透明的「点击进入」把它说明白 —— 否则一整块图看着就是张静态插画。 */ .img-link { display:block; position:relative; } .img-hover { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; background:oklch(0.21 0.035 295 / .55); color:var(--ink); font-size:14px; font-weight:700; letter-spacing:.04em; opacity:0; transition:opacity .15s ease; } .img-link:hover .img-hover { opacity:1; } .img-hover.sm { font-size:12.5px; } /* 没有 ROM 的游戏:整块压暗,不给任何可点的入口。 */ .off { opacity:.42; } .off .b-nm, .off .b-nm-s { color:var(--dim); } .tag-off { font-family:var(--mono); font-size:10px; letter-spacing:.1em; padding:3px 7px; border:1px solid var(--edge); color:var(--dim); white-space:nowrap; } /* 缩略图占位:没有截图素材,用游戏名首字生成一块霓虹色卡, 比灰底占位图更像个街机柜。 */ .thumb { width:100%; height:100%; display:flex; align-items:center; justify-content:center; font-family:"Monoton", var(--latin); font-size:34px; letter-spacing:.06em; position:relative; overflow:hidden; } .thumb::after { content:""; position:absolute; inset:0; background:repeating-linear-gradient(to bottom, rgba(0,0,0,0) 0 2px, rgba(0,0,0,.22) 3px 4px); } .thumb span { position:relative; z-index:1; font-family:var(--cjk); font-weight:700; font-size:24px; } .grid-lobby { display:grid; grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); gap:40px; } .row { display:flex; align-items:center; justify-content:space-between; gap:16px; padding:13px 0; border-bottom:1px solid var(--edge); } .row-main { display:flex; flex-direction:column; gap:4px; min-width:0; } .row-t { font-size:14.5px; font-weight:500; } .row-s { font-family:var(--mono); font-size:11.5px; color:var(--dim); } .empty { font-size:13px; color:var(--dim); padding:16px 0; } .grid-acct { display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:14px; } .acct { display:flex; flex-direction:column; gap:10px; padding:22px 24px; background:var(--void-2); border:1px solid var(--edge); } .acct.on { border-color:var(--neon-b); } .acct-t { font-size:16px; font-weight:700; } .acct-b { font-size:13.5px; line-height:1.8; color:var(--dim); text-wrap:pretty; } .notice { font-size:13px; line-height:1.85; color:var(--dim); padding:18px 22px; background:var(--void-2); border-left:2px solid var(--neon-c); max-width:76ch; text-wrap:pretty; } .notice b { color:var(--ink); font-weight:700; } /* 弹窗(登录/注册) */ .mask { position:fixed; inset:0; z-index:100; background:rgba(0,0,0,.72); display:flex; align-items:center; justify-content:center; padding:24px; } .modal { background:var(--void-2); border:1px solid var(--edge); padding:28px; width:100%; max-width:380px; } .modal h3 { margin:0 0 4px; font-size:18px; } .modal p.sub { margin:0 0 18px; font-size:12.5px; color:var(--dim); } .field { display:flex; flex-direction:column; gap:6px; margin-bottom:14px; } .field label { font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--dim); } .field input { background:var(--void); border:1px solid var(--edge); color:var(--ink); padding:10px 12px; font-family:var(--cjk); font-size:14px; outline:none; } .field input:focus { border-color:var(--neon-b); } .err { color:var(--neon-a); font-size:12.5px; min-height:18px; } .toast { position:fixed; left:50%; bottom:32px; transform:translateX(-50%); z-index:120; background:var(--panel); border:1px solid var(--neon-b); color:var(--ink); padding:12px 20px; font-size:13.5px; box-shadow:0 0 24px rgba(0,0,0,.5); } @media (prefers-reduced-motion: no-preference) { .rise { animation: rise .7s cubic-bezier(.22,.7,.3,1) backwards; } .d1{animation-delay:.05s} .d2{animation-delay:.15s} .d3{animation-delay:.25s} .d4{animation-delay:.35s} @keyframes rise { from { opacity:0; transform:translateY(16px); } } .powerup { animation: powerup 1.05s steps(1) backwards; } @keyframes powerup { 0%{opacity:0} 22%{opacity:1} 30%{opacity:.25} 38%{opacity:1} 46%{opacity:.5} 54%{opacity:1} } }