// ============================================================
// 禅心问答 · 卡片展开/收起 (2026-04-24)
// ============================================================
window.toggleDialogCard = function(cardEl) {
var isActive = cardEl.classList.contains('active');
// 收起所有
var allCards = document.querySelectorAll('.zen-dialog-card');
for (var i = 0; i < allCards.length; i++) {
allCards[i].classList.remove('active');
}
// 如果不是当前激活的,则展开
if (!isActive) {
cardEl.classList.add('active');
}
};
// ============================================================
// 禅心问答 · 随机叩问 (2026-04-24 增强)
// ============================================================
window.zyRandomQuestion = function() {
var cards = document.querySelectorAll('.zen-dialog-card');
if (!cards || cards.length === 0) return;
// 收起所有卡片
for (var i = 0; i < cards.length; i++) {
cards[i].classList.remove('active');
}
// 随机选一张
var randomIdx = Math.floor(Math.random() * cards.length);
cards[randomIdx].classList.add('active');
// 滚动到这张卡片
cards[randomIdx].scrollIntoView({behavior: 'smooth', block: 'center'});
// 高亮动画
cards[randomIdx].style.transition = 'box-shadow 0.3s ease';
cards[randomIdx].style.boxShadow = '0 0 0 3px rgba(184,134,11,0.3)';
setTimeout(function() {
cards[randomIdx].style.boxShadow = '';
}, 1500);
};
// ============================================================
// 禅茶一歇 · Zen Tea Break (2026-04-25 战略新增)
// ============================================================
// --- 数据源 ---
var ztbVerses = [
{text:'菩提本无树,明镜亦非台。
本来无一物,何处惹尘埃。', src:'六祖慧能'},
{text:'春有百花秋有月,夏有凉风冬有雪。
若无闲事挂心头,便是人间好时节。', src:'无门慧开'},
{text:'千山万水不曾遮,处处相逢岁月赊。
野老门前无别事,朝朝惟见水生花。', src:'虚云老和尚'},
{text:'空手把锄头,步行骑水牛。
人从桥上过,桥流水不流。', src:'傅大士'},
{text:'终日寻春不见春,芒鞋踏破岭头云。
归来偶把梅花嗅,春在枝头已十分。', src:'无尽藏比丘尼'},
{text:'庐山烟雨浙江潮,未到千般恨不消。
到得还来别无事,庐山烟雨浙江潮。', src:'苏东坡'},
{text:'手把青秧插满田,低头便见水中天。
心地清净方为道,退步原来是向前。', src:'布袋和尚'},
{text:'一树春风有两般,南枝向暖北枝寒。
现前一段西来意,一片西飞一片东。', src:'苏东坡'},
{text:'溪声尽是广长舌,山色无非清净身。
夜来八万四千偈,他日如何举似人。', src:'苏东坡'}
];
var ztbPerspectives = [
{before:'「堵车好烦,浪费时间」', after:'「此刻无人打扰,正好观息」'},
{before:'「工作压力好大,撑不住了」', after:'「压力是心在告诉我:停下来看看」'},
{before:'「为什么别人都比我好」', after:'「别人的好,与我何干?我走我的路」'},
{before:'「失眠了,明天一定很糟糕」', after:'「睡不着,那就安心躺着。夜很静」'},
{before:'「做了好多事却没有结果」', after:'「种子发芽之前,土是看不见动静的」'},
{before:'「他/她为什么这样对我」', after:'「别人的行为是别人的因果,我的反应是我的修行」'},
{before:'「我太孤独了,没人理解我」', after:'「独处是与自己相遇的时刻。你一直都在」'},
{before:'「时间不够用,什么都没做」', after:'「你正在呼吸,这就够了。其他都是加法」'},
{before:'「老了一岁,又虚度了」', after:'「又多活了一年。活着本身,就是最大的成就」'},
{before:'「怕出错,不敢开始」', after:'「错了又怎样?禅说:迷时师度,悟时自度」'},
{before:'「生活一成不变,无聊透顶」', after:'「不变的是风景,变化的是你看风景的心」'},
{before:'「这个世界太乱了」', after:'「外界的乱是修行的磨刀石。心静了,世界就静了」'}
];
var ztbVerseIndex = 0;
var ztbPerspIndex = 0;
// --- 翻牌 ---
window.ztbFlipCard = function(cardEl) {
cardEl.classList.toggle('flipped');
};
// --- 换一偈 ---
window.ztbRefreshVerse = function() {
ztbVerseIndex = (ztbVerseIndex + 1) % ztbVerses.length;
var v = ztbVerses[ztbVerseIndex];
document.getElementById('ztbVerse').innerHTML = v.text;
document.getElementById('ztbVerseSource').textContent = '— ' + v.src;
};
// --- 换一念 ---
window.ztbRefreshPerspective = function() {
ztbPerspIndex = (ztbPerspIndex + 1) % ztbPerspectives.length;
var p = ztbPerspectives[ztbPerspIndex];
document.getElementById('ztbBefore').textContent = p.before;
document.getElementById('ztbAfter').textContent = p.after;
};
// --- 十秒正念 ---
var ztbMicroTimer = null;
window.ztbStartMicroZen = function() {
var card = document.getElementById('ztbCardC');
var front = document.getElementById('ztbFrontC');
var back = document.getElementById('ztbBackC');
var timerEl = document.getElementById('ztbMicroTimer');
var textEl = document.getElementById('ztbMicroText');
// 如果正在运行,停止
if (ztbMicroTimer) {
clearInterval(ztbMicroTimer);
ztbMicroTimer = null;
front.style.display = '';
back.style.display = 'none';
timerEl.textContent = '10';
textEl.textContent = '呼吸...';
return;
}
// 显示背面
front.style.display = 'none';
back.style.display = 'flex';
var count = 10;
timerEl.textContent = count;
var phases = ['吸气...', '屏住...', '呼气...', '静默...'];
var phaseIdx = 0;
textEl.textContent = phases[0];
ztbMicroTimer = setInterval(function() {
count--;
timerEl.textContent = count;
// 每2-3秒切换呼吸阶段
if (count === 7 || count === 5 || count === 2) {
phaseIdx = (phaseIdx + 1) % phases.length;
textEl.textContent = phases[phaseIdx];
}
if (count <= 0) {
clearInterval(ztbMicroTimer);
ztbMicroTimer = null;
textEl.textContent = '善。';
timerEl.textContent = '✓';
// 3秒后恢复
setTimeout(function() {
front.style.display = '';
back.style.display = 'none';
timerEl.textContent = '10';
textEl.textContent = '呼吸...';
}, 3000);
}
}, 1000);
};
// 随机初始化(基于日期)
(function initZtb() {
var today = new Date();
var dayIdx = today.getFullYear() * 366 + today.getMonth() * 31 + today.getDate();
ztbVerseIndex = dayIdx % ztbVerses.length;
ztbPerspIndex = dayIdx % ztbPerspectives.length;
var v = ztbVerses[ztbVerseIndex];
document.getElementById('ztbVerse').innerHTML = v.text;
document.getElementById('ztbVerseSource').textContent = '— ' + v.src;
var p = ztbPerspectives[ztbPerspIndex];
document.getElementById('ztbBefore').textContent = p.before;
document.getElementById('ztbAfter').textContent = p.after;
})();
// ═══════════════════════════════════════════════════
// 止语·静坐 · Silent Sitting (2026-04-27 战略新增)
// 沉浸式禅修计时 — Web Audio 钟声 + 呼吸圆 + 记录追踪
// ═══════════════════════════════════════════════════
var zsDuration = 5; // minutes
var zsRunning = false;
var zsTimer = null;
var zsTotalSec = 0;
var zsRemainSec = 0;
var zsAudioCtx = null;
function zsSelectDur(min, btn) {
if (zsRunning) return;
zsDuration = min;
document.querySelectorAll('.zs-dur-btn').forEach(function(b) { b.classList.remove('zs-dur-active'); });
btn.classList.add('zs-dur-active');
document.getElementById('zsTimer').textContent = zsFmtTime(min * 60);
// reset progress ring
document.getElementById('zsProgress').style.strokeDashoffset = '565.48';
}
function zsFmtTime(sec) {
var m = Math.floor(sec / 60);
var s = sec % 60;
return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;
}
function zsPlayBell(freq) {
// Web Audio API: singing bowl sound at healing frequency
if (!zsAudioCtx) zsAudioCtx = new (window.AudioContext || window.webkitAudioContext)();
var ctx = zsAudioCtx;
var now = ctx.currentTime;
// fundamental
var osc1 = ctx.createOscillator();
osc1.type = 'sine';
osc1.frequency.setValueAtTime(freq || 528, now);
var gain1 = ctx.createGain();
gain1.gain.setValueAtTime(0.3, now);
gain1.gain.exponentialRampToValueAtTime(0.001, now + 4);
osc1.connect(gain1);
gain1.connect(ctx.destination);
osc1.start(now);
osc1.stop(now + 4);
// overtone
var osc2 = ctx.createOscillator();
osc2.type = 'sine';
osc2.frequency.setValueAtTime((freq || 528) * 2.01, now);
var gain2 = ctx.createGain();
gain2.gain.setValueAtTime(0.08, now);
gain2.gain.exponentialRampToValueAtTime(0.001, now + 2.5);
osc2.connect(gain2);
gain2.connect(ctx.destination);
osc2.start(now);
osc2.stop(now + 2.5);
// third harmonic
var osc3 = ctx.createOscillator();
osc3.type = 'sine';
osc3.frequency.setValueAtTime((freq || 528) * 3.01, now);
var gain3 = ctx.createGain();
gain3.gain.setValueAtTime(0.04, now);
gain3.gain.exponentialRampToValueAtTime(0.001, now + 1.5);
osc3.connect(gain3);
gain3.connect(ctx.destination);
osc3.start(now);
osc3.stop(now + 1.5);
}
function zsToggle() {
if (zsRunning) {
zsStop(false);
} else {
zsStart();
}
}
function zsStart() {
zsRunning = true;
zsTotalSec = zsDuration * 60;
zsRemainSec = zsTotalSec;
var section = document.getElementById('silentSit');
section.classList.add('zs-active');
var btn = document.getElementById('zsStartBtn');
btn.textContent = '结 束 静 坐';
btn.classList.add('zs-running');
document.getElementById('zsComplete').classList.remove('show');
// start bell
zsPlayBell(528);
// breath phase state
zsBreathPhase();
// countdown
zsTimer = setInterval(function() {
zsRemainSec--;
document.getElementById('zsTimer').textContent = zsFmtTime(zsRemainSec);
// update progress ring
var pct = (zsTotalSec - zsRemainSec) / zsTotalSec;
document.getElementById('zsProgress').style.strokeDashoffset = 565.48 * (1 - pct);
// breath cycle every 16 seconds (4-4-4-4)
if (zsRemainSec % 16 === 0 && zsRemainSec > 0) {
zsBreathPhase();
}
if (zsRemainSec <= 0) {
zsStop(true);
}
}, 1000);
}
var zsBreathIdx = 0;
var zsBreathLabels = ['吸 气', '屏 息', '呼 气', '静 默'];
function zsBreathPhase() {
var label = zsBreathLabels[zsBreathIdx % 4];
document.getElementById('zsPhase').textContent = label;
var glow = document.getElementById('zsGlow');
glow.className = 'zs-breath-glow';
if (zsBreathIdx % 4 === 0) glow.classList.add('zs-inhale');
else if (zsBreathIdx % 4 === 2) glow.classList.add('zs-exhale');
zsBreathIdx++;
}
function zsStop(completed) {
zsRunning = false;
clearInterval(zsTimer);
zsTimer = null;
zsBreathIdx = 0;
var section = document.getElementById('silentSit');
section.classList.remove('zs-active');
var btn = document.getElementById('zsStartBtn');
btn.textContent = '开 始 静 坐';
btn.classList.remove('zs-running');
if (completed) {
// end bell
zsPlayBell(396);
setTimeout(function() { zsPlayBell(528); }, 800);
// show completion
document.getElementById('zsTimer').textContent = '善。';
document.getElementById('zsPhase').textContent = '静坐圆满';
document.getElementById('zsComplete').classList.add('show');
// save streak
zsSaveStreak();
} else {
document.getElementById('zsTimer').textContent = zsFmtTime(zsDuration * 60);
document.getElementById('zsPhase').textContent = '选择时间,开始静坐';
document.getElementById('zsProgress').style.strokeDashoffset = '565.48';
}
}
function zsSaveStreak() {
var key = 'bofei_sit_log';
var log = {};
try { log = JSON.parse(localStorage.getItem(key) || '{}'); } catch(e) {}
var today = new Date().toISOString().slice(0,10);
if (!log[today]) log[today] = 0;
log[today] += zsDuration;
localStorage.setItem(key, JSON.stringify(log));
zsRenderStreak();
}
function zsRenderStreak() {
var key = 'bofei_sit_log';
var log = {};
try { log = JSON.parse(localStorage.getItem(key) || '{}'); } catch(e) {}
var total = Object.keys(log).length;
var today = new Date().toISOString().slice(0,10);
document.getElementById('zsStreakNum').textContent = total;
if (log[today]) {
document.getElementById('zsStreakHint').textContent = '今日已静坐 ' + log[today] + ' 分钟。善哉。';
} else {
document.getElementById('zsStreakHint').textContent = '每一次静坐,都是与自己的约定';
}
}
// Init streak on load
zsRenderStreak();
// ═══════════════════════════════════════════════════
// 禅径导航 · Zen Path Navigation (2026-04-27 补全)
// ═══════════════════════════════════════════════════
window.zenPathGo = function(target, node) {
var el = document.querySelector(target);
if (!el) return;
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
// highlight clicked node
document.querySelectorAll('.zp-node').forEach(function(n) { n.classList.remove('zp-active'); });
if (node) node.classList.add('zp-active');
};
(function initZenPathObserver() {
var targets = [
{ sel: '#hero', step: 1 },
{ sel: '#zenDailyGongfu', step: 2 },
{ sel: '#zenLineage', step: 3 },
{ sel: '#heartMirror', step: 4 },
{ sel: '#silentSit', step: 5 },
{ sel: '#zenReading', step: 6 },
{ sel: '#zenDeepExplore', step: 7 }
];
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
var t = targets.find(function(t) { return t.sel === '#' + entry.target.id; });
if (!t) return;
var node = document.querySelector('.zp-node[data-step="' + t.step + '"]');
if (!node) return;
if (entry.isIntersecting) {
document.querySelectorAll('.zp-node').forEach(function(n) { n.classList.remove('zp-active'); });
node.classList.add('zp-active');
}
});
}, { threshold: 0.3, rootMargin: '-10% 0px -60% 0px' });
targets.forEach(function(t) {
var el = document.querySelector(t.sel);
if (el) observer.observe(el);
});
})();