CSS
/* ─── 04 Selected Work Grid — collision-typography portfolio ──── */
@import url('https://fonts.googleapis.com/css2?family=Anton&family=Syne:wght@400;700;800&family=Syne+Mono&display=swap');
.br-swg {
--br-swg-bg: #f2ede6;
--br-swg-black: #0d0d0d;
--br-swg-white: #f2ede6;
--br-swg-lime: #b6ff00;
--br-swg-pink: #ff2d6b;
--br-swg-blue: #0040ff;
position: relative;
width: 100%;
height: 720px;
background: var(--br-swg-bg);
font-family: 'Syne', sans-serif;
overflow: hidden;
box-sizing: border-box;
}
.br-swg *,
.br-swg *::before,
.br-swg *::after { box-sizing: border-box; margin: 0; padding: 0; }
.br-swg .card {
position: absolute;
inset: 0;
}
/* Custom cursor — scoped to wrapper, doesn't hijack global cursor */
.br-swg .swg-cursor-dot,
.br-swg .swg-cursor-ring,
.br-swg .swg-cursor-label {
position: absolute;
pointer-events: none;
display: none;
}
.br-swg.cursor-active .swg-cursor-dot,
.br-swg.cursor-active .swg-cursor-ring,
.br-swg.cursor-active .swg-cursor-label { display: block; }
.br-swg.cursor-active * { cursor: none !important; }
.br-swg .swg-cursor-dot {
width: 10px; height: 10px;
background: var(--br-swg-black);
border-radius: 50%;
z-index: 9999;
transform: translate(-50%, -50%);
transition: width 0.2s, height 0.2s, background 0.2s;
mix-blend-mode: difference;
}
.br-swg .swg-cursor-ring {
width: 44px; height: 44px;
border: 2px solid var(--br-swg-black);
border-radius: 50%;
z-index: 9998;
transform: translate(-50%, -50%);
transition: width 0.25s, height 0.25s, border-color 0.2s;
mix-blend-mode: difference;
}
.br-swg .swg-cursor-label {
z-index: 9997;
font-family: 'Syne Mono', monospace;
font-size: 10px;
letter-spacing: 2px;
text-transform: uppercase;
color: var(--br-swg-black);
transform: translate(14px, -6px);
opacity: 0;
transition: opacity 0.15s;
white-space: nowrap;
}
.br-swg.on-work .swg-cursor-dot { width: 60px; height: 60px; background: var(--br-swg-lime); }
.br-swg.on-work .swg-cursor-ring { width: 80px; height: 80px; border-color: var(--br-swg-lime); }
.br-swg.on-work .swg-cursor-label { opacity: 1; }
/* Hero type */
.br-swg .hero-type {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 2;
overflow: hidden;
}
.br-swg .hero-word {
font-family: 'Anton', sans-serif;
position: absolute;
line-height: 0.88;
letter-spacing: -0.03em;
white-space: nowrap;
user-select: none;
}
.br-swg .hw-selected { color: var(--br-swg-black); font-size: 22vw; top: -0.05em; left: -0.02em; z-index: 1; }
.br-swg .hw-work { color: transparent; font-size: 19vw; bottom: -0.1em; right: -0.02em; z-index: 0;
-webkit-text-stroke: 2px var(--br-swg-black); }
.br-swg .hw-year { color: var(--br-swg-lime); font-size: 6vw; bottom: 56px; left: 20px; z-index: 3;
mix-blend-mode: multiply; }
/* Stage grid */
.br-swg .stage {
position: absolute;
inset: 0 0 36px 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.br-swg .cell {
position: relative;
border: 3px solid var(--br-swg-black);
border-left: none; border-top: none;
overflow: hidden;
z-index: 3;
}
.br-swg .cell:nth-child(3n) { border-right: none; }
.br-swg .cell:nth-child(n+4) { border-bottom: none; }
.br-swg .cell-inner {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 20px 22px;
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.br-swg .cell-1 { background: var(--br-swg-black); border-left: 3px solid var(--br-swg-black); border-top: 3px solid var(--br-swg-black); }
.br-swg .cell-2 { background: var(--br-swg-bg); border-top: 3px solid var(--br-swg-black); }
.br-swg .cell-3 { background: var(--br-swg-pink); border-top: 3px solid var(--br-swg-black); border-right: none; }
.br-swg .cell-4 { background: var(--br-swg-blue); border-left: 3px solid var(--br-swg-black); border-bottom: none; }
.br-swg .cell-5 { background: var(--br-swg-bg); border-bottom: none; }
.br-swg .cell-6 { background: var(--br-swg-lime); border-right: none; border-bottom: none; }
.br-swg .cell:hover .cell-inner { transform: translateY(-8px); }
.br-swg .cell:hover { z-index: 10; }
.br-swg .cell-num {
font-family: 'Syne Mono', monospace;
font-size: 10px;
letter-spacing: 3px;
margin-bottom: 8px;
opacity: 0.5;
}
.br-swg .cell-1 .cell-num { color: #555; }
.br-swg .cell-2 .cell-num, .br-swg .cell-5 .cell-num { color: #aaa; }
.br-swg .cell-3 .cell-num { color: rgba(255,255,255,0.5); }
.br-swg .cell-4 .cell-num { color: rgba(255,255,255,0.4); }
.br-swg .cell-6 .cell-num { color: rgba(0,0,0,0.4); }
.br-swg .cell-title {
font-family: 'Anton', sans-serif;
font-size: clamp(22px, 2.8vw, 36px);
line-height: 0.95;
letter-spacing: 0.01em;
}
.br-swg .cell-1 .cell-title { color: var(--br-swg-white); }
.br-swg .cell-2 .cell-title { color: var(--br-swg-black); }
.br-swg .cell-3 .cell-title { color: var(--br-swg-white); }
.br-swg .cell-4 .cell-title { color: var(--br-swg-lime); }
.br-swg .cell-5 .cell-title { color: var(--br-swg-black); }
.br-swg .cell-6 .cell-title { color: var(--br-swg-black); }
.br-swg .cell-tag {
font-size: 9px;
letter-spacing: 3px;
text-transform: uppercase;
margin-top: 8px;
font-weight: 600;
}
.br-swg .cell-1 .cell-tag { color: var(--br-swg-lime); }
.br-swg .cell-2 .cell-tag { color: #888; }
.br-swg .cell-3 .cell-tag { color: rgba(255,255,255,0.7); }
.br-swg .cell-4 .cell-tag { color: rgba(255,255,255,0.6); }
.br-swg .cell-5 .cell-tag { color: #999; }
.br-swg .cell-6 .cell-tag { color: rgba(0,0,0,0.5); }
.br-swg .cell-vis { position: absolute; pointer-events: none; }
.br-swg .cell-1 .cell-vis {
width: 120px; height: 120px;
border-radius: 50%;
border: 3px solid #2a2a2a;
top: 20px; right: 20px;
}
.br-swg .cell-1 .cell-vis::after {
content: '';
width: 60px; height: 60px;
border-radius: 50%;
background: var(--br-swg-lime);
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
}
.br-swg .cell-2 .cell-vis {
width: 100%; height: 100%;
top: 0; left: 0;
background: linear-gradient(135deg, transparent 48%, #ddd 48%, #ddd 52%, transparent 52%);
}
.br-swg .cell-3 .cell-vis {
top: 16px; right: 16px;
font-family: 'Anton', sans-serif;
font-size: 80px;
color: rgba(255,255,255,0.15);
line-height: 1;
}
.br-swg .cell-4 .cell-vis { top: 20px; left: 20px; right: 20px; }
.br-swg .bar-set { display: flex; flex-direction: column; gap: 6px; }
.br-swg .bar-item { height: 4px; background: rgba(255,255,255,0.15); position: relative; }
.br-swg .bar-item::before {
content: '';
position: absolute; left: 0; top: 0; height: 100%;
background: var(--br-swg-lime);
}
.br-swg .b1::before { width: 80%; }
.br-swg .b2::before { width: 55%; }
.br-swg .b3::before { width: 92%; }
.br-swg .b4::before { width: 40%; }
.br-swg .cell-5 .cell-vis {
top: 10px; left: 16px;
font-family: 'Anton', sans-serif;
font-size: 100px;
color: rgba(0,0,0,0.05);
line-height: 1;
letter-spacing: -5px;
}
.br-swg .cell-6 .cell-vis {
top: 0; left: 0; right: 0; bottom: 0;
background-image: radial-gradient(circle, rgba(0,0,0,0.2) 1.5px, transparent 1.5px);
background-size: 20px 20px;
}
.br-swg .cell::after {
content: '→';
position: absolute;
top: 20px; right: 22px;
font-family: 'Anton', sans-serif;
font-size: 28px;
opacity: 0;
transition: opacity 0.2s, transform 0.2s;
transform: translateX(-8px);
pointer-events: none;
}
.br-swg .cell-1::after { color: var(--br-swg-lime); }
.br-swg .cell-2::after, .br-swg .cell-5::after { color: var(--br-swg-black); }
.br-swg .cell-3::after { color: white; }
.br-swg .cell-4::after { color: var(--br-swg-lime); }
.br-swg .cell-6::after { color: var(--br-swg-black); }
.br-swg .cell:hover::after { opacity: 1; transform: translateX(0); }
/* Ticker — absolute to wrapper, not viewport */
.br-swg .ticker {
position: absolute;
bottom: 0; left: 0; right: 0;
background: var(--br-swg-black);
padding: 7px 0;
overflow: hidden;
z-index: 20;
border-top: 3px solid var(--br-swg-black);
pointer-events: none;
}
.br-swg .ticker-inner {
display: flex;
gap: 0;
animation: br-swg-ticker 18s linear infinite;
white-space: nowrap;
}
@keyframes br-swg-ticker { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.br-swg .ticker-item {
font-family: 'Syne Mono', monospace;
font-size: 10px;
letter-spacing: 4px;
text-transform: uppercase;
color: var(--br-swg-lime);
padding: 0 32px;
}
.br-swg .ticker-sep { color: #333; padding: 0; font-family: 'Syne Mono', monospace; font-size: 10px; }
@media (prefers-reduced-motion: reduce) {
.br-swg .ticker-inner,
.br-swg .cell-inner,
.br-swg .cell::after { animation: none !important; transition: none !important; }
} JS
(() => {
const root = document.querySelector('.br-swg');
if (!root) return;
const dot = root.querySelector('[data-br-swg-dot]');
const ring = root.querySelector('[data-br-swg-ring]');
const label = root.querySelector('[data-br-swg-label]');
if (!dot || !ring || !label) return;
let mx = 0, my = 0, rx = 0, ry = 0, rafId = null;
root.addEventListener('mouseenter', () => root.classList.add('cursor-active'));
root.addEventListener('mouseleave', () => {
root.classList.remove('cursor-active');
root.classList.remove('on-work');
if (rafId) { cancelAnimationFrame(rafId); rafId = null; }
});
root.addEventListener('mousemove', e => {
const rect = root.getBoundingClientRect();
mx = e.clientX - rect.left;
my = e.clientY - rect.top;
dot.style.left = mx + 'px';
dot.style.top = my + 'px';
label.style.left = mx + 'px';
label.style.top = my + 'px';
if (!rafId) rafId = requestAnimationFrame(lerpRing);
});
function lerpRing() {
rx += (mx - rx) * 0.14;
ry += (my - ry) * 0.14;
ring.style.left = rx + 'px';
ring.style.top = ry + 'px';
if (Math.abs(mx - rx) > 0.5 || Math.abs(my - ry) > 0.5) {
rafId = requestAnimationFrame(lerpRing);
} else {
rafId = null;
}
}
root.querySelectorAll('.cell').forEach(cell => {
cell.addEventListener('mouseenter', () => root.classList.add('on-work'));
cell.addEventListener('mouseleave', () => root.classList.remove('on-work'));
});
})();