Midnight Drive
Neon Coast
1:243:41
const css = `
@keyframes card-id-badge-scan {
0% { transform: translateY(0); opacity: 1; }
80% { transform: translateY(150px); opacity: 1; }
100% { transform: translateY(150px); opacity: 0; }
}
.card-id-badge {
position: relative;
display: grid;
grid-template-columns: 64px 1fr;
gap: 12px;
width: 240px;
padding: 14px;
border-radius: 16px;
background: light-dark(#f3f4f7, #1a1c1f);
box-shadow: inset 0 0 0 1px light-dark(#dbdde1, #2e3035);
overflow: hidden;
cursor: pointer;
}
.card-id-badge:focus-visible { outline: 2px solid light-dark(#42454c, #e5e6e9); outline-offset: 3px; }
.card-id-badge__photo {
position: relative;
height: 78px;
border-radius: 10px;
background: light-dark(#ebedf0, #232529);
overflow: hidden;
}
/* A head-and-shoulders silhouette. */
.card-id-badge__photo::before { content: ''; position: absolute; left: 50%; top: 16px; width: 26px; height: 26px; margin-left: -13px; border-radius: 50%; background: light-dark(#6d7179, #7d8087); }
.card-id-badge__photo::after { content: ''; position: absolute; left: 50%; bottom: -14px; width: 50px; height: 40px; margin-left: -25px; border-radius: 50%; background: light-dark(#6d7179, #7d8087); }
.card-id-badge__name { color: light-dark(#373a40, #f1f2f3); font-size: 13px; font-weight: 600; }
.card-id-badge__role { color: light-dark(#5f626a, #a7abb2); font-size: 11px; margin-bottom: 6px; }
.card-id-badge__field { display: flex; justify-content: space-between; align-items: center; height: 17px; color: light-dark(#5f626a, #a7abb2); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; }
.card-id-badge__field b { color: light-dark(#42454c, #e5e6e9); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 500; letter-spacing: 0; }
.card-id-badge__check { width: 12px; height: 12px; margin-left: 6px; color: light-dark(#373a40, #f1f2f3); opacity: 0; transform: scale(0.4); transition: opacity 0.2s ease, transform 0.3s cubic-bezier(0.34, 1.6, 0.64, 1); }
.card-id-badge__scan {
position: absolute;
left: 0;
right: 0;
top: 0;
height: 2px;
background: light-dark(#373a40, #f1f2f3);
box-shadow: 0 0 10px 3px color-mix(in oklab, light-dark(#373a40, #f1f2f3) 45%, transparent);
opacity: 0;
pointer-events: none;
}
.card-id-badge__stamp {
position: absolute;
left: 10px;
top: 58px;
padding: 2px 6px;
background: light-dark(#f3f4f7, #1a1c1f);
border: 1.5px solid light-dark(#373a40, #f1f2f3);
border-radius: 4px;
color: light-dark(#373a40, #f1f2f3);
font-size: 10px;
font-weight: 600;
letter-spacing: 0.16em;
opacity: 0;
transform: rotate(-14deg) scale(1.8);
transition: opacity 0.2s ease, transform 0.35s cubic-bezier(0.34, 1.6, 0.64, 1);
}
.card-id-badge:hover .card-id-badge__scan, .card-id-badge:focus-visible .card-id-badge__scan { animation: card-id-badge-scan 1.1s cubic-bezier(0.45, 0, 0.55, 1) forwards; }
/* Each field ticks as the scan line passes its row. */
.card-id-badge:hover .card-id-badge__check, .card-id-badge:focus-visible .card-id-badge__check { opacity: 1; transform: none; transition-delay: var(--t); }
.card-id-badge:hover .card-id-badge__stamp, .card-id-badge:focus-visible .card-id-badge__stamp { opacity: 1; transform: rotate(-14deg); transition-delay: 1.05s; }
@media (prefers-reduced-motion: reduce) {
.card-id-badge:hover .card-id-badge__scan { animation: none; }
.card-id-badge__check, .card-id-badge__stamp { transition-duration: 0.01s; }
}
`;
const FIELDS = [
{ k: 'ID', v: 'MV-0418', t: '0.55s' },
{ k: 'Dept', v: 'Design', t: '0.68s' },
{ k: 'Level', v: 'L4', t: '0.81s' },
];
export function IdBadgeCard() {
return (
<>
<style>
{css}
</style>
<div className="card-id-badge" tabIndex={0} role="group" aria-label="Access badge: Sam Okafor, Design, level 4">
<span className="card-id-badge__photo" aria-hidden="true" />
<div>
<div className="card-id-badge__name">Sam Okafor</div>
<div className="card-id-badge__role">Product designer</div>
{FIELDS.map((f) => (
<div key={f.k} className="card-id-badge__field">
{f.k}
<span style={{ display: 'flex', alignItems: 'center' }}>
<b>{f.v}</b>
<svg className="card-id-badge__check" viewBox="0 0 24 24" fill="none" aria-hidden="true" style={{ '--t': f.t } as React.CSSProperties}>
<path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
</div>
))}
</div>
<span className="card-id-badge__scan" aria-hidden="true" />
<span className="card-id-badge__stamp" aria-hidden="true">
CLEARED
</span>
</div>
</>
);
}Markup where the component goes, CSS in your stylesheet. No JavaScript.
<div class="card-id-badge" tabindex="0" role="group" aria-label="Access badge: Sam Okafor, Design, level 4">
<span class="card-id-badge__photo" aria-hidden="true"></span>
<div>
<div class="card-id-badge__name">Sam Okafor</div>
<div class="card-id-badge__role">Product designer</div>
<div class="card-id-badge__field">ID<span style="display:flex;align-items:center"><b>MV-0418</b><svg class="card-id-badge__check" viewBox="0 0 24 24" fill="none" aria-hidden="true" style="--t:0.55s"><path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"></path></svg></span></div>
<div class="card-id-badge__field">Dept<span style="display:flex;align-items:center"><b>Design</b><svg class="card-id-badge__check" viewBox="0 0 24 24" fill="none" aria-hidden="true" style="--t:0.68s"><path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"></path></svg></span></div>
<div class="card-id-badge__field">Level<span style="display:flex;align-items:center"><b>L4</b><svg class="card-id-badge__check" viewBox="0 0 24 24" fill="none" aria-hidden="true" style="--t:0.81s"><path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"></path></svg></span></div>
</div>
<span class="card-id-badge__scan" aria-hidden="true"></span>
<span class="card-id-badge__stamp" aria-hidden="true">CLEARED</span>
</div>@keyframes card-id-badge-scan {
0% { transform: translateY(0); opacity: 1; }
80% { transform: translateY(150px); opacity: 1; }
100% { transform: translateY(150px); opacity: 0; }
}
.card-id-badge {
position: relative;
display: grid;
grid-template-columns: 64px 1fr;
gap: 12px;
width: 240px;
padding: 14px;
border-radius: 16px;
background: light-dark(#f3f4f7, #1a1c1f);
box-shadow: inset 0 0 0 1px light-dark(#dbdde1, #2e3035);
overflow: hidden;
cursor: pointer;
}
.card-id-badge:focus-visible { outline: 2px solid light-dark(#42454c, #e5e6e9); outline-offset: 3px; }
.card-id-badge__photo {
position: relative;
height: 78px;
border-radius: 10px;
background: light-dark(#ebedf0, #232529);
overflow: hidden;
}
/* A head-and-shoulders silhouette. */
.card-id-badge__photo::before { content: ''; position: absolute; left: 50%; top: 16px; width: 26px; height: 26px; margin-left: -13px; border-radius: 50%; background: light-dark(#6d7179, #7d8087); }
.card-id-badge__photo::after { content: ''; position: absolute; left: 50%; bottom: -14px; width: 50px; height: 40px; margin-left: -25px; border-radius: 50%; background: light-dark(#6d7179, #7d8087); }
.card-id-badge__name { color: light-dark(#373a40, #f1f2f3); font-size: 13px; font-weight: 600; }
.card-id-badge__role { color: light-dark(#5f626a, #a7abb2); font-size: 11px; margin-bottom: 6px; }
.card-id-badge__field { display: flex; justify-content: space-between; align-items: center; height: 17px; color: light-dark(#5f626a, #a7abb2); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; }
.card-id-badge__field b { color: light-dark(#42454c, #e5e6e9); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 500; letter-spacing: 0; }
.card-id-badge__check { width: 12px; height: 12px; margin-left: 6px; color: light-dark(#373a40, #f1f2f3); opacity: 0; transform: scale(0.4); transition: opacity 0.2s ease, transform 0.3s cubic-bezier(0.34, 1.6, 0.64, 1); }
.card-id-badge__scan {
position: absolute;
left: 0;
right: 0;
top: 0;
height: 2px;
background: light-dark(#373a40, #f1f2f3);
box-shadow: 0 0 10px 3px color-mix(in oklab, light-dark(#373a40, #f1f2f3) 45%, transparent);
opacity: 0;
pointer-events: none;
}
.card-id-badge__stamp {
position: absolute;
left: 10px;
top: 58px;
padding: 2px 6px;
background: light-dark(#f3f4f7, #1a1c1f);
border: 1.5px solid light-dark(#373a40, #f1f2f3);
border-radius: 4px;
color: light-dark(#373a40, #f1f2f3);
font-size: 10px;
font-weight: 600;
letter-spacing: 0.16em;
opacity: 0;
transform: rotate(-14deg) scale(1.8);
transition: opacity 0.2s ease, transform 0.35s cubic-bezier(0.34, 1.6, 0.64, 1);
}
.card-id-badge:hover .card-id-badge__scan, .card-id-badge:focus-visible .card-id-badge__scan { animation: card-id-badge-scan 1.1s cubic-bezier(0.45, 0, 0.55, 1) forwards; }
/* Each field ticks as the scan line passes its row. */
.card-id-badge:hover .card-id-badge__check, .card-id-badge:focus-visible .card-id-badge__check { opacity: 1; transform: none; transition-delay: var(--t); }
.card-id-badge:hover .card-id-badge__stamp, .card-id-badge:focus-visible .card-id-badge__stamp { opacity: 1; transform: rotate(-14deg); transition-delay: 1.05s; }
@media (prefers-reduced-motion: reduce) {
.card-id-badge:hover .card-id-badge__scan { animation: none; }
.card-id-badge__check, .card-id-badge__stamp { transition-duration: 0.01s; }
}Goal: Create a "ID Badge" card.
Visual behavior: An access badge: on hover a scan line sweeps down it, each field ticks as the line passes its row, and a CLEARED stamp slams onto the photo at the end.
Technique:
- The photo is a head-and-shoulders silhouette drawn with ::before and ::after circles.
- A glowing line runs a one-shot keyframe from the top to the bottom of the badge on hover.
- Each field's tick pops in with a transition-delay timed to when the line crosses its row (0.55, 0.68, 0.81s).
- The stamp starts scaled 1.8 and transparent, and lands rotated -14deg with an overshoot after 1.05s.
Accessibility: The card is focusable (tabIndex 0) with role="group" and an aria-label that sums it up; keyboard focus plays the same reveal as hover. Under prefers-reduced-motion the ticks and stamp appear without the scan.
My stack: {{USER_STACK}}
My styling: {{USER_STYLING}}
My constraints: {{USER_CONSTRAINTS}}
My colors: neutral only. Black, white and grays, no hues. Use the color values above as written, or my project's closest neutral tokens.
Return a single self-contained component. No dependencies.Goal: Create a "ID Badge" card.
Visual behavior: An access badge: on hover a scan line sweeps down it, each field ticks as the line passes its row, and a CLEARED stamp slams onto the photo at the end.
Technique:
- The photo is a head-and-shoulders silhouette drawn with ::before and ::after circles.
- A glowing line runs a one-shot keyframe from the top to the bottom of the badge on hover.
- Each field's tick pops in with a transition-delay timed to when the line crosses its row (0.55, 0.68, 0.81s).
- The stamp starts scaled 1.8 and transparent, and lands rotated -14deg with an overshoot after 1.05s.
Accessibility: The card is focusable (tabIndex 0) with role="group" and an aria-label that sums it up; keyboard focus plays the same reveal as hover. Under prefers-reduced-motion the ticks and stamp appear without the scan.
My stack: {{USER_STACK}}
My styling: {{USER_STYLING}}
My constraints: {{USER_CONSTRAINTS}}
My colors: use my project's existing color tokens. The color values above are grayscale placeholders. Map each one by its role (surface, text, border, accent, glow) to my theme, and keep their relative lightness so contrast and the effect still read.
Return a single self-contained component. No dependencies.Paste into Claude, ChatGPT or Cursor after filling in {{USER_STACK}}, {{USER_STYLING}} and {{USER_CONSTRAINTS}}. Neutral keeps the greys you see here; Match my project asks the model to map them onto your own colour tokens.
Free to use in any project, commercial included. MIT-0, no attribution required. Licence
An access badge: on hover a scan line sweeps down it, each field ticks as the line passes its row, and a CLEARED stamp slams onto the photo at the end.
The card is focusable (tabIndex 0) with role="group" and an aria-label that sums it up; keyboard focus plays the same reveal as hover. Under prefers-reduced-motion the ticks and stamp appear without the scan.