<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Contact — Realm</title>
<meta name="description" content="领地联络处 — Contact the Realm">
<meta name="theme-color" content="#1a1a2e">
<link rel="stylesheet" href="../css/realm.css">
</head>
<body>
<a class="skip-link" href="#main-content">跳至正文</a>
<main class="realm-scene" style="--scene-bg: oklch(0.25 0.04 278)">
<h1 class="visually-hidden">联络处</h1>
<div class="realm-scene__content">
<div id="main-content" class="phone-scene">
<div class="phone-booth">
<!-- 纸条堆叠 -->
<div class="phone-note-stack">
<!-- 上层纸条:号码表 -->
<aside class="phone-note">
<p class="phone-note__title">以防我忘记……</p>
<dl class="phone-note__list">
<dt>114</dt><dd>电子邮箱</dd>
<dt>520</dt><dd>长毛象</dd>
<dt>404</dt><dd>GitHub</dd>
<dt>818</dt><dd>Pixelfed(新)</dd>
<dt>886</dt><dd>Pixelfed(旧)</dd>
<dt>010</dt><dd>Matrix</dd>
</dl>
</aside>
<!-- 下层纸条:使用说明(checkbox hack) -->
<input type="checkbox" id="phone-hint-toggle" class="phone-hint-toggle">
<div class="phone-hint">
<div class="phone-hint__body">
<p>这种电话是需要将听筒拿起来才能拨号的。</p>
<ol>
<li>拿起左侧听筒(点击听筒按钮)</li>
<li>听到提示音后,按键盘上的数字</li>
<li>拨满三位后等待接通</li>
<li>打完电话记得挂回听筒</li>
</ol>
</div>
<label for="phone-hint-toggle" class="phone-hint__tab" aria-label="展开使用说明">?</label>
</div>
</div>
<!-- 电话主体 -->
<div class="phone" data-state="idle">
<!-- 雨棚 -->
<div class="phone-hood"></div>
<!-- 机身 -->
<div class="phone-body">
<!-- 听筒(点击拿起/挂断)-->
<button class="phone-handset" type="button" aria-label="拿起听筒"></button>
<!-- 显示屏 -->
<div class="phone-display">
<span class="phone-display__digits"></span>
<span class="phone-display__status" aria-live="polite"></span>
<!-- 拨号结果(显示在屏幕内) -->
<div class="phone-result" hidden aria-live="polite">
<a class="phone-result__link" href=""></a>
</div>
</div>
<!-- 键盘 3×4 -->
<div class="phone-keypad">
<button class="phone-key" type="button" data-digit="1">1</button>
<button class="phone-key" type="button" data-digit="2">2</button>
<button class="phone-key" type="button" data-digit="3">3</button>
<button class="phone-key" type="button" data-digit="4">4</button>
<button class="phone-key" type="button" data-digit="5">5</button>
<button class="phone-key" type="button" data-digit="6">6</button>
<button class="phone-key" type="button" data-digit="7">7</button>
<button class="phone-key" type="button" data-digit="8">8</button>
<button class="phone-key" type="button" data-digit="9">9</button>
<button class="phone-key" type="button" data-digit="*">*</button>
<button class="phone-key" type="button" data-digit="0">0</button>
<button class="phone-key" type="button" data-digit="#">#</button>
</div>
<!-- 投币口 -->
<div class="phone-coin"></div>
</div>
<!-- 搁物台 -->
<div class="phone-shelf"></div>
</div>
</div>
</div>
</div>
<!-- 无 JS 降级:直接显示联系方式 -->
<noscript>
<div class="realm-content">
<p>电子邮箱:<a href="mailto:boo@cytrogen.icu">boo@cytrogen.icu</a></p>
<p>长毛象:<a href="https://m.otter.homes/@Cytrogen">@Cytrogen@m.otter.homes</a></p>
<p>GitHub:<a href="https://github.com/cytrogen">github.com/cytrogen</a></p>
</div>
</noscript>
<nav class="realm-scene__nav realm-nav">
<a href="castle.html">← 返回领地</a>
</nav>
</main>
<script>
(() => {
const phone = document.querySelector('.phone');
const digits = phone.querySelector('.phone-display__digits');
const status = phone.querySelector('.phone-display__status');
const result = phone.querySelector('.phone-result');
const link = phone.querySelector('.phone-result__link');
const codes = {
'114': { label: 'boo@cytrogen.icu', href: 'mailto:boo@cytrogen.icu' },
'520': { label: '@Cytrogen@m.otter.homes', href: 'https://m.otter.homes/@Cytrogen' },
'404': { label: 'github.com/cytrogen', href: 'https://github.com/cytrogen' },
'818': { label: '@Cytrogen@pixelfed.feddit.social', href: 'https://pixelfed.feddit.social/Cytrogen' },
'886': { label: '@Cytrogen@pxlmo.com', href: 'https://pxlmo.com/Cytrogen' },
'010': { label: '@cytrogen:tchncs.de', href: 'https://matrix.to/#/@cytrogen:tchncs.de' },
};
let timer = null;
function setState(s) {
phone.dataset.state = s;
phone.querySelector('.phone-handset').ariaLabel =
s === 'idle' ? '拿起听筒' : '挂断听筒';
const keysDisabled = s !== 'ready';
phone.querySelectorAll('.phone-key').forEach(k => k.disabled = keysDisabled);
}
function reset() {
clearTimeout(timer);
digits.textContent = '';
status.textContent = '';
status.hidden = false;
result.hidden = true;
link.href = '';
link.textContent = '';
setState('idle');
}
phone.querySelector('.phone-handset').addEventListener('click', () => {
if (phone.dataset.state === 'idle') {
setState('ready');
status.textContent = '请拨号…';
} else {
reset();
}
});
phone.querySelector('.phone-keypad').addEventListener('click', (e) => {
const key = e.target.closest('[data-digit]');
if (!key || phone.dataset.state !== 'ready') return;
digits.textContent += key.dataset.digit;
if (digits.textContent.length < 3) return;
const num = digits.textContent;
const entry = codes[num];
if (entry) {
setState('connecting');
status.textContent = '拨号中…';
timer = setTimeout(() => {
setState('connected');
status.hidden = true;
link.href = entry.href;
link.textContent = entry.label;
result.hidden = false;
}, 1500);
} else {
setState('error');
status.textContent = '空号';
timer = setTimeout(() => {
digits.textContent = '';
status.textContent = '请拨号…';
setState('ready');
}, 2000);
}
});
})();
</script>
</body>
</html>