Sauberes 3-Spalten-Raster (mobil einspaltig). Bei Hover/Fokus gleitet ein ruhiges Overlay mit Titel + Kategorie herein. Die Filter-Chips oben sind dezente Optik und filtern per Progressive Enhancement — ohne JS bleiben alle Kacheln sichtbar. Bilder als CSS-Verlauf angedeutet (im Projekt durch <img> ersetzen).
Referenzen
Ausgewählte Projekte
<section class="rf-grid" aria-label="Referenzen">
<div class="rf-grid-head">
<p class="rf-grid-eyebrow">Referenzen</p>
<h2 class="rf-grid-title">Ausgewählte Projekte</h2>
</div>
<ul class="rf-chips" role="group" aria-label="Nach Kategorie filtern">
<li><button type="button" class="rf-chip" data-filter="alle" aria-pressed="true">Alle</button></li>
<li><button type="button" class="rf-chip" data-filter="bad" aria-pressed="false">Bad</button></li>
<li><button type="button" class="rf-chip" data-filter="kueche" aria-pressed="false">Küche</button></li>
</ul>
<div class="rf-tiles">
<a class="rf-tile" href="#" data-kat="bad">
<!-- statt Verlauf hier ein <img> in .rf-tile-img einsetzen -->
<span class="rf-tile-img" aria-hidden="true"></span>
<span class="rf-tile-veil" aria-hidden="true"></span>
<span class="rf-tile-cap">
<span class="rf-tile-kat">Badsanierung</span>
<span class="rf-tile-name">Wellnessbad in Eiche</span>
</span>
</a>
<!-- weitere .rf-tile analog; data-kat steuert den Filter -->
</div>
</section>
<style>
.rf-grid{width:100%;background:#16161a;border:1px solid #26262c;border-radius:18px;
padding:1.6rem;color:#e9e9ee}
@media(min-width:720px){.rf-grid{padding:2.4rem}}
.rf-grid-head{margin:0 0 1.4rem}
.rf-grid-eyebrow{margin:0 0 .5rem;font-size:.74rem;font-weight:600;letter-spacing:.16em;
text-transform:uppercase;color:var(--akzent,#7c87ff)}
.rf-grid-title{margin:0;font-size:clamp(1.4rem,3.2vw,1.95rem);line-height:1.15;
letter-spacing:-.01em;color:#f4f4f5}
.rf-chips{list-style:none;display:flex;flex-wrap:wrap;gap:.5rem;margin:1.2rem 0 1.6rem;padding:0}
.rf-chip{font-size:.82rem;font-weight:600;color:#a1a1aa;background:#17171b;
border:1px solid #26262c;border-radius:99px;padding:.42rem .95rem;cursor:pointer;
transition:color .2s ease,border-color .2s ease,background .2s ease}
.rf-chip:hover,.rf-chip:focus-visible{color:#f4f4f5;border-color:#3a3a45;outline:none}
.rf-chip:focus-visible{outline:2px solid var(--akzent,#7c87ff);outline-offset:2px}
.rf-chip[aria-pressed="true"]{color:#0f0f12;background:var(--akzent,#7c87ff);
border-color:var(--akzent,#7c87ff)}
.rf-tiles{display:grid;gap:1rem;grid-template-columns:1fr}
@media(min-width:560px){.rf-tiles{grid-template-columns:repeat(2,1fr)}}
@media(min-width:840px){.rf-tiles{grid-template-columns:repeat(3,1fr)}}
.rf-tile{position:relative;display:block;aspect-ratio:4/3;border-radius:14px;overflow:hidden;
border:1px solid #26262c;color:#f4f4f5;isolation:isolate}
.rf-tile.is-off{display:none}
.rf-tile-img{position:absolute;inset:0;z-index:0}
.rf-tile:nth-child(1) .rf-tile-img{background:radial-gradient(120% 110% at 25% 15%,#3b3b54 0%,#24242f 48%,#15151b 100%)}
.rf-tile:nth-child(2) .rf-tile-img{background:radial-gradient(120% 110% at 80% 20%,#2f4448 0%,#20303233 45%,#141a1c 100%)}
.rf-tile:nth-child(3) .rf-tile-img{background:radial-gradient(130% 120% at 50% 90%,#4a3550 0%,#2a2233 50%,#161018 100%)}
.rf-tile:nth-child(4) .rf-tile-img{background:radial-gradient(120% 110% at 20% 80%,#453b28 0%,#2b2620 48%,#171310 100%)}
.rf-tile:nth-child(5) .rf-tile-img{background:radial-gradient(120% 100% at 70% 30%,#28324e 0%,#1e2536 45%,#12151f 100%)}
.rf-tile:nth-child(6) .rf-tile-img{background:radial-gradient(120% 110% at 40% 20%,#3d3d46 0%,#26262f 48%,#141419 100%)}
.rf-tile-veil{position:absolute;inset:0;z-index:1;
background:linear-gradient(to top,rgba(12,12,16,.82) 0%,rgba(12,12,16,.15) 55%,transparent 100%);
opacity:0;transform:translateY(12px);
transition:opacity .3s ease,transform .3s ease}
.rf-tile-cap{position:absolute;left:1rem;right:1rem;bottom:1rem;z-index:2;
transform:translateY(10px);opacity:0;
transition:opacity .3s ease .04s,transform .3s ease .04s}
.rf-tile-kat{display:block;font-size:.72rem;font-weight:700;letter-spacing:.1em;
text-transform:uppercase;color:var(--akzent,#7c87ff);margin:0 0 .25rem}
.rf-tile-name{font-size:1.02rem;font-weight:700;line-height:1.2;margin:0}
.rf-tile:hover .rf-tile-veil,.rf-tile:focus-visible .rf-tile-veil,
.rf-tile:hover .rf-tile-cap,.rf-tile:focus-visible .rf-tile-cap{opacity:1;transform:translateY(0)}
.rf-tile:focus-visible{outline:2px solid var(--akzent,#7c87ff);outline-offset:3px}
@media (prefers-reduced-motion:reduce){
.rf-chip,.rf-tile-veil,.rf-tile-cap{transition:none}
}
</style>
<script>
// Filter-Chips (Progressive Enhancement — ohne JS bleiben alle Kacheln sichtbar)
document.querySelectorAll('.rf-grid').forEach((sec) => {
const chips = sec.querySelectorAll('.rf-chip');
const tiles = sec.querySelectorAll('.rf-tile');
chips.forEach((chip) => chip.addEventListener('click', () => {
const f = chip.dataset.filter;
chips.forEach((c) => c.setAttribute('aria-pressed', String(c === chip)));
tiles.forEach((t) => {
const show = f === 'alle' || t.dataset.kat === f;
t.classList.toggle('is-off', !show);
});
}));
});
</script>