@@ -0,0 +1,356 @@
{{define "layout"}}<!doctype html>
< html lang = "{{.Lang}}" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width,initial-scale=1,viewport-fit=cover" >
< meta name = "theme-color" content = "#f4eedd" >
< title > {{template "title" .}}< / title >
< meta name = "description" content = "{{if .Desc}}{{.Desc}}{{else}}{{T " 赛博要饭 : 行行好 , 赏口饭吃 。 用币安 Pay 投币施舍 , 留一句话上功德簿 ; 不花钱也能丢钢镚 ; 用 X 发一条推就能开自己的要饭站 。 " } } { { end } } " >
< meta property = "og:title" content = "{{template " title " . } } " >
< meta property = "og:description" content = "{{if .Desc}}{{.Desc}}{{else}}{{T " 行行好 , 赏口饭吃 。 投币上功德簿 , 丢钢镚也算爱 。 " } } { { end } } " >
< meta property = "og:type" content = "website" >
{{if .OGImage}}< meta property = "og:image" content = "{{.OGImage}}" > {{end}}
< meta name = "twitter:card" content = "summary" >
< link rel = "icon" href = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E🥣%3C/text%3E%3C/svg%3E" >
{{if .NoIndex}}< meta name = "robots" content = "noindex" > {{end}}
< link rel = "preload" href = "/static/pixel.woff2" as = "font" type = "font/woff2" crossorigin >
< style >
@font-face{font-family:"Pixel";src:url(/static/pixel.woff2) format("woff2");font-display:swap}
:root{--ink:#1e1e2e;--paper:#f4eedd;--paper-2:#e9e1ca;--panel:#fffbf0;--panel-2:#fff3cc;--gold:#ffcc00;--gold-2:#e0a800;--red:#ff4b4b;--green:#3ec46d;--blue:#3d8bfd;--purple:#8e5cff;--muted:#4a4954;--muted-2:#6f6d66;--pf:"Pixel","PingFang SC","Noto Sans SC","Microsoft YaHei",sans-serif;--line:#d9d0b8;--frame:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='6' height='6' shape-rendering='crispEdges'%3E%3Cpath fill='%231e1e2e' d='M1 0h4v1H1zM0 1h6v1H0zM0 2h2v2H0zM4 2h2v2H4zM0 4h6v1H0zM1 5h4v1H1z'/%3E%3C/svg%3E")}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;overflow-x:hidden}
html,body{max-width:100%;overscroll-behavior-x:none}
@media(max-width:899px){body{overflow-x:hidden;position:relative}}
body{margin:0;color:var(--ink);background-color:var(--paper);background-image:linear-gradient(45deg,var(--paper-2) 25%,transparent 25%,transparent 75%,var(--paper-2) 75%),linear-gradient(45deg,var(--paper-2) 25%,transparent 25%,transparent 75%,var(--paper-2) 75%);background-size:16px 16px;background-position:0 0,8px 8px;font:15px/1.7 -apple-system,BlinkMacSystemFont,"PingFang SC","Noto Sans SC","Hiragino Sans GB","Microsoft YaHei","Helvetica Neue",Arial,sans-serif;min-height:100vh}
.pf,h1,h2,.brand,.ticker,.lv,.pname,.stat .v,.stat .k,.amt-btn,.btn,.tab,.amtv,.rank,.insert,.barlabel,.tag,.nav a,.name,.av,.section-title,.copy,.anchors a,.step::before,.big,.dialog,.me,.count,.card h2 .sub,.kv .k,.empty .ico{font-family:var(--pf)}
.pf12{font-size:12px}
a{color:var(--blue)}
.num{font-variant-numeric:tabular-nums}
.accent{color:var(--gold-2)}
.page{max-width:1080px;margin:0 auto;padding:0 16px 96px}
@media(min-width:900px){.page{padding-bottom:40px}}
.px{border:4px solid transparent;border-image:var(--frame) 2 / 4px stretch;image-rendering:pixelated;background-clip:padding-box}
.nav{display:flex;align-items:center;gap:6px;height:64px}
.langsel{display:inline-flex;align-items:center;flex:none;position:relative;cursor:pointer}.langsel select{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;font-size:16px}
.langcur{display:inline-flex;align-items:center;gap:2px;font-family:var(--pf);font-size:14px;line-height:1;color:var(--ink);background:#fff;border:2px solid var(--ink);box-shadow:2px 2px 0 var(--ink);padding:5px 6px;min-width:34px;justify-content:center}
.langcur i{font-style:normal;font-size:9px;opacity:.6}
.sfx{background:none;border:0;line-height:0;padding:8px 4px;cursor:pointer;min-width:34px;min-height:36px;display:inline-flex;align-items:center;justify-content:center;flex:none}
.px-spk .spk-x{display:none}.sfx.off .spk-w1,.sfx.off .spk-w2{display:none}.sfx.off .spk-x{display:inline}
.sfx.idle .spk-w2{opacity:.25}
.navlogin{display:inline-flex;align-items:center;gap:5px}.px-key{flex:none}
.navrank{display:inline-flex;align-items:center;gap:5px}.px-trophy{flex:none}
.sfx.idle{animation:sfxnudge 1.2s ease-in-out infinite}@keyframes sfxnudge{0%,100%{transform:scale(1)}50%{transform:scale(1.18)}}@media(prefers-reduced-motion:reduce){.sfx.idle{animation:none}}
.nav>*{flex:none}.nav .brand{flex:0 1 auto;min-width:0}.nav .brand span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media(max-width:430px){.nav{gap:4px}.nav .brand{font-size:20px;margin-right:2px}.nav .brand .px-coin{display:none}.sfx{min-width:28px;padding:6px 2px;font-size:16px}.nav a.link{padding:8px 5px;font-size:15px}.nav a.pill{padding:6px 10px;font-size:15px}
.nav a.navrank span{display:none}.nav .navlogin .lbl{display:none}}
.brand{display:flex;align-items:center;gap:8px;font-size:24px;line-height:1;color:var(--ink);text-decoration:none;white-space:nowrap;margin-right:6px}
.brand .px-coin{width:28px;height:28px;flex:none}
.nav .sp{flex:1}
.nav a.link{color:var(--ink);text-decoration:none;font-size:16px;padding:8px 8px;white-space:nowrap}
.nav a.link:hover{background:var(--panel-2)}
.nav a.pill{color:var(--ink);background:var(--gold);font-size:16px;padding:6px 12px;text-decoration:none;white-space:nowrap;box-shadow:3px 3px 0 var(--ink)}
.nav a.pill:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--ink)}
@media(max-width:420px){.hide-sm{display:none}.nav a.pill{font-size:12px;padding:6px 10px}.nav a.link{font-size:12px;padding:8px 5px}}
.ticker{overflow:hidden;contain:paint;touch-action:pan-y;background:var(--ink);color:var(--gold);font-size:12px;line-height:1.5;padding:6px 0;margin:0 0 16px;white-space:nowrap;box-shadow:3px 3px 0 rgba(30,30,46,.25)}
.ticker-in{display:inline-block;animation:tick 34s linear infinite}
.ticker-in span{padding:0 10px}
@keyframes tick{to{transform:translateX(-50%)}}
@media(prefers-reduced-motion:reduce){.ticker-in,.sprite .bowl,.sprite .eyes,.sprite .tear,.blink,.jump .sprite,.dialog .cursor,.flycoin{animation:none!important}}
.layout{display:grid;gap:18px}
@media(min-width:900px){.layout{grid-template-columns:400px minmax(0,1fr);gap:24px;align-items:start}.col-l{position:sticky;top:16px}.layout.cols2{grid-template-columns:1fr 1fr}}
.col-l,.col-r{display:grid;gap:18px;min-width:0}
.narrow{max-width:560px;margin:0 auto}
.card{background:var(--panel);padding:18px;box-shadow:4px 4px 0 var(--ink)}
.card h2{font-size:18px;margin:0 0 12px;display:flex;align-items:center;gap:8px;flex-wrap:wrap;line-height:1.3}
.card h2 .sub{color:var(--muted);font-size:12px}
h1{font-size:24px;margin:0 0 8px;line-height:1.3}
/* 角色卡 */
.char-top{display:flex;gap:16px;align-items:flex-start}
.sprite-wrap{flex:none;width:96px;display:grid;place-items:end center}
.sprite{width:96px;height:auto;image-rendering:pixelated}
@media(min-width:900px){.char-top .sprite-wrap,.char-top .sprite{width:120px}}
.sprite .bowl{animation:shake 1s steps(1) infinite}
@keyframes shake{0%,100%{transform:translateY(0)}50%{transform:translateY(-1px)}}
.sprite .eyes{animation:blink 4s steps(1) infinite}
@keyframes blink{0%,90%{opacity:1}91%,96%{opacity:0}97%,100%{opacity:1}}
.sprite .tear{animation:tear 2.4s steps(1) infinite}
@keyframes tear{0%{transform:translateY(0)}33%{transform:translateY(1px)}66%{transform:translateY(2px)}}
.jump .sprite{animation:jump .9s steps(1) infinite}
@keyframes jump{0%,100%{transform:translateY(0)}50%{transform:translateY(-8px)}}
.char-info{flex:1;min-width:0}
.lvrow{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}
.lv{display:inline-block;background:var(--ink);color:var(--gold);font-size:12px;line-height:1.6;padding:2px 8px}
.lv b{color:#fff;font-weight:normal;margin-left:6px}
.lv.gold{background:var(--gold);color:var(--ink);border:2px solid var(--ink);padding:0 8px}
.pname{font-size:24px;margin:0 0 8px;line-height:1.25;word-break:break-word}
.barlabel{display:flex;justify-content:space-between;align-items:baseline;font-size:12px;color:var(--muted);margin-top:8px;line-height:1.4}
.barlabel b{color:var(--ink);font-weight:normal;margin-left:4px}
.barlabel span{font-size:12px;color:var(--muted);margin-left:8px;text-align:right}
.bar{position:relative;height:14px;border:3px solid var(--ink);background:#fff;margin:2px 0 0;box-shadow:2px 2px 0 var(--ink)}
.bar span{display:block;height:100%;background:var(--green);background-image:repeating-linear-gradient(90deg,transparent 0 6px,rgba(0,0,0,.14) 6px 8px);transition:width .6s steps(12)}
.bar.hp span{background-color:var(--red)}
.xpill{display:inline-flex;align-items:center;gap:6px;font-size:13px;font-weight:700;padding:3px 8px;border:3px solid var(--ink);background:#fff;color:var(--ink);text-decoration:none;box-shadow:2px 2px 0 var(--ink);margin-top:6px}
.dialog{position:relative;margin-top:16px;background:#fff;padding:10px 26px 10px 12px;font-size:16px;line-height:1.6;box-shadow:3px 3px 0 var(--ink);min-height:44px;word-break:break-word}
.dialog::before{content:"▶";position:absolute;left:-2px;top:-14px;background:var(--gold);padding:0 6px;font-size:10px;border:3px solid var(--ink)}
.dialog .cursor{position:absolute;right:8px;bottom:6px;font-size:10px;animation:blinkc .8s steps(1) infinite}
@keyframes blinkc{50%{opacity:0}}
.more{background:none;border:0;color:var(--blue);font-size:12px;cursor:pointer;padding:6px 0 0;font-family:inherit}
/* HUD */
.stats{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.stat{background:var(--panel);padding:10px 12px;min-width:0;box-shadow:3px 3px 0 var(--ink)}
.stat.main{grid-column:1/-1;background:var(--gold);display:flex;align-items:center;gap:12px}
.stat .k{font-size:12px;color:var(--muted);line-height:1.6}
.stat.main .k{color:var(--ink)}
.stat .v{font-size:24px;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.2}
.stat.main .v{font-size:36px;line-height:1.1}
.stat .v small{font-size:12px;color:var(--muted);margin-left:5px}
.stat.main .v small{color:var(--ink)}
.stat.main .bowlv{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 14px;white-space:nowrap;overflow:visible}
.stat.main .bowlv>span:first-child{min-width:0;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.stat.main .bowlcoins{font-size:22px;display:inline-flex;align-items:center;gap:5px}
.stat.main .bowlcoins .px-coin{width:18px;height:18px;flex:none}
.stat.main .bowlcoins small{margin-left:0}
.stat .px-bowl{width:48px;height:auto;flex:none}
.stat.main .sub2{display:flex;flex-direction:column;gap:8px;align-self:center;flex:none;font-family:var(--pf);color:var(--ink);text-align:left}
.stat.main .sub2 span{display:flex;align-items:baseline;justify-content:flex-start;gap:5px;white-space:nowrap;background:#fff;border:2px solid var(--ink);box-shadow:2px 2px 0 var(--ink);padding:3px 9px;min-width:96px}
.stat.main .sub2 i{font-style:normal;font-size:11px;opacity:.7}.stat.main .sub2 b{font-size:16px;font-weight:400}.stat.main .sub2 small{font-size:11px;opacity:.7}
@media(max-width:430px){.stat.main .v{font-size:30px}.stat.main .bowlcoins{font-size:18px}.stat.main{gap:8px}.stat .px-bowl{width:40px}}
/* 表单 */
label{display:block;font-size:13px;color:var(--ink);font-weight:600;margin:14px 0 6px}
form>label:first-child,.grid2>div>label:first-child{margin-top:0}
input,textarea,select{width:100%;padding:10px 12px;border:3px solid var(--ink);background:#fff;color:var(--ink);font-size:16px;font-family:inherit;line-height:1.4;border-radius:0;box-shadow:inset 3px 3px 0 var(--paper-2)}
input::placeholder,textarea::placeholder{color:#8f8a7c}
input:focus,textarea:focus,select:focus{outline:none;border-color:var(--blue);box-shadow:3px 3px 0 var(--blue)}
textarea{resize:vertical;min-height:70px}
.hint{font-size:13px;color:var(--muted);margin-top:6px;line-height:1.6}
.err{color:var(--red);font-size:13px;margin-top:10px}
.ok{color:var(--green);font-size:13px}
.insert{text-align:center;font-size:12px;letter-spacing:.1em;color:var(--red);margin:-4px 0 12px;line-height:1.6}
.blink{animation:blinkc 1s steps(1) infinite}
.amounts{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.amt-btn{display:flex;align-items:center;justify-content:center;gap:5px;padding:10px 4px;border:3px solid var(--ink);background:#fff;color:var(--ink);font-size:16px;white-space:nowrap;cursor:pointer;font-family:inherit;min-height:46px;box-shadow:3px 3px 0 var(--ink)}
.amt-btn .px-coin{width:16px;height:16px}
.amt-btn.on{background:var(--gold);transform:translate(2px,2px);box-shadow:1px 1px 0 var(--ink)}
.count{float:right;font-size:12px;color:var(--muted-2)}
.btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:50px;border:4px solid transparent;border-image:var(--frame) 2 / 4px stretch;image-rendering:pixelated;background-clip:padding-box;padding:10px 16px;font-size:18px;cursor:pointer;background-color:var(--gold);color:var(--ink);text-decoration:none;box-shadow:4px 4px 0 var(--ink)}
.btn:active{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--ink)}
.btn.sec{background-color:#fff}
.btn.ghost{background-color:transparent;box-shadow:none;color:var(--muted)}
.btn.danger{background-color:#fff;color:var(--red)}
.btn.sm{display:inline-flex;width:auto;min-height:40px;padding:6px 12px;font-size:14px;box-shadow:3px 3px 0 var(--ink)}
.btns{display:flex;gap:12px;flex-wrap:wrap;margin-top:14px}
.btns .btn{flex:1 1 auto;white-space:nowrap}
/* Tab */
.tabs{display:grid;grid-template-columns:repeat(3,1fr);border:3px solid var(--ink);margin-bottom:14px;background:#fff;box-shadow:3px 3px 0 var(--ink)}
.tab{border:0;border-right:3px solid var(--ink);background:transparent;color:var(--muted);font-size:16px;padding:10px 4px;cursor:pointer;white-space:nowrap}
.tab:last-child{border-right:0}
.tab.on{background:var(--gold);color:var(--ink)}
.panel{display:none}.panel.on{display:block}
/* 榜单 / 功德簿 */
.list{list-style:none;margin:0;padding:0}
.item{display:flex;align-items:center;gap:10px;padding:10px 0;border-top:3px dotted var(--line)}
.item:first-child{border-top:0;padding-top:2px}
.av{width:36px;height:36px;flex:none;display:grid;place-items:center;font-size:16px;background:hsl(var(--h) 75% 86%);color:hsl(var(--h) 55% 28%);border:3px solid var(--ink);box-shadow:2px 2px 0 var(--ink)}
.av.sq{background:#fff;font-size:20px;color:var(--ink)}
.rank{width:30px;flex:none;text-align:center;font-size:16px;color:var(--muted)}
.rank.m{font-size:20px}
.body{flex:1;min-width:0}
.name{display:flex;align-items:center;gap:6px;min-width:0;font-size:16px}
.name>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.name a{color:inherit;text-decoration:none}
.sub{font-size:13px;color:var(--muted);margin-top:1px}
.amtv .px-coin{width:14px;height:14px;vertical-align:-2px}
.amtv{white-space:nowrap;font-size:18px}
.feed .item{flex-wrap:wrap}
.bubble{flex-basis:100%;margin:8px 0 0 46px;background:#fff;border:3px solid var(--ink);padding:6px 10px;font-size:14px;line-height:1.6;word-break:break-word;position:relative;box-shadow:2px 2px 0 var(--ink)}
.bubble::before{content:"";position:absolute;left:-9px;top:8px;border:3px solid transparent;border-right-color:var(--ink);border-width:4px 6px 4px 0}
.bubble.blocked{color:var(--muted-2);letter-spacing:2px}
.time{font-size:12px;color:var(--muted);white-space:nowrap}
.me{font-size:10px;color:var(--ink);background:var(--gold);border:2px solid var(--ink);padding:0 5px;flex:none}
.empty{text-align:center;color:var(--muted);padding:24px 12px;font-size:14px}
.fold>summary{list-style:none;cursor:pointer;-webkit-tap-highlight-color:transparent}.fold>summary::-webkit-details-marker{display:none}
.fold>summary h2{margin:0;display:flex;align-items:center;gap:8px}.fold>summary .caret{margin-left:auto;font-size:18px;transition:transform .15s}.fold[open]>summary .caret{transform:rotate(90deg)}
.fold[open]>summary h2{margin-bottom:12px}
.pager{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:12px;font-family:var(--pf);font-size:14px}
.pager a,.pager span.cur,.pager span.dis{display:inline-flex;align-items:center;justify-content:center;min-width:36px;min-height:36px;padding:0 10px;border:3px solid var(--ink);background:#fff;color:var(--ink);text-decoration:none;box-shadow:2px 2px 0 var(--ink)}
.pager span.cur{background:var(--gold)}.pager span.dis{opacity:.4;box-shadow:none}
.empty .ico{font-size:32px;margin-bottom:6px}
.empty .sprite{width:72px}
.cta{text-align:center}
.cta p{color:var(--ink);margin:0 0 12px;font-size:14px}
.fab{position:fixed;left:16px;right:16px;bottom:calc(16px + env(safe-area-inset-bottom));z-index:20;display:none}
.fab.show{display:block}
@media(min-width:900px){.fab{display:none!important}.only-mobile{display:none!important}}
@media(max-width:899px){.only-desktop{display:none!important}}
.notice{background:var(--panel-2);border:3px solid var(--ink);padding:10px 12px;font-size:14px;line-height:1.6;box-shadow:3px 3px 0 var(--ink)}
.notice.ok{background:#dff7e8}
.notice.bad{background:#ffe1e1}
.code{background:#fff;border:2px solid var(--ink);padding:1px 6px;font-size:13px;word-break:break-all}
.copy{cursor:pointer;border:3px solid var(--ink);background:#fff;color:var(--ink);padding:6px 10px;min-height:36px;font-size:12px;flex:none;box-shadow:2px 2px 0 var(--ink)}
.kv{display:grid;grid-template-columns:auto 1fr;gap:10px 14px;font-size:14px;align-items:center}
.kv .k{color:var(--muted)}
.kv .v{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.qr{display:block;margin:8px auto;background:#fff;padding:8px;width:240px;height:240px;border:3px solid var(--ink);box-shadow:3px 3px 0 var(--ink);image-rendering:pixelated}
.steps{counter-reset:s;display:grid;gap:18px}
.step{position:relative;padding-left:44px}
.step::before{counter-increment:s;content:counter(s);position:absolute;left:0;top:-2px;width:30px;height:30px;background:var(--gold);color:var(--ink);border:3px solid var(--ink);font-size:14px;display:grid;place-items:center;box-shadow:2px 2px 0 var(--ink)}
.step h2{margin-bottom:8px}
.big{font-size:36px;line-height:1.2}
.big small{font-size:12px;color:var(--muted);margin-left:6px}
.spin{width:44px;height:44px;border:4px solid var(--line);border-top-color:var(--ink);margin:12px auto 16px;animation:spin 1s steps(8) infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.center{text-align:center}
.tag{display:inline-block;padding:0 6px;font-size:12px;line-height:1.6;border:2px solid var(--ink);color:var(--ink);white-space:nowrap;background:#fff}
.tag.paid{background:#dff7e8}.tag.claimed{background:var(--panel-2)}.tag.bad{background:#ffe1e1;color:var(--red);border-color:var(--red)}
.grid2{display:grid;gap:0 14px}@media(min-width:600px){.grid2{grid-template-columns:1fr 1fr}}
.emojis{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.emojis button{font-size:20px;background:#fff;border:3px solid var(--ink);padding:3px 7px;cursor:pointer;line-height:1.3;box-shadow:2px 2px 0 var(--ink)}
.anchors{display:flex;gap:10px;overflow-x:auto;padding:2px 2px 6px;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.anchors::-webkit-scrollbar{display:none}
.anchors a{flex:none;font-size:12px;line-height:1.8;color:var(--ink);text-decoration:none;border:3px solid var(--ink);padding:4px 10px;background:#fff;box-shadow:2px 2px 0 var(--ink)}
.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:10px;flex-basis:100%;padding-left:46px}
.actions form,.inline form{display:inline}
.section-title{font-size:12px;color:var(--muted);letter-spacing:.1em;margin:22px 0 8px;line-height:1.6}
.xavatar{width:40px;height:40px;border:3px solid var(--ink);vertical-align:middle;margin-right:6px;image-rendering:auto;object-fit:cover;background:#fff}
.av.img{object-fit:cover;background:#fff}
.xh{font-size:12px;color:var(--muted);font-family:var(--pf);flex:none}
.badge{font-size:14px;flex:none;letter-spacing:-2px}
.coinrow{display:flex;align-items:center;gap:10px;margin-top:14px;flex-wrap:wrap}
.js .col-l>.donate-card{display:none}
#modalForm .donate-card{box-shadow:none;border:0;padding:0;background:transparent}
#modalForm .donate-card h2{padding-right:44px}
.coinrow .coins b{color:var(--ink);font-size:16px}
.coinbtn .px-coin{width:16px;height:16px}
.coinbtn:disabled{opacity:.6;cursor:default}
.flycoin{position:fixed;z-index:50;font-size:28px;animation:fly .9s ease-out forwards;pointer-events:none}
@keyframes fly{0%{transform:translate(-50%,0) scale(1);opacity:1}60%{transform:translate(-50%,-90px) scale(1.3);opacity:1}100%{transform:translate(-50%,-140px) scale(.6);opacity:0}}
.hdr{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.hdr .body{flex:1 1 220px;min-width:0}
.hdr-actions{display:flex;gap:8px;margin-left:auto;flex:none}.hdr-actions form{display:contents}
@media(max-width:599px){.hdr-actions{flex-basis:100%;margin-left:0}.hdr-actions .btn{flex:1}}
.toast{position:fixed;left:50%;bottom:calc(84px + env(safe-area-inset-bottom));transform:translateX(-50%);background:var(--ink);color:var(--gold);padding:8px 14px;font-family:var(--pf);font-size:14px;z-index:60;box-shadow:3px 3px 0 rgba(0,0,0,.25)}
.tabs.four{grid-template-columns:repeat(4,1fr)}
.tabs.four .tab{font-size:14px;padding:10px 2px}
.tab.on::before{content:"▶";font-size:8px;margin-right:3px}
.toggle{display:inline-flex;border:3px solid var(--ink);margin-bottom:10px;background:#fff}
.toggle button{border:0;background:transparent;font-family:var(--pf);font-size:12px;padding:8px 12px;min-height:36px;cursor:pointer;color:var(--muted)}
.toggle button.on{background:var(--ink);color:var(--gold)}
.bubble.reply{background:var(--panel-2);margin-top:6px}
.profrow{display:flex;align-items:center;gap:12px;margin:12px 0}
.profrow .xavatar{width:56px;height:56px;margin:0}
.codebox{display:flex;align-items:center;gap:10px;margin:8px 0 12px}
.codebox .code.big{font-size:24px;padding:6px 12px;font-family:var(--pf)}
.sharebox{margin-top:14px}
.sharebox img{display:block;max-width:100%;border:3px solid var(--ink);box-shadow:4px 4px 0 var(--ink)}
.modal{position:fixed;inset:0;background:rgba(30,30,46,.6);z-index:100;display:flex;align-items:flex-end;justify-content:center}
.modal[hidden]{display:none}
.modal-box{position:relative;width:100%;max-height:92vh;overflow:auto;background:var(--panel);padding:18px 16px calc(18px + env(safe-area-inset-bottom));border-top:4px solid var(--ink);box-shadow:0 -6px 0 var(--ink)}
@media(min-width:600px){.modal{align-items:center;padding:20px}.modal-box{width:520px;max-height:90vh;border:4px solid var(--ink);box-shadow:6px 6px 0 var(--ink)}}
.modal-x{position:absolute;right:10px;top:8px;width:36px;height:36px;border:3px solid var(--ink);background:#fff;font-family:var(--pf);font-size:16px;cursor:pointer;box-shadow:2px 2px 0 var(--ink);z-index:1}
.spin-inline{display:inline-block;width:14px;height:14px;border:3px solid var(--line);border-top-color:var(--ink);border-radius:50%;animation:spin 1s steps(8) infinite;vertical-align:-2px;margin-right:4px}
.paypanel .qr{width:200px;height:200px}
.paypanel .big{font-size:32px}
footer{color:var(--muted);font-size:13px;text-align:center;margin-top:32px;line-height:1.9}
footer a{color:var(--muted)}
< / style >
< / head >
< body >
{{if .HasBGM}}< audio id = "bgm" src = "/static/bgm.m4a" loop preload = "none" playsinline > < / audio > {{end}}
< div class = "page" >
< nav class = "nav" >
< a class = "brand" href = "{{.HomePath}}" { { if ne . HomePath " / " } } title = "{{T " 回到刚才看的碗 " } } " { { end } } > {{template "coin"}}< span > {{T .SiteTitle}}< / span > < / a >
< span class = "sp" > < / span >
< label class = "langsel" title = "Language / 语言" > < span class = "langcur" aria-hidden = "true" > {{.LangShort}}< i > ▾< / i > < / span > < select onchange = "location.href='/lang?to='+encodeURIComponent(this.value)" aria-label = "Language" > {{range .Langs}}< option value = "{{.Code}}" { { if eq . Code $ . Lang } } selected { { end } } > {{.Name}}< / option > {{end}}< / select > < / label >
< button class = "sfx" id = "sfxBtn" type = "button" aria-label = "{{T " 声音开关 " } } " title = "{{T " 声音 " } } " > {{template "spk"}}< / button >
< a class = "link navrank" href = "/rank" aria-label = "{{T " 排行榜 " } } " title = "{{T " 排行榜 " } } " > {{template "trophy"}}< span > {{T "排行榜"}}< / span > < / a >
{{if .Me}}< a class = "link" href = "/manage" > {{T "我的后台"}}< / a > {{else}}< a class = "link navlogin" href = "/login" > {{template "keyicon"}}< span class = "hide-sm" > {{T "站长"}}< / span > < span class = "lbl" > {{T "登录"}}< / span > < / a > {{end}}
{{if .Me}}< a class = "pill px" href = "/{{.Me.Slug}}" > {{T "我的站"}}< / a > {{else if .SubsitesEnabled}}< a class = "pill px" href = "/new" > {{T "开通要饭站"}}< / a > {{end}}
< / nav >
< div class = "ticker" aria-hidden = "true" > < div class = "ticker-in" > < span > {{T "🙏 行行好,赏口饭吃"}}< / span > < span > {{T "🪙 一毛也是爱"}}< / span > < span > {{T "💸 投币就上榜"}}< / span > < span > {{T "📜 留一句话刻功德簿"}}< / span > < span > {{T "🏚 发条推就能开自己的要饭站"}}< / span > < span > {{T "👾 赛博丐帮,人人有碗"}}< / span > < span > {{T "🙏 行行好,赏口饭吃"}}< / span > < span > {{T "🪙 一毛也是爱"}}< / span > < span > {{T "💸 投币就上榜"}}< / span > < span > {{T "📜 留一句话刻功德簿"}}< / span > < span > {{T "🏚 发条推就能开自己的要饭站"}}< / span > < span > {{T "👾 赛博丐帮,人人有碗"}}< / span > < / div > < / div >
{{template "content" .}}
< footer >
{{T .SiteTitle}} {{T "· 赛博丐帮,行行好"}}< br >
{{if or .AuthorX .AuthorGitHub}}{{T "作者"}}{{if .AuthorX}} < a href = "{{.AuthorX}}" target = "_blank" rel = "noopener" > 𝕏 @{{lastSeg .AuthorX}}< / a > {{end}}{{if .AuthorGitHub}} · < a href = "{{.AuthorGitHub}}" target = "_blank" rel = "noopener" > GitHub {{lastSeg .AuthorGitHub}}< / a > {{end}}< br > {{end}}
{{T "收款由"}} < a href = "{{.RepoURL}}" target = "_blank" rel = "noopener" > BinancePayTool< / a > {{T "驱动 · 字体"}} < a href = "https://github.com/TakWolf/fusion-pixel-font" target = "_blank" rel = "noopener" > {{T "缝合怪像素字体"}}< / a > {{if .SourceURL}}< br >
< a href = "{{.SourceURL}}" target = "_blank" rel = "noopener" > {{T "本站开源,欢迎 Star ⭐"}}< / a > {{end}}
< / footer >
< / div >
< script >
// 声音:背景音乐(/static/bgm.m4a 循环)+ 8-bit 音效(Web Audio 现场合成,不加载文件)。一个开关管全部,记 localStorage(sfx),默认开。
// 浏览器不让页面一打开就出声:先尝试自动播放,被拦就等用户第一次触屏/点击/按键再起。音效首次出声也必须在用户手势里创建 AudioContext( iOS 限制)。
// 背景音乐也解码进同一个 AudioContext 里循环播放(AudioBufferSourceNode,无缝循环):和 < audio > 元素分开走的话,iOS 上音效一起音频会话就会把音乐打断重来。
// 解码不了(极少数浏览器没有 AAC 解码器)才退回 < audio > 元素。
var BGM_VOL=0.45;
window.sfx=(function(){var ctx,on=true,C=window.AudioContext||window.webkitAudioContext,buf=null,src=null,el=null,bytes=null,elMode=false,loading=false,unlocked=false;try{on=localStorage.getItem('sfx')!=='0'}catch(e){}
function ac(){if(!C)return null;if(!ctx){try{ctx=new C()}catch(e){return null}}if(ctx.state==='suspended'){try{ctx.resume()}catch(e){}}return ctx}
// 在用户手势里解锁:resume + 放一个空 buffer(老 iOS 的解锁套路)
function unlock(){var c=ac();if(!c)return;try{var b=c.createBuffer(1,1,22050),s=c.createBufferSource();s.buffer=b;s.connect(c.destination);s.start(0);unlocked=true}catch(e){}}
var paint=function(){};
// 下载一次:字节既喂给 < audio > (手势里能立刻响)也喂给 decodeAudioData(解码完切到 Web Audio 无缝循环)
function loadBgm(){if(bytes||loading)return;el=el||document.getElementById('bgm');if(!el)return;loading=true;
fetch(el.getAttribute('src')).then(function(r){if(!r.ok)throw 0;return r.arrayBuffer()}).then(function(ab){bytes=ab;
try{el.src=URL.createObjectURL(new Blob([ab],{type:'audio/mp4'}))}catch(e){}
var c=C&&ac(); if(!c){elMode=true;loading=false;startBgm();return}
return new Promise(function(res,rej){var p=c.decodeAudioData(ab.slice(0),res,rej);if(p&&p.then)p.then(res,rej)}).then(function(b){buf=b; loading=false;startBgm()})})
.catch(function(){loading=false;elMode=true;startBgm()})}
function elPlay(){if(!el||!el.paused)return;el.volume=BGM_VOL;var p=el.play();if(p& & p.then)p.then(paint,function(){})}
function startBgm(){if(!on)return;
if(elMode||!buf){ // 还没解码好(或解码不了):先用 < audio > 顶上,只有在手势里才播得出来
if(bytes)elPlay();return}
var c=ac();if(!c)return;
if(c.state!=='running'){var r=c.resume&&c.resume(); if(r&&r.then)r.then(function(){if(c.state==='running'&&!src)startBgm(); paint()},function(){});return}
if(src)return;
var off=0;if(el&&!el.paused){off=el.currentTime%buf.duration; el.pause()} // 从 < audio > 接力,不从头来
var s=c.createBufferSource(),g=c.createGain();s.buffer=buf;s.loop=true;g.gain.value=BGM_VOL;s.connect(g);g.connect(c.destination);s.start(0,off);src=s;paint()}
function stopBgm(){if(src){try{src.stop()}catch(e){}src=null}if(el)el.pause();paint()}
function playingNow(){if(src)return ctx&&ctx.state==='running'; return !!(el& & !el.paused)}
function armBgm(){['pointerdown','touchend','click','keydown'].forEach(function(t){document.addEventListener(t,function(){if(!on)return;unlock();loadBgm();startBgm()},{passive:true})})}
function tone(f,t0,dur,type,vol){var c=ac();if(!c)return;var o=c.createOscillator(),g=c.createGain(),t=c.currentTime+t0;o.type=type||'square';o.frequency.setValueAtTime(f,t);
g.gain.setValueAtTime(0.0001,t);g.gain.exponentialRampToValueAtTime(vol||0.22,t+0.012);g.gain.exponentialRampToValueAtTime(0.0001,t+dur);o.connect(g);g.connect(c.destination);o.start(t);o.stop(t+dur+0.03)}
function play(seq){if(!on)return;try{seq.forEach(function(n){tone(n[0],n[1],n[2],n[3],n[4])})}catch(e){}}
var S={
warm:function(){if(on)ac()},
click:function(){play([[740,0,0.045,'square',0.12]])},
coin:function(){play([[988,0,0.07,'square',0.25],[1319,0.07,0.32,'square',0.25]])},
ok:function(){play([[523,0,0.09],[659,0.09,0.09],[784,0.18,0.09],[1047,0.27,0.38,'square',0.26]])},
fail:function(){play([[196,0,0.1,'sawtooth',0.16],[147,0.1,0.26,'sawtooth',0.16]])},
levelup:function(){play([[659,0,0.08],[784,0.08,0.08],[988,0.16,0.08],[1319,0.24,0.08],[1568,0.32,0.4,'square',0.26]])},
enabled:function(){return on},
playing:function(){return src?'webaudio':(el& & !el.paused?'element':'')},
toggle:function(){on=!on;try{localStorage.setItem('sfx',on?'1':'0')}catch(e){}if(on){S.coin();loadBgm();startBgm()}else{stopBgm()}paint();return on}};
document.addEventListener('DOMContentLoaded',function(){if(on)loadBgm();armBgm();
var b=document.getElementById('sfxBtn');if(!b)return;
// 三态:🔊 在放 / 🔈 开着但还没放(浏览器拦了自动播放,点一下就放)/ 🔇 静音
var hasBgm=!!document.getElementById('bgm'); // 没放音乐文件时只有音效,喇叭只有开/关两态
paint=function(){var p=on&&(!hasBgm||playingNow()); b.classList.toggle('off',!on);b.classList.toggle('idle',on&&!p); b.title=!on?{{T "声音:关"}}:(p?{{T "声音:开(点击静音)"}}:{{T "点一下开始播放"}})};paint();
b.addEventListener('click',function(){if(on&&!playingNow()){loadBgm(); startBgm();return}S.toggle()})});
document.addEventListener('click',function(ev){var b=ev.target.closest('.btn,.tab,.amt-btn,.copy,.pill,.toggle button,.link');if(!b||b.disabled)return;ac();if(b.id!=='coinbtn')S.click()},true);
return S})();
(function(){
// 复制按钮(全站委托)
document.addEventListener('click',function(ev){var b=ev.target.closest('.copy');if(!b||b.id==='nextText')return;var src=b.dataset.copyFrom;var t=src?document.getElementById(src).value:b.dataset.copy;var o=b.textContent;
function done(){b.textContent={{T "已复制"}};setTimeout(function(){b.textContent=o},1500)}
(navigator.clipboard?navigator.clipboard.writeText(t):Promise.reject()).then(done,function(){var i=document.createElement('input');i.value=t;document.body.appendChild(i);i.select();try{document.execCommand('copy')}catch(e){}i.remove();done()})});
// 付款面板:轮询到账、回填/自报、成功态
window.initPayPanel=function(pp,onDone){
var code=pp.dataset.code,site=pp.dataset.site,amount=pp.dataset.amount,status=pp.dataset.status,stop=false,fails=0;
function success(amt){stop=true;if(window.sfx)sfx.ok();var sp=document.querySelector('.sprite');pp.innerHTML='< div class = "center" > < div class = "sprite-wrap jump" style = "margin:0 auto 8px" > '+(sp?sp.outerHTML:'🥣')+'< / div > < div class = "insert" > ★ THANK YOU ★< / div > < h2 class = "center" style = "justify-content:center" > 🙏 '+{{T "功德 +"}}+(amt||amount)+'< / h2 > < p class = "hint" > '+{{T "你的名号和留言已刻上功德簿"}}+'< / p > < div class = "btns" > < a class = "btn" href = "'+site+'#feed" onclick = "if(location.pathname===this.pathname){location.hash=\'feed\';location.reload();return false}" > '+{{T "看看功德簿"}}+'< / a > < a class = "btn sec" href = "/d/'+code+'" > '+{{T "分享卡片"}}+'< / a > < / div > < / div > ';if(onDone)onDone('paid')}
function setStatus(html){var st=pp.querySelector('#ppStatus');if(st)st.innerHTML=html}
function apply(j){if(!j||!j.status)return;if(j.status==='paid'){success(j.amount)}else if(j.status==='claimed'&&status!=='claimed'){status='claimed'; setStatus('< div class = "notice" style = "margin-top:12px" > < span class = "spin-inline" > < / span > '+{{T "已提交,等站长确认后上榜。本页会自动更新。"}}+'< / div > ')}else if(['expired','failed','rejected','closed'].indexOf(j.status)>=0){stop=true;setStatus('< div class = "notice bad" style = "margin-top:12px" > '+{{T "这笔施舍已"}}+({expired:{{T "过期"}},failed:{{T "下单失败"}},rejected:{{T "被站长拒绝"}},closed:{{T "关闭"}}})[j.status]+{{T ",请回到页面重新投币。"}}+'< / div > ')}}
function tick(){if(stop)return;fetch('/d/'+code+'/status',{cache:'no-store'}).then(function(r){return r.json()}).then(function(j){fails=0;apply(j)}).catch(function(){if(++fails>=20)stop=true})}
var timer=setInterval(function(){if(stop){clearInterval(timer);return}tick()},3000);
pp.addEventListener('submit',function(ev){var f=ev.target.closest('.claimf');if(!f)return;ev.preventDefault();var fd=new FormData(f);fd.append('ajax','1');var btn=f.querySelector('button');btn.disabled=true;var err=f.querySelector('.claim-err');err.textContent='';
fetch(f.getAttribute('action'),{method:'POST',body:fd}).then(function(r){return r.json()}).then(function(j){btn.disabled=false;if(j.status==='paid'){success()}else if(j.ok&&j.status==='claimed'){apply({status:'claimed'})}else{if(window.sfx)sfx.fail(); err.textContent=j.msg||{{T "没成功,再试试"}}}}).catch(function(){btn.disabled=false;if(window.sfx)sfx.fail();err.textContent={{T "网络开小差了"}}})});
return function(){stop=true;clearInterval(timer)}
};
var pp=document.getElementById('paypanel');if(pp)window.initPayPanel(pp);
})();
< / script >
{{block "scripts" .}}{{end}}
< / body >
< / html > {{end}}
{{define "pager"}}{{if gt .Pages 1}}< nav class = "pager" aria-label = "{{T " 分页 " } } " >
{{if .HasPrev}}< a href = "{{.URL .Prev}}" > {{T "‹ 上一页"}}< / a > {{else}}< span class = "dis" > {{T "‹ 上一页"}}< / span > {{end}}
{{range .Nums}}{{if eq . $.Page}}< span class = "cur" > {{.}}< / span > {{else}}< a href = "{{$.URL .}}" > {{.}}< / a > {{end}}{{end}}
{{if .HasNext}}< a href = "{{.URL .Next}}" > {{T "下一页 › "}}< / a > {{else}}< span class = "dis" > {{T "下一页 › "}}< / span > {{end}}
< span class = "hint" style = "margin-left:auto" > {{.Page}}/{{.Pages}} {{T "页"}}< / span >
< / nav > {{end}}{{end}}