Real Estate — Lead Card
An editorial buyer-lead card for a real-estate CRM pipeline, with initials avatar, phone and email contacts, a source tag, budget and desired-area chips, a colour-coded status pill that cycles through New, Contacted, Touring and Offer, a star priority toggle, last-activity timestamp, and quick call, email and inline-note actions. Built with semantic HTML, a warm ivory-and-brass palette, faux listing photography rendered in pure CSS, and dependency-free vanilla JavaScript.
MCP
程式碼
:root {
--ivory: #f7f4ec;
--paper: #fffdf8;
--white: #ffffff;
--green: #1f3d34;
--green-d: #16302a;
--green-700: #26493e;
--green-50: #e8efea;
--brass: #b08d57;
--brass-d: #94733f;
--brass-50: #f3ead9;
--ink: #1c2a25;
--ink-2: #33433d;
--muted: #6b7a72;
--line: rgba(31, 61, 52, 0.12);
--line-2: rgba(31, 61, 52, 0.22);
--ok: #2f9e6f;
--warn: #c98a2b;
--danger: #c4503e;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 22px;
--sh-1: 0 1px 2px rgba(22, 48, 42, 0.06), 0 1px 1px rgba(22, 48, 42, 0.04);
--sh-2: 0 12px 30px -16px rgba(22, 48, 42, 0.28), 0 4px 10px -6px rgba(22, 48, 42, 0.16);
--sh-3: 0 26px 60px -28px rgba(22, 48, 42, 0.42);
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
background:
radial-gradient(1200px 700px at 84% -8%, rgba(176, 141, 87, 0.1), transparent 60%),
radial-gradient(900px 600px at -10% 4%, rgba(31, 61, 52, 0.07), transparent 55%),
var(--ivory);
color: var(--ink);
font-family: "Inter", system-ui, -apple-system, sans-serif;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.shell {
max-width: 560px;
margin: 0 auto;
padding: 48px 24px 80px;
}
/* ---------- Masthead ---------- */
.masthead { margin-bottom: 30px; }
.eyebrow {
margin: 0 0 10px;
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--brass-d);
}
.eyebrow::before {
content: "";
display: inline-block;
width: 26px;
height: 1px;
margin-right: 10px;
vertical-align: middle;
background: var(--brass);
}
.masthead h1 {
margin: 0 0 8px;
font-family: "Cormorant Garamond", Georgia, serif;
font-weight: 600;
font-size: clamp(2.4rem, 6vw, 3.1rem);
line-height: 1.05;
letter-spacing: -0.01em;
color: var(--green-d);
}
.masthead .sub {
margin: 0;
max-width: 44ch;
color: var(--muted);
font-size: 0.95rem;
}
/* ---------- List ---------- */
.lead-list {
display: flex;
flex-direction: column;
gap: 22px;
}
/* ---------- Card ---------- */
.lead {
position: relative;
overflow: hidden;
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--r-lg);
box-shadow: var(--sh-2);
transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1),
box-shadow 0.28s ease, border-color 0.28s ease;
}
.lead::before {
content: "";
position: absolute;
inset: 0 auto 0 0;
width: 3px;
background: var(--line-2);
transition: background 0.3s ease;
}
.lead:hover {
transform: translateY(-3px);
box-shadow: var(--sh-3);
border-color: var(--line-2);
}
.lead:focus-within { outline: none; }
/* ---------- Media / faux photography ---------- */
.lead__media {
position: relative;
aspect-ratio: 16 / 6;
display: flex;
align-items: flex-end;
padding: 12px 14px;
}
.lead__media::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 36%, rgba(20, 30, 26, 0.42));
pointer-events: none;
}
.lead__shot-label {
position: relative;
z-index: 1;
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.05em;
color: rgba(255, 255, 255, 0.96);
background: rgba(22, 48, 42, 0.34);
backdrop-filter: blur(3px);
padding: 4px 10px;
border-radius: 999px;
border: 1px solid rgba(255, 255, 255, 0.28);
}
/* Distinct architectural "photos" per card */
.lead__media[data-shot="a"] {
background:
radial-gradient(120% 90% at 80% 10%, rgba(255, 240, 214, 0.6), transparent 55%),
linear-gradient(115deg, #2c4a5e 0%, #3f6f7a 42%, #7fa7a0 100%),
repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.06) 0 2px, transparent 2px 26px);
}
.lead__media[data-shot="b"] {
background:
radial-gradient(110% 120% at 18% 0%, rgba(255, 246, 220, 0.7), transparent 50%),
linear-gradient(120deg, #8a5a35 0%, #b9824c 45%, #e0b97e 100%),
repeating-linear-gradient(85deg, rgba(60, 36, 18, 0.12) 0 3px, transparent 3px 30px);
}
.lead__media[data-shot="c"] {
background:
radial-gradient(120% 110% at 75% 0%, rgba(255, 232, 198, 0.55), transparent 55%),
linear-gradient(125deg, #3a3550 0%, #6b5d7e 48%, #b39fb0 100%),
repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 22px);
}
.lead__media[data-shot="d"] {
background:
radial-gradient(130% 100% at 30% 6%, rgba(232, 245, 234, 0.55), transparent 55%),
linear-gradient(120deg, #1f3d34 0%, #34614f 46%, #84a98c 100%),
repeating-linear-gradient(70deg, rgba(255, 255, 255, 0.05) 0 2px, transparent 2px 28px);
}
/* ---------- Body ---------- */
.lead__body { padding: 18px 20px 20px; }
.lead__top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.lead__who {
display: flex;
align-items: center;
gap: 13px;
min-width: 0;
}
.avatar {
flex: none;
width: 46px;
height: 46px;
border-radius: 50%;
display: grid;
place-items: center;
font-weight: 700;
font-size: 0.92rem;
letter-spacing: 0.02em;
color: var(--white);
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.4), var(--sh-1);
}
.avatar[data-tone="1"] { background: linear-gradient(140deg, #2f6f5b, #1f3d34); }
.avatar[data-tone="2"] { background: linear-gradient(140deg, #b9824c, #94733f); }
.avatar[data-tone="3"] { background: linear-gradient(140deg, #6b5d7e, #443a5a); }
.avatar[data-tone="4"] { background: linear-gradient(140deg, #3a7a6a, #26493e); }
.lead__id { min-width: 0; }
.lead__name {
margin: 0 0 3px;
font-family: "Cormorant Garamond", Georgia, serif;
font-weight: 600;
font-size: 1.5rem;
line-height: 1.1;
color: var(--green-d);
}
.lead__contact {
display: flex;
flex-wrap: wrap;
gap: 4px 14px;
}
.contact {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 0.8rem;
color: var(--muted);
text-decoration: none;
transition: color 0.2s ease;
}
.contact svg { width: 13px; height: 13px; fill: var(--brass); flex: none; }
.contact:hover { color: var(--green-700); }
/* ---------- Star ---------- */
.star {
flex: none;
width: 38px;
height: 38px;
display: grid;
place-items: center;
border: 1px solid var(--line);
border-radius: 50%;
background: var(--white);
cursor: pointer;
transition: transform 0.18s ease, border-color 0.2s ease, background 0.2s ease;
}
.star svg { width: 18px; height: 18px; fill: none; stroke: var(--muted); stroke-width: 1.6; }
.star:hover { transform: scale(1.08); border-color: var(--brass); }
.star:active { transform: scale(0.94); }
.star.is-on { background: var(--brass-50); border-color: var(--brass); }
.star.is-on svg { fill: var(--brass); stroke: var(--brass-d); }
.star.bump { animation: starPop 0.32s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes starPop {
0% { transform: scale(1); }
45% { transform: scale(1.32) rotate(8deg); }
100% { transform: scale(1); }
}
/* ---------- Facts / chips ---------- */
.lead__facts {
display: flex;
flex-wrap: wrap;
gap: 7px;
margin: 15px 0 14px;
}
.chip {
font-size: 0.74rem;
font-weight: 500;
color: var(--ink-2);
background: var(--green-50);
border: 1px solid var(--line);
padding: 4px 10px;
border-radius: 999px;
white-space: nowrap;
}
.chip--brass {
color: var(--brass-d);
background: var(--brass-50);
border-color: rgba(176, 141, 87, 0.34);
}
/* ---------- Meta row: status pill + activity ---------- */
.lead__meta {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
flex-wrap: wrap;
padding-top: 14px;
border-top: 1px solid var(--line);
}
.pill {
display: inline-flex;
align-items: center;
gap: 8px;
font: inherit;
font-size: 0.78rem;
font-weight: 600;
letter-spacing: 0.01em;
padding: 6px 13px;
border-radius: 999px;
border: 1px solid currentColor;
background: var(--white);
cursor: pointer;
transition: transform 0.16s ease, box-shadow 0.2s ease, background 0.2s ease;
}
.pill__dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: currentColor;
box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 22%, transparent);
}
.pill:hover { transform: translateY(-1px); box-shadow: var(--sh-1); }
.pill:active { transform: translateY(0); }
.pill.flash { animation: pillFlash 0.4s ease; }
@keyframes pillFlash {
0% { box-shadow: 0 0 0 0 color-mix(in srgb, currentColor 38%, transparent); }
100% { box-shadow: 0 0 0 12px transparent; }
}
/* status colour mapping (drives pill + left accent) */
.lead[data-status="new"] .pill { color: #2563a8; background: #eaf2fb; }
.lead[data-status="new"]::before { background: #2563a8; }
.lead[data-status="contacted"] .pill { color: var(--warn); background: #fbf1e2; }
.lead[data-status="contacted"]::before { background: var(--warn); }
.lead[data-status="touring"] .pill { color: var(--green-700); background: var(--green-50); }
.lead[data-status="touring"]::before { background: var(--green-700); }
.lead[data-status="offer"] .pill { color: var(--brass-d); background: var(--brass-50); }
.lead[data-status="offer"]::before { background: var(--brass-d); }
.activity {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 0.76rem;
color: var(--muted);
}
.activity svg { width: 14px; height: 14px; fill: var(--muted); flex: none; }
/* ---------- Notes ---------- */
.notes {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 14px;
}
.note {
font-size: 0.82rem;
color: var(--ink-2);
background: var(--ivory);
border: 1px solid var(--line);
border-left: 3px solid var(--brass);
border-radius: var(--r-sm);
padding: 9px 12px;
animation: noteIn 0.3s ease;
}
.note__time {
display: block;
font-size: 0.68rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--brass-d);
margin-bottom: 2px;
}
@keyframes noteIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: none; }
}
/* note composer */
.note-form {
display: flex;
gap: 8px;
margin-top: 12px;
animation: noteIn 0.24s ease;
}
.note-form input {
flex: 1;
min-width: 0;
font: inherit;
font-size: 0.85rem;
padding: 9px 12px;
border: 1px solid var(--line-2);
border-radius: var(--r-sm);
background: var(--white);
color: var(--ink);
}
.note-form input:focus {
outline: none;
border-color: var(--brass);
box-shadow: 0 0 0 3px var(--brass-50);
}
.note-form button {
flex: none;
font: inherit;
font-size: 0.82rem;
font-weight: 600;
padding: 9px 16px;
border: none;
border-radius: var(--r-sm);
background: var(--green);
color: var(--white);
cursor: pointer;
transition: background 0.2s ease;
}
.note-form button:hover { background: var(--green-d); }
/* ---------- Quick actions ---------- */
.lead__actions {
display: flex;
gap: 8px;
margin-top: 16px;
}
.act {
flex: 1;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
font: inherit;
font-size: 0.82rem;
font-weight: 600;
text-decoration: none;
color: var(--green-d);
background: var(--white);
border: 1px solid var(--line-2);
border-radius: var(--r-md);
padding: 9px 10px;
cursor: pointer;
transition: transform 0.16s ease, background 0.2s ease, color 0.2s ease,
border-color 0.2s ease, box-shadow 0.2s ease;
}
.act svg { width: 15px; height: 15px; fill: currentColor; }
.act:hover {
background: var(--green);
color: var(--white);
border-color: var(--green);
box-shadow: var(--sh-1);
}
.act:active { transform: translateY(1px); }
.act--ghost { color: var(--brass-d); }
.act--ghost:hover { background: var(--brass); border-color: var(--brass); color: var(--white); }
/* keyboard focus visibility */
.star:focus-visible,
.pill:focus-visible,
.act:focus-visible,
.contact:focus-visible,
.note-form input:focus-visible,
.note-form button:focus-visible {
outline: 2px solid var(--green-700);
outline-offset: 2px;
}
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 18px);
background: var(--green-d);
color: var(--paper);
font-size: 0.85rem;
font-weight: 500;
padding: 11px 18px;
border-radius: 999px;
box-shadow: var(--sh-3);
opacity: 0;
pointer-events: none;
transition: opacity 0.28s ease, transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
z-index: 50;
max-width: calc(100vw - 32px);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* ---------- Responsive ---------- */
@media (max-width: 520px) {
.shell { padding: 34px 16px 70px; }
.lead__body { padding: 16px 15px 17px; }
.lead__name { font-size: 1.32rem; }
.lead__media { aspect-ratio: 16 / 7; }
.lead__actions { flex-wrap: wrap; }
.act { flex: 1 1 30%; padding: 9px 6px; }
.lead__meta { gap: 8px; }
.contact span { font-size: 0.76rem; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.001ms !important;
transition-duration: 0.001ms !important;
}
}
/* Visibility guard: honor the [hidden] attribute over base display */
.notes[hidden] {
display: none;
}(function () {
"use strict";
/* ---- Status cycle definition ---- */
var STATUS_ORDER = ["new", "contacted", "touring", "offer"];
var STATUS_LABEL = {
new: "New",
contacted: "Contacted",
touring: "Touring",
offer: "Offer",
};
/* ---- Toast helper ---- */
var toastEl = document.getElementById("toast");
var toastTimer = null;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
window.clearTimeout(toastTimer);
toastTimer = window.setTimeout(function () {
toastEl.classList.remove("show");
}, 2400);
}
function leadName(card) {
var n = card.querySelector(".lead__name");
return n ? n.textContent.trim() : "Lead";
}
/* ---- Status cycling ---- */
function cycleStatus(card) {
var current = card.getAttribute("data-status") || "new";
var idx = STATUS_ORDER.indexOf(current);
var next = STATUS_ORDER[(idx + 1) % STATUS_ORDER.length];
card.setAttribute("data-status", next);
var pill = card.querySelector(".pill");
var text = card.querySelector(".pill__text");
if (text) text.textContent = STATUS_LABEL[next];
if (pill) {
pill.classList.remove("flash");
// reflow to restart animation
void pill.offsetWidth;
pill.classList.add("flash");
}
toast(leadName(card) + " moved to " + STATUS_LABEL[next]);
}
/* ---- Star / priority toggle ---- */
function toggleStar(btn, card) {
var on = btn.classList.toggle("is-on");
btn.setAttribute("aria-pressed", on ? "true" : "false");
card.setAttribute("data-priority", on ? "true" : "false");
btn.classList.remove("bump");
void btn.offsetWidth;
btn.classList.add("bump");
toast(
on
? leadName(card) + " flagged as priority"
: "Priority removed for " + leadName(card)
);
}
/* ---- Add note inline ---- */
function nowStamp() {
var d = new Date();
var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
var h = d.getHours();
var ampm = h >= 12 ? "PM" : "AM";
var hr = h % 12 || 12;
var min = ("0" + d.getMinutes()).slice(-2);
return days[d.getDay()] + " · " + hr + ":" + min + " " + ampm;
}
function appendNote(notesEl, value) {
var note = document.createElement("div");
note.className = "note";
var time = document.createElement("span");
time.className = "note__time";
time.textContent = nowStamp();
note.appendChild(time);
note.appendChild(document.createTextNode(value));
notesEl.appendChild(note);
}
function openNoteForm(card) {
var notesEl = card.querySelector("[data-notes]");
if (!notesEl) return;
notesEl.hidden = false;
// avoid duplicate composer
if (card.querySelector(".note-form")) {
var existing = card.querySelector(".note-form input");
if (existing) existing.focus();
return;
}
var form = document.createElement("form");
form.className = "note-form";
var input = document.createElement("input");
input.type = "text";
input.placeholder = "Quick note about this lead…";
input.setAttribute("aria-label", "Note for " + leadName(card));
input.maxLength = 160;
var submit = document.createElement("button");
submit.type = "submit";
submit.textContent = "Save";
form.appendChild(input);
form.appendChild(submit);
notesEl.insertAdjacentElement("afterend", form);
input.focus();
form.addEventListener("submit", function (e) {
e.preventDefault();
var v = input.value.trim();
if (!v) {
input.focus();
return;
}
appendNote(notesEl, v);
form.remove();
toast("Note added to " + leadName(card));
});
input.addEventListener("keydown", function (e) {
if (e.key === "Escape") {
form.remove();
}
});
}
/* ---- Event delegation ---- */
var list = document.getElementById("leadList");
if (!list) return;
list.addEventListener("click", function (e) {
var card = e.target.closest(".lead");
if (!card) return;
var star = e.target.closest(".star");
if (star) {
e.preventDefault();
toggleStar(star, card);
return;
}
var statusBtn = e.target.closest('[data-action="status"]');
if (statusBtn) {
e.preventDefault();
cycleStatus(card);
return;
}
var noteBtn = e.target.closest('[data-action="note"]');
if (noteBtn) {
e.preventDefault();
openNoteForm(card);
return;
}
// Let real tel:/mailto: links and contact rows behave naturally,
// but surface a toast for the in-card quick actions.
var act = e.target.closest("a.act");
if (act) {
var label = act.textContent.trim();
toast(label + " · " + leadName(card));
}
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Real Estate — Lead Card</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600;700&family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="shell">
<header class="masthead">
<p class="eyebrow">Maison & Vale · Buyer Pipeline</p>
<h1>Lead Cards</h1>
<p class="sub">
Active buyers moving through the pipeline. Cycle a status, flag a priority,
or drop a quick note without leaving the card.
</p>
</header>
<section class="lead-list" id="leadList" aria-label="Buyer leads">
<!-- Lead 1 -->
<article class="lead" data-status="new" data-priority="true" tabindex="-1">
<div class="lead__media" aria-hidden="true" data-shot="a">
<span class="lead__shot-label">North Loop Tower</span>
</div>
<div class="lead__body">
<div class="lead__top">
<div class="lead__who">
<span class="avatar" data-tone="1" aria-hidden="true">EM</span>
<div class="lead__id">
<h2 class="lead__name">Elena Marchetti</h2>
<div class="lead__contact">
<a class="contact" href="tel:+15125550148" aria-label="Call Elena Marchetti">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 10.8a15.5 15.5 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.5.56 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .56 3.5 1 1 0 0 1-.24 1z"/></svg>
<span>(512) 555-0148</span>
</a>
<a class="contact" href="mailto:[email protected]" aria-label="Email Elena Marchetti">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h15A1.5 1.5 0 0 1 21 6.5v11A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5zM5 7.6V8l7 4.4L19 8v-.4l-7 4.4z"/></svg>
<span>[email protected]</span>
</a>
</div>
</div>
</div>
<button class="star is-on" type="button" aria-pressed="true" aria-label="Toggle priority for Elena Marchetti">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2.5l2.9 5.9 6.5.95-4.7 4.58 1.1 6.47L12 17.9l-5.8 3.05 1.1-6.47-4.7-4.58 6.5-.95z"/></svg>
</button>
</div>
<div class="lead__facts">
<span class="chip chip--brass">Source · Referral</span>
<span class="chip">Budget · $1.2M–$1.5M</span>
<span class="chip">Area · North Loop</span>
</div>
<div class="lead__meta">
<button class="pill" type="button" data-action="status" aria-label="Cycle status">
<span class="pill__dot"></span>
<span class="pill__text">New</span>
</button>
<span class="activity">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3a9 9 0 1 0 9 9 9 9 0 0 0-9-9zm.9 4h-1.6v5.2l4.3 2.6.8-1.4-3.5-2.1z"/></svg>
Added 12 min ago
</span>
</div>
<div class="notes" data-notes hidden></div>
<div class="lead__actions">
<a class="act" href="tel:+15125550148"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 10.8a15.5 15.5 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.5.56 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .56 3.5 1 1 0 0 1-.24 1z"/></svg>Call</a>
<a class="act" href="mailto:[email protected]"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h15A1.5 1.5 0 0 1 21 6.5v11A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5zM5 7.6V8l7 4.4L19 8v-.4l-7 4.4z"/></svg>Email</a>
<button class="act act--ghost" type="button" data-action="note"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 3h14a2 2 0 0 1 2 2v9.2L15.2 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm9 16v-3a1 1 0 0 1 1-1h3z"/></svg>Add note</button>
</div>
</div>
</article>
<!-- Lead 2 -->
<article class="lead" data-status="contacted" data-priority="false" tabindex="-1">
<div class="lead__media" aria-hidden="true" data-shot="b">
<span class="lead__shot-label">Cedar Row Bungalow</span>
</div>
<div class="lead__body">
<div class="lead__top">
<div class="lead__who">
<span class="avatar" data-tone="2" aria-hidden="true">DO</span>
<div class="lead__id">
<h2 class="lead__name">Darius Okonkwo</h2>
<div class="lead__contact">
<a class="contact" href="tel:+15125550207" aria-label="Call Darius Okonkwo">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 10.8a15.5 15.5 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.5.56 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .56 3.5 1 1 0 0 1-.24 1z"/></svg>
<span>(512) 555-0207</span>
</a>
<a class="contact" href="mailto:[email protected]" aria-label="Email Darius Okonkwo">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h15A1.5 1.5 0 0 1 21 6.5v11A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5zM5 7.6V8l7 4.4L19 8v-.4l-7 4.4z"/></svg>
<span>[email protected]</span>
</a>
</div>
</div>
</div>
<button class="star" type="button" aria-pressed="false" aria-label="Toggle priority for Darius Okonkwo">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2.5l2.9 5.9 6.5.95-4.7 4.58 1.1 6.47L12 17.9l-5.8 3.05 1.1-6.47-4.7-4.58 6.5-.95z"/></svg>
</button>
</div>
<div class="lead__facts">
<span class="chip chip--brass">Source · Zillow</span>
<span class="chip">Budget · $640K–$780K</span>
<span class="chip">Area · Cedar Row</span>
</div>
<div class="lead__meta">
<button class="pill" type="button" data-action="status" aria-label="Cycle status">
<span class="pill__dot"></span>
<span class="pill__text">Contacted</span>
</button>
<span class="activity">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3a9 9 0 1 0 9 9 9 9 0 0 0-9-9zm.9 4h-1.6v5.2l4.3 2.6.8-1.4-3.5-2.1z"/></svg>
Replied 2 hrs ago
</span>
</div>
<div class="notes" data-notes hidden></div>
<div class="lead__actions">
<a class="act" href="tel:+15125550207"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 10.8a15.5 15.5 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.5.56 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .56 3.5 1 1 0 0 1-.24 1z"/></svg>Call</a>
<a class="act" href="mailto:[email protected]"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h15A1.5 1.5 0 0 1 21 6.5v11A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5zM5 7.6V8l7 4.4L19 8v-.4l-7 4.4z"/></svg>Email</a>
<button class="act act--ghost" type="button" data-action="note"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 3h14a2 2 0 0 1 2 2v9.2L15.2 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm9 16v-3a1 1 0 0 1 1-1h3z"/></svg>Add note</button>
</div>
</div>
</article>
<!-- Lead 3 -->
<article class="lead" data-status="touring" data-priority="false" tabindex="-1">
<div class="lead__media" aria-hidden="true" data-shot="c">
<span class="lead__shot-label">Marlowe Heights Loft</span>
</div>
<div class="lead__body">
<div class="lead__top">
<div class="lead__who">
<span class="avatar" data-tone="3" aria-hidden="true">PV</span>
<div class="lead__id">
<h2 class="lead__name">Priya Venkat</h2>
<div class="lead__contact">
<a class="contact" href="tel:+15125550319" aria-label="Call Priya Venkat">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 10.8a15.5 15.5 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.5.56 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .56 3.5 1 1 0 0 1-.24 1z"/></svg>
<span>(512) 555-0319</span>
</a>
<a class="contact" href="mailto:[email protected]" aria-label="Email Priya Venkat">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h15A1.5 1.5 0 0 1 21 6.5v11A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5zM5 7.6V8l7 4.4L19 8v-.4l-7 4.4z"/></svg>
<span>[email protected]</span>
</a>
</div>
</div>
</div>
<button class="star is-on" type="button" aria-pressed="true" aria-label="Toggle priority for Priya Venkat">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2.5l2.9 5.9 6.5.95-4.7 4.58 1.1 6.47L12 17.9l-5.8 3.05 1.1-6.47-4.7-4.58 6.5-.95z"/></svg>
</button>
</div>
<div class="lead__facts">
<span class="chip chip--brass">Source · Open House</span>
<span class="chip">Budget · $890K–$1.1M</span>
<span class="chip">Area · Marlowe Heights</span>
</div>
<div class="lead__meta">
<button class="pill" type="button" data-action="status" aria-label="Cycle status">
<span class="pill__dot"></span>
<span class="pill__text">Touring</span>
</button>
<span class="activity">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3a9 9 0 1 0 9 9 9 9 0 0 0-9-9zm.9 4h-1.6v5.2l4.3 2.6.8-1.4-3.5-2.1z"/></svg>
Toured yesterday
</span>
</div>
<div class="notes" data-notes hidden>
<div class="note"><span class="note__time">Mon · 9:40 AM</span>Loved the south-facing windows. Wants a second viewing with her partner before the weekend.</div>
</div>
<div class="lead__actions">
<a class="act" href="tel:+15125550319"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 10.8a15.5 15.5 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.5.56 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .56 3.5 1 1 0 0 1-.24 1z"/></svg>Call</a>
<a class="act" href="mailto:[email protected]"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h15A1.5 1.5 0 0 1 21 6.5v11A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5zM5 7.6V8l7 4.4L19 8v-.4l-7 4.4z"/></svg>Email</a>
<button class="act act--ghost" type="button" data-action="note"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 3h14a2 2 0 0 1 2 2v9.2L15.2 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm9 16v-3a1 1 0 0 1 1-1h3z"/></svg>Add note</button>
</div>
</div>
</article>
<!-- Lead 4 -->
<article class="lead" data-status="offer" data-priority="true" tabindex="-1">
<div class="lead__media" aria-hidden="true" data-shot="d">
<span class="lead__shot-label">Harbor Mews Townhome</span>
</div>
<div class="lead__body">
<div class="lead__top">
<div class="lead__who">
<span class="avatar" data-tone="4" aria-hidden="true">RS</span>
<div class="lead__id">
<h2 class="lead__name">Rosa & Sam Whitlock</h2>
<div class="lead__contact">
<a class="contact" href="tel:+15125550462" aria-label="Call Rosa and Sam Whitlock">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 10.8a15.5 15.5 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.5.56 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .56 3.5 1 1 0 0 1-.24 1z"/></svg>
<span>(512) 555-0462</span>
</a>
<a class="contact" href="mailto:[email protected]" aria-label="Email Rosa and Sam Whitlock">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h15A1.5 1.5 0 0 1 21 6.5v11A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5zM5 7.6V8l7 4.4L19 8v-.4l-7 4.4z"/></svg>
<span>[email protected]</span>
</a>
</div>
</div>
</div>
<button class="star is-on" type="button" aria-pressed="true" aria-label="Toggle priority for Rosa and Sam Whitlock">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2.5l2.9 5.9 6.5.95-4.7 4.58 1.1 6.47L12 17.9l-5.8 3.05 1.1-6.47-4.7-4.58 6.5-.95z"/></svg>
</button>
</div>
<div class="lead__facts">
<span class="chip chip--brass">Source · Past Client</span>
<span class="chip">Budget · $1.6M–$1.9M</span>
<span class="chip">Area · Harbor Mews</span>
</div>
<div class="lead__meta">
<button class="pill" type="button" data-action="status" aria-label="Cycle status">
<span class="pill__dot"></span>
<span class="pill__text">Offer</span>
</button>
<span class="activity">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3a9 9 0 1 0 9 9 9 9 0 0 0-9-9zm.9 4h-1.6v5.2l4.3 2.6.8-1.4-3.5-2.1z"/></svg>
Offer sent 40 min ago
</span>
</div>
<div class="notes" data-notes hidden>
<div class="note"><span class="note__time">Today · 8:05 AM</span>Submitted at $1.74M, 18-day close. Awaiting seller counter — follow up by 5 PM.</div>
</div>
<div class="lead__actions">
<a class="act" href="tel:+15125550462"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 10.8a15.5 15.5 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.5.56 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .56 3.5 1 1 0 0 1-.24 1z"/></svg>Call</a>
<a class="act" href="mailto:[email protected]"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h15A1.5 1.5 0 0 1 21 6.5v11A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5zM5 7.6V8l7 4.4L19 8v-.4l-7 4.4z"/></svg>Email</a>
<button class="act act--ghost" type="button" data-action="note"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 3h14a2 2 0 0 1 2 2v9.2L15.2 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm9 16v-3a1 1 0 0 1 1-1h3z"/></svg>Add note</button>
</div>
</div>
</article>
</section>
</main>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Lead Card
A polished buyer-lead card for a real-estate CRM, presented as a stacked column of four prospects moving through the pipeline. Each card pairs an initials avatar and a serif name with one-tap phone and email contacts, a source tag, and chips for budget range and desired area. A colour-coded status pill, a brass star for priority, and a relative last-activity timestamp give an agent the full picture at a glance, with a faux architectural “listing photo” — rendered entirely in CSS gradients — anchoring the top of every card.
The interface is genuinely interactive. Tapping the status pill cycles a lead through New → Contacted → Touring → Offer, recolouring the pill and the card’s left accent rail in sync. The star toggles priority with a springy pop, and the “Add note” action reveals an inline composer that stamps each saved note with the current day and time. Every meaningful change surfaces a brief toast for feedback.
It is built from semantic, accessible markup — aria-pressed on toggles, labelled controls,
visible keyboard focus, and AA-contrast text — and ships as plain HTML, CSS, and vanilla
JavaScript with no frameworks or build step. The layout stays comfortable down to roughly
360px wide via a dedicated mobile breakpoint, and honours prefers-reduced-motion.
Illustrative UI only — sample listings and data are fictional; not a real real-estate service.