Audio cue
Een fluisterend signaal. Geen geluid voor de show.
// Mechanisme: cta-audio-cue-minimal
// Auto-loop ripple-rings vanuit het centrum van een play-button.
// Reduced-motion respecterend; geen stijlkeuzes, alleen mechaniek.
const root = document.querySelector('.audio-cue');
if (root && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
const stage = root.querySelector('.cue-stage');
let n = 0;
const spawn = () => {
const ring = document.createElement('span');
ring.className = 'cue-ring';
ring.style.setProperty('--i', String(n++));
stage.appendChild(ring);
setTimeout(() => ring.remove(), 2400);
};
spawn();
setInterval(spawn, 3000);
// Pulserende dots
const dots = root.querySelectorAll('.cue-dot');
let k = 0;
setInterval(() => {
dots.forEach((d, i) => d.classList.toggle('on', i === k % dots.length));
k++;
}, 280);
} <!-- Skeleton: cta-audio-cue-minimal -->
<section class="audio-cue">
<p class="cue-eyebrow">Audio cue</p>
<div class="cue-stage">
<button class="cue-button" type="button" aria-label="Speel audio voorbeeld">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 5v14l11-7z"/></svg>
</button>
<!-- ripple-rings worden via JS in .cue-stage gespawnd -->
</div>
<p class="cue-meta">
<span class="cue-dot"></span>
<span class="cue-dot"></span>
<span class="cue-dot"></span>
<span class="cue-label">luister</span>
</p>
<hr class="cue-rule" />
<p class="cue-caption">Een fluisterend signaal. Geen geluid voor de show.</p>
</section> /* Styling: cta-audio-cue-minimal — cream/ink, Inter 300, single rule */
.audio-cue {
--paper: #F4F1EB;
--ink: #0A0A0A;
--rule: rgba(10,10,10,.18);
background: var(--paper);
color: var(--ink);
font-family: 'Inter', system-ui, sans-serif;
font-weight: 300;
padding: clamp(3rem, 8vw, 7rem) clamp(2rem, 6vw, 6rem);
min-height: 70vh;
display: grid;
gap: 2.5rem;
align-content: center;
justify-items: start;
max-width: 64ch;
}
.cue-eyebrow {
font-size: .72rem;
letter-spacing: .28em;
text-transform: uppercase;
margin: 0;
opacity: .55;
}
.cue-stage {
position: relative;
width: 96px;
height: 96px;
}
.cue-button {
position: relative;
z-index: 2;
width: 96px;
height: 96px;
border-radius: 50%;
border: 1px solid var(--ink);
background: transparent;
color: var(--ink);
cursor: pointer;
display: grid;
place-items: center;
transition: background .4s ease, color .4s ease;
}
.cue-button:hover { background: var(--ink); color: var(--paper); }
.cue-button svg { width: 26px; height: 26px; fill: currentColor; }
.cue-ring {
position: absolute;
inset: 0;
border-radius: 50%;
border: 1px solid var(--ink);
pointer-events: none;
animation: cueRipple 2.4s ease-out forwards;
}
@keyframes cueRipple {
0% { transform: scale(1); opacity: .4; }
100% { transform: scale(2.5); opacity: 0; }
}
.cue-meta {
display: flex;
align-items: center;
gap: .55rem;
font-size: .8rem;
letter-spacing: .14em;
text-transform: lowercase;
margin: 0;
opacity: .7;
}
.cue-dot {
width: 6px; height: 6px; border-radius: 50%;
background: rgba(10,10,10,.22);
transition: background .2s ease;
}
.cue-dot.on { background: var(--ink); }
.cue-label { margin-left: .35rem; }
.cue-rule {
border: 0;
border-top: 1px solid var(--rule);
width: 100%;
margin: 0;
}
.cue-caption {
font-size: 1rem;
line-height: 1.5;
margin: 0;
max-width: 32ch;
opacity: .75;
}
@media (prefers-reduced-motion: reduce) {
.cue-ring { display: none; }
.cue-dot.on { background: rgba(10,10,10,.22); }
}