Vet — Pet Detail / Record
A single-pet medical record page with a profile header showing species, breed, age, weight and microchip, an allergy alert banner, vital stat tiles, a tabbed Overview, Visits, Vaccines and Meds switcher, a CSS weight trend chart and an upcoming-care reminder card.
MCP
Code
:root {
--teal: #179c8e;
--teal-d: #0f7f73;
--teal-50: #e6f5f2;
--coral: #ff8a5c;
--ink: #173a36;
--muted: #6b827e;
--bg: #f2f8f6;
--white: #ffffff;
--line: #dcebe7;
--warn: #e8a33d;
--over: #e3604f;
--radius: 20px;
--radius-sm: 12px;
--shadow: 0 10px 30px rgba(15, 127, 115, 0.08);
--font: 'Inter', system-ui, -apple-system, sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font);
background: var(--bg);
color: var(--ink);
line-height: 1.5;
padding: 28px 16px;
-webkit-font-smoothing: antialiased;
}
.record {
max-width: 920px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 18px;
}
/* Buttons */
.btn-primary,
.btn-ghost {
font-family: inherit;
font-weight: 600;
border-radius: 999px;
cursor: pointer;
border: none;
transition: transform 0.12s ease, background 0.12s ease, box-shadow 0.12s ease;
font-size: 0.92rem;
padding: 11px 18px;
}
.btn-primary { background: var(--teal); color: #fff; }
.btn-primary:hover { background: var(--teal-d); transform: translateY(-1px); }
.btn-ghost { background: var(--teal-50); color: var(--teal-d); }
.btn-ghost:hover { background: #d6efe9; }
.btn-sm { padding: 8px 14px; font-size: 0.85rem; }
button:focus-visible { outline: 3px solid rgba(23, 156, 142, 0.4); outline-offset: 2px; }
/* Profile header */
.profile {
background: var(--white);
border-radius: var(--radius);
box-shadow: var(--shadow);
padding: 22px;
display: flex;
align-items: flex-start;
gap: 18px;
}
.avatar {
flex: none;
width: 76px;
height: 76px;
border-radius: 24px;
background: linear-gradient(140deg, var(--teal-50), #d2efe8);
display: grid;
place-items: center;
font-size: 2.2rem;
box-shadow: inset 0 0 0 2px rgba(23, 156, 142, 0.15);
}
.profile-main { flex: 1; min-width: 0; }
.profile-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.profile-top h1 { font-size: 1.7rem; letter-spacing: -0.02em; }
.profile-sub { color: var(--muted); margin: 4px 0 14px; font-size: 0.95rem; }
.profile-facts {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 12px 18px;
}
.profile-facts dt { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.profile-facts dd { font-weight: 600; font-size: 0.92rem; margin-top: 2px; }
/* Badges */
.badge {
font-size: 0.72rem;
font-weight: 600;
padding: 4px 10px;
border-radius: 999px;
white-space: nowrap;
}
.badge-soft { background: var(--teal-50); color: var(--teal-d); }
.badge-ok { background: #def3ee; color: var(--teal-d); }
.badge-warn { background: #fdf0db; color: #a96b18; }
.badge-over { background: #fde3df; color: #b23a2c; }
/* Alert */
.alert {
display: flex;
gap: 12px;
align-items: flex-start;
background: #fff1ea;
border: 1px solid #ffd5c2;
border-left: 5px solid var(--coral);
border-radius: var(--radius-sm);
padding: 14px 16px;
}
.alert-icon { font-size: 1.2rem; line-height: 1.3; }
.alert strong { display: block; color: #b8462a; font-size: 0.95rem; }
.alert p { color: #8c5340; font-size: 0.88rem; margin-top: 2px; }
/* Vitals */
.vitals {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 14px;
}
.vital {
background: var(--white);
border-radius: var(--radius-sm);
box-shadow: var(--shadow);
padding: 16px;
display: flex;
flex-direction: column;
gap: 6px;
}
.vital-label { font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.vital-value { font-size: 1.6rem; font-weight: 700; letter-spacing: -0.02em; }
.vital-value-sm { font-size: 1.25rem; }
.vital-unit { font-size: 0.8rem; font-weight: 600; color: var(--muted); margin-left: 3px; }
.trend { font-size: 0.74rem; font-weight: 600; }
.trend-up { color: var(--teal-d); }
.trend-ok { color: var(--teal-d); }
.trend-soft { color: var(--muted); }
/* Grid */
.grid {
display: grid;
grid-template-columns: 1fr 280px;
gap: 18px;
align-items: start;
}
.panel, .sidecard {
background: var(--white);
border-radius: var(--radius);
box-shadow: var(--shadow);
padding: 20px;
}
.panel-h { font-size: 1.05rem; margin-bottom: 4px; }
.panel-note { font-size: 0.82rem; color: var(--muted); margin-bottom: 14px; }
/* Tabs */
.tabs {
display: flex;
gap: 4px;
background: var(--bg);
padding: 5px;
border-radius: 999px;
margin-bottom: 18px;
overflow-x: auto;
}
.tab {
flex: 1;
font-family: inherit;
font-size: 0.85rem;
font-weight: 600;
color: var(--muted);
background: transparent;
border: none;
border-radius: 999px;
padding: 9px 12px;
cursor: pointer;
white-space: nowrap;
transition: background 0.15s ease, color 0.15s ease;
}
.tab:hover { color: var(--ink); }
.tab.is-active { background: var(--white); color: var(--teal-d); box-shadow: 0 2px 6px rgba(15, 127, 115, 0.12); }
.tab-count {
display: inline-block;
background: var(--teal-50);
color: var(--teal-d);
border-radius: 999px;
font-size: 0.7rem;
padding: 1px 7px;
margin-left: 3px;
}
.tab.is-active .tab-count { background: var(--teal-50); }
.tabpanel { animation: fade 0.2s ease; }
.tabpanel[hidden] { display: none; }
@keyframes fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
/* Chart */
.chart {
display: flex;
align-items: flex-end;
gap: 10px;
height: 140px;
padding: 10px 4px 0;
border-bottom: 2px solid var(--line);
margin-bottom: 18px;
}
.bar {
flex: 1;
height: 100%;
display: flex;
align-items: flex-end;
position: relative;
cursor: pointer;
}
.bar-fill {
width: 100%;
height: var(--h);
background: linear-gradient(180deg, #5fc4b8, var(--teal));
border-radius: 8px 8px 0 0;
transition: filter 0.15s ease;
}
.bar.is-current .bar-fill { background: linear-gradient(180deg, #ffb094, var(--coral)); }
.bar:hover .bar-fill { filter: brightness(1.08); }
.bar::after {
content: attr(data-label);
position: absolute;
bottom: calc(var(--h) + 8px);
left: 50%;
transform: translateX(-50%) translateY(4px);
background: var(--ink);
color: #fff;
font-size: 0.72rem;
font-weight: 600;
padding: 4px 8px;
border-radius: 6px;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.15s ease, transform 0.15s ease;
z-index: 2;
}
.bar:hover::after, .bar:focus-within::after { opacity: 1; transform: translateX(-50%) translateY(0); }
/* Quick list */
.quick-list { list-style: none; display: flex; flex-direction: column; gap: 10px; }
.quick-list li { display: flex; align-items: center; gap: 10px; font-size: 0.9rem; }
.dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.dot-teal { background: var(--teal); }
.dot-coral { background: var(--coral); }
/* Timeline */
.timeline { list-style: none; display: flex; flex-direction: column; gap: 16px; }
.timeline li { display: flex; gap: 14px; }
.tl-date {
flex: none;
width: 58px;
text-align: center;
background: var(--teal-50);
border-radius: var(--radius-sm);
padding: 8px 4px;
}
.tl-date strong { display: block; color: var(--teal-d); font-size: 0.85rem; }
.tl-date span { font-size: 0.7rem; color: var(--muted); }
.tl-body { flex: 1; }
.tl-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 3px; }
.tl-top h3 { font-size: 0.95rem; }
.tl-body p { font-size: 0.86rem; color: var(--muted); }
/* Vaccine table */
.vtable { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.vtable th, .vtable td { text-align: left; padding: 11px 8px; border-bottom: 1px solid var(--line); }
.vtable thead th { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); font-weight: 600; }
.vtable tbody th { font-weight: 600; }
.vtable td:last-child, .vtable th:last-child { text-align: right; }
/* Meds */
.med-list { list-style: none; display: flex; flex-direction: column; gap: 12px; }
.med-list li { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 14px; }
.med-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 4px; }
.med-top h3 { font-size: 0.95rem; }
.med-list p { font-size: 0.85rem; color: var(--muted); }
/* Care card */
.care {
position: relative;
background: linear-gradient(150deg, var(--teal-50), #d8f0eb);
border-radius: var(--radius-sm);
padding: 16px;
}
.care-dismiss {
position: absolute;
top: 8px;
right: 10px;
background: transparent;
border: none;
font-size: 1.3rem;
line-height: 1;
color: var(--muted);
cursor: pointer;
border-radius: 8px;
width: 28px;
height: 28px;
}
.care-dismiss:hover { color: var(--ink); background: rgba(255,255,255,0.5); }
.care-tag { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--teal-d); }
.care h3 { font-size: 1.05rem; margin: 4px 0 8px; }
.care-when { font-size: 0.88rem; font-weight: 600; }
.care-with { font-size: 0.82rem; color: var(--muted); margin-bottom: 14px; }
.care-actions { display: flex; gap: 8px; }
.care-empty { font-size: 0.9rem; color: var(--muted); text-align: center; padding: 18px 0; }
/* Responsive */
@media (max-width: 760px) {
.grid { grid-template-columns: 1fr; }
.vitals { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
body { padding: 16px 10px; }
.profile { flex-direction: column; }
.profile > .btn-primary { width: 100%; }
.vitals { grid-template-columns: 1fr 1fr; }
.profile-top h1 { font-size: 1.45rem; }
.tabs { gap: 2px; }
.tab { padding: 9px 8px; font-size: 0.8rem; }
.chart { gap: 6px; }
}// Vet pet detail — tabs, chart keyboard access, reminder dismiss. Vanilla JS, no libs.
(function () {
'use strict';
// --- Tabbed sections ---
var tabs = Array.prototype.slice.call(document.querySelectorAll('.tab'));
var panels = Array.prototype.slice.call(document.querySelectorAll('.tabpanel'));
function activate(tab) {
tabs.forEach(function (t) {
var on = t === tab;
t.classList.toggle('is-active', on);
t.setAttribute('aria-selected', on ? 'true' : 'false');
});
var targetId = tab.getAttribute('aria-controls');
panels.forEach(function (p) {
var show = p.id === targetId;
p.hidden = !show;
p.classList.toggle('is-active', show);
});
}
tabs.forEach(function (tab, i) {
tab.addEventListener('click', function () { activate(tab); });
// Arrow-key navigation between tabs (WAI-ARIA pattern).
tab.addEventListener('keydown', function (e) {
var next = null;
if (e.key === 'ArrowRight') next = tabs[(i + 1) % tabs.length];
else if (e.key === 'ArrowLeft') next = tabs[(i - 1 + tabs.length) % tabs.length];
else if (e.key === 'Home') next = tabs[0];
else if (e.key === 'End') next = tabs[tabs.length - 1];
if (next) {
e.preventDefault();
activate(next);
next.focus();
}
});
});
// --- Chart bars: make focusable so the CSS tooltip works via keyboard ---
Array.prototype.forEach.call(document.querySelectorAll('.bar'), function (bar) {
bar.setAttribute('tabindex', '0');
bar.setAttribute('role', 'img');
var label = bar.getAttribute('data-label');
if (label) bar.setAttribute('aria-label', label);
});
// --- Upcoming-care reminder dismiss ---
var care = document.getElementById('care-card');
var empty = document.getElementById('care-empty');
var dismiss = care ? care.querySelector('.care-dismiss') : null;
if (dismiss) {
dismiss.addEventListener('click', function () {
care.hidden = true;
if (empty) empty.hidden = false;
});
}
// Confirm button gives quick visual feedback.
var confirmBtn = care ? care.querySelector('.btn-primary') : null;
if (confirmBtn) {
confirmBtn.addEventListener('click', function () {
confirmBtn.textContent = 'Confirmed ✓';
confirmBtn.disabled = true;
confirmBtn.style.opacity = '0.75';
});
}
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pet Record — Biscuit</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=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="record" aria-labelledby="pet-name">
<!-- Header -->
<header class="profile">
<div class="avatar" aria-hidden="true">🐾</div>
<div class="profile-main">
<div class="profile-top">
<h1 id="pet-name">Biscuit</h1>
<span class="badge badge-soft">Active patient</span>
</div>
<p class="profile-sub">Golden Retriever · Dog · Male, neutered</p>
<dl class="profile-facts">
<div><dt>Age</dt><dd>4 yrs 2 mo</dd></div>
<div><dt>Weight</dt><dd>31.4 kg</dd></div>
<div><dt>Microchip</dt><dd>985 1410 0027 3318</dd></div>
<div><dt>Owner</dt><dd>Marisol Vega</dd></div>
</dl>
</div>
<button class="btn-primary" type="button">+ New visit</button>
</header>
<!-- Allergy alert -->
<div class="alert" role="alert">
<span class="alert-icon" aria-hidden="true">⚠️</span>
<div>
<strong>Known allergies</strong>
<p>Penicillin (anaphylaxis), chicken protein. Avoid amoxicillin-based courses.</p>
</div>
</div>
<!-- Vital tiles -->
<section class="vitals" aria-label="Vital stats">
<div class="vital">
<span class="vital-label">Weight</span>
<span class="vital-value">31.4<span class="vital-unit">kg</span></span>
<span class="trend trend-up">▲ 0.6 kg</span>
</div>
<div class="vital">
<span class="vital-label">Temperature</span>
<span class="vital-value">38.5<span class="vital-unit">°C</span></span>
<span class="trend trend-ok">Normal</span>
</div>
<div class="vital">
<span class="vital-label">Heart rate</span>
<span class="vital-value">92<span class="vital-unit">bpm</span></span>
<span class="trend trend-ok">Normal</span>
</div>
<div class="vital">
<span class="vital-label">Next visit</span>
<span class="vital-value vital-value-sm">Jul 9</span>
<span class="trend trend-soft">In 17 days</span>
</div>
</section>
<div class="grid">
<!-- Tabs -->
<section class="panel">
<div class="tabs" role="tablist" aria-label="Pet record sections">
<button class="tab is-active" role="tab" aria-selected="true" aria-controls="tab-overview" id="t-overview" type="button">Overview</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="tab-visits" id="t-visits" type="button">Visits <span class="tab-count">6</span></button>
<button class="tab" role="tab" aria-selected="false" aria-controls="tab-vaccines" id="t-vaccines" type="button">Vaccines</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="tab-meds" id="t-meds" type="button">Meds <span class="tab-count">2</span></button>
</div>
<!-- Overview -->
<div class="tabpanel is-active" id="tab-overview" role="tabpanel" aria-labelledby="t-overview" tabindex="0">
<h2 class="panel-h">Weight trend</h2>
<p class="panel-note">Last 6 measurements · healthy range 29–33 kg</p>
<div class="chart" role="img" aria-label="Weight trend chart, rising from 29.8 to 31.4 kg over six visits">
<div class="bar" style="--h:62%" data-label="Jan · 29.8 kg"><span class="bar-fill"></span></div>
<div class="bar" style="--h:70%" data-label="Feb · 30.3 kg"><span class="bar-fill"></span></div>
<div class="bar" style="--h:66%" data-label="Mar · 30.0 kg"><span class="bar-fill"></span></div>
<div class="bar" style="--h:78%" data-label="Apr · 30.6 kg"><span class="bar-fill"></span></div>
<div class="bar" style="--h:84%" data-label="May · 30.8 kg"><span class="bar-fill"></span></div>
<div class="bar is-current" style="--h:100%" data-label="Jun · 31.4 kg"><span class="bar-fill"></span></div>
</div>
<ul class="quick-list">
<li><span class="dot dot-teal"></span> Last seen by Dr. Amara Okafor — wellness exam</li>
<li><span class="dot dot-coral"></span> Dental cleaning recommended within 3 months</li>
<li><span class="dot dot-teal"></span> Diet: Royal Canin Adult, 2 cups/day</li>
</ul>
</div>
<!-- Visits -->
<div class="tabpanel" id="tab-visits" role="tabpanel" aria-labelledby="t-visits" tabindex="0" hidden>
<h2 class="panel-h">Recent visits</h2>
<ol class="timeline">
<li>
<div class="tl-date"><strong>Jun 22</strong><span>2026</span></div>
<div class="tl-body">
<div class="tl-top"><h3>Wellness exam</h3><span class="badge badge-ok">Completed</span></div>
<p>Routine check. Weight up 0.6 kg, coat healthy. Dr. Amara Okafor.</p>
</div>
</li>
<li>
<div class="tl-date"><strong>Mar 14</strong><span>2026</span></div>
<div class="tl-body">
<div class="tl-top"><h3>Ear infection</h3><span class="badge badge-ok">Completed</span></div>
<p>Right ear otitis. Prescribed otic drops, 10-day course. Resolved.</p>
</div>
</li>
<li>
<div class="tl-date"><strong>Jan 08</strong><span>2026</span></div>
<div class="tl-body">
<div class="tl-top"><h3>Annual vaccines</h3><span class="badge badge-ok">Completed</span></div>
<p>DHPP + Rabies booster administered. No adverse reaction.</p>
</div>
</li>
</ol>
</div>
<!-- Vaccines -->
<div class="tabpanel" id="tab-vaccines" role="tabpanel" aria-labelledby="t-vaccines" tabindex="0" hidden>
<h2 class="panel-h">Vaccination status</h2>
<table class="vtable">
<thead><tr><th scope="col">Vaccine</th><th scope="col">Last given</th><th scope="col">Status</th></tr></thead>
<tbody>
<tr><th scope="row">Rabies</th><td>Jan 8, 2026</td><td><span class="badge badge-ok">Current</span></td></tr>
<tr><th scope="row">DHPP</th><td>Jan 8, 2026</td><td><span class="badge badge-ok">Current</span></td></tr>
<tr><th scope="row">Bordetella</th><td>Aug 2, 2025</td><td><span class="badge badge-warn">Due soon</span></td></tr>
<tr><th scope="row">Leptospirosis</th><td>Mar 4, 2025</td><td><span class="badge badge-over">Overdue</span></td></tr>
</tbody>
</table>
</div>
<!-- Meds -->
<div class="tabpanel" id="tab-meds" role="tabpanel" aria-labelledby="t-meds" tabindex="0" hidden>
<h2 class="panel-h">Active medications</h2>
<ul class="med-list">
<li>
<div class="med-top"><h3>Apoquel 16 mg</h3><span class="badge badge-soft">Active</span></div>
<p>1 tablet daily with food · for seasonal pruritus · refill by Jul 18</p>
</li>
<li>
<div class="med-top"><h3>Bravecto chew</h3><span class="badge badge-soft">Active</span></div>
<p>1 chew every 12 weeks · flea & tick · next dose Aug 30</p>
</li>
</ul>
</div>
</section>
<!-- Upcoming care -->
<aside class="sidecard" aria-label="Upcoming care">
<h2 class="panel-h">Upcoming care</h2>
<div class="care" id="care-card">
<button class="care-dismiss" type="button" aria-label="Dismiss reminder">×</button>
<span class="care-tag">Reminder</span>
<h3>Dental cleaning</h3>
<p class="care-when">📅 Jul 9, 2026 · 10:30 AM</p>
<p class="care-with">with Dr. Amara Okafor</p>
<div class="care-actions">
<button class="btn-primary btn-sm" type="button">Confirm</button>
<button class="btn-ghost btn-sm" type="button">Reschedule</button>
</div>
</div>
<p class="care-empty" id="care-empty" hidden>No upcoming reminders 🐶</p>
</aside>
</div>
</main>
<script src="script.js"></script>
</body>
</html>Pet Detail / Record
A warm, friendly veterinary record page for a single patient. The header pairs an avatar with the pet’s name, species, breed, age, weight and microchip, while a coral allergy banner surfaces known reactions at a glance. Vital tiles summarise weight, temperature, heart rate and next visit.
A tabbed control switches between Overview, Visits, Vaccines and Meds without leaving the page. Overview includes a compact weight trend rendered with pure CSS bars, Visits lists recent appointments with outcome notes, Vaccines shows due/current status badges, and Meds tracks active prescriptions. An upcoming-care card highlights the next reminder.
All tab switching, the weight-chart tooltip and the reminder dismiss are handled with vanilla JS — no libraries.
Illustrative UI only — not for real veterinary use.