Museum — Object Label / Wall Plaque
A curatorial object-label gallery rendering the classic museum tombstone — artist, life dates, italicized title, date, medium, dimensions, credit line, and accession number — across three registers: standard, extended interpretive, and a warmer kids version. A pill style switcher swaps every label in place, a mat toggle frames or unframes each artwork, and copy-to-clipboard plus single-label print affordances make the plaques feel like real gallery production tools.
MCP
Code
:root {
--paper: #f6f4ef;
--wall: #ffffff;
--charcoal: #1c1b19;
--ink: #2a2825;
--ink-2: #4a4640;
--muted: #8c857a;
--gold: #a98140;
--gold-d: #876631;
--gold-50: #f3ecdd;
--line: rgba(28, 27, 25, 0.12);
--line-2: rgba(28, 27, 25, 0.2);
--ok: #3f7d56;
--warn: #b8842c;
--danger: #b4493a;
--r-sm: 6px;
--r-md: 12px;
--r-lg: 18px;
--serif: "Cormorant Garamond", Georgia, serif;
--sans: "Inter", system-ui, -apple-system, sans-serif;
--shadow-1: 0 1px 2px rgba(28, 27, 25, 0.05), 0 6px 18px rgba(28, 27, 25, 0.06);
--shadow-2: 0 2px 6px rgba(28, 27, 25, 0.08), 0 18px 44px rgba(28, 27, 25, 0.1);
}
* {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
background: var(--paper);
color: var(--ink);
font-family: var(--sans);
font-size: 16px;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.frame {
max-width: 1080px;
margin: 0 auto;
padding: 56px 24px 72px;
}
/* ---------- masthead ---------- */
.masthead {
max-width: 680px;
}
.eyebrow {
margin: 0 0 14px;
font-size: 12px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--gold-d);
font-weight: 600;
}
.masthead h1 {
margin: 0 0 16px;
font-family: var(--serif);
font-weight: 600;
font-size: clamp(2.1rem, 5vw, 3.2rem);
line-height: 1.04;
letter-spacing: 0.005em;
color: var(--charcoal);
}
.lede {
margin: 0;
color: var(--ink-2);
font-size: 1.05rem;
max-width: 56ch;
}
/* ---------- controls ---------- */
.controls {
display: flex;
flex-wrap: wrap;
gap: 16px;
align-items: center;
justify-content: space-between;
margin: 36px 0 8px;
padding-bottom: 20px;
border-bottom: 1px solid var(--line);
}
.switcher {
display: inline-flex;
background: var(--wall);
border: 1px solid var(--line);
border-radius: 999px;
padding: 4px;
box-shadow: var(--shadow-1);
}
.seg {
appearance: none;
border: 0;
background: transparent;
color: var(--ink-2);
font-family: var(--sans);
font-size: 14px;
font-weight: 500;
letter-spacing: 0.01em;
padding: 8px 18px;
border-radius: 999px;
cursor: pointer;
transition: color 0.18s ease, background 0.18s ease;
}
.seg:hover {
color: var(--charcoal);
}
.seg.is-active {
background: var(--charcoal);
color: #fff;
box-shadow: 0 1px 3px rgba(28, 27, 25, 0.3);
}
.control-aside {
display: flex;
align-items: center;
gap: 18px;
}
.toggle {
display: inline-flex;
align-items: center;
gap: 9px;
font-size: 14px;
color: var(--ink-2);
cursor: pointer;
user-select: none;
}
.toggle input {
width: 16px;
height: 16px;
accent-color: var(--gold-d);
cursor: pointer;
}
.btn-ghost {
appearance: none;
background: transparent;
border: 1px solid var(--line-2);
border-radius: var(--r-sm);
color: var(--ink);
font-family: var(--sans);
font-size: 13px;
font-weight: 500;
padding: 8px 14px;
cursor: pointer;
transition: border-color 0.18s ease, background 0.18s ease, color 0.18s ease;
}
.btn-ghost:hover {
border-color: var(--gold);
color: var(--gold-d);
background: var(--gold-50);
}
/* ---------- wall / grid ---------- */
.wall {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 28px;
margin: 36px 0 0;
}
.piece {
background: var(--wall);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 22px;
box-shadow: var(--shadow-1);
transition: box-shadow 0.22s ease, transform 0.22s ease;
}
.piece:hover {
box-shadow: var(--shadow-2);
transform: translateY(-2px);
}
/* artwork mat + image */
.art {
position: relative;
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 22px;
transition: padding 0.25s ease, background 0.25s ease;
}
.art.no-mat {
padding: 0;
background: transparent;
border-color: transparent;
}
.art-canvas {
aspect-ratio: 4 / 3;
border-radius: var(--r-sm);
border: 1px solid rgba(28, 27, 25, 0.18);
box-shadow: inset 0 0 0 6px rgba(255, 255, 255, 0.55),
0 8px 22px rgba(28, 27, 25, 0.14);
overflow: hidden;
}
.art-canvas svg {
display: block;
width: 100%;
height: 100%;
}
.medium-tag {
position: absolute;
top: 14px;
right: 14px;
font-size: 10px;
letter-spacing: 0.12em;
text-transform: uppercase;
font-weight: 600;
color: var(--gold-d);
background: var(--gold-50);
border: 1px solid rgba(169, 129, 64, 0.3);
border-radius: 999px;
padding: 4px 10px;
}
/* ---------- label ---------- */
.label {
margin-top: 22px;
border-top: 1px solid var(--line);
padding-top: 18px;
}
.label .artist {
font-family: var(--serif);
font-weight: 700;
font-size: 1.35rem;
line-height: 1.15;
color: var(--charcoal);
margin: 0;
}
.label .life {
font-size: 12.5px;
color: var(--muted);
margin: 2px 0 12px;
}
.label .work {
margin: 0;
font-size: 1.02rem;
color: var(--ink);
}
.label .work em {
font-family: var(--serif);
font-style: italic;
font-weight: 600;
font-size: 1.18rem;
}
.label .work .year {
color: var(--ink-2);
}
.label .specs {
margin: 12px 0 0;
font-size: 14px;
color: var(--ink-2);
line-height: 1.65;
}
.label .specs .medium {
font-style: italic;
}
.label .credit {
margin: 14px 0 0;
font-size: 12.5px;
color: var(--muted);
line-height: 1.55;
}
.label .accession {
display: inline-block;
margin-top: 10px;
font-family: var(--sans);
font-size: 11px;
letter-spacing: 0.08em;
color: var(--gold-d);
font-weight: 600;
}
/* extended interpretive panel */
.interp {
margin: 16px 0 0;
font-size: 14.5px;
color: var(--ink-2);
line-height: 1.62;
border-left: 2px solid var(--gold);
padding-left: 14px;
}
/* kids voice */
.piece.is-kids .label .artist,
.piece.is-kids .interp {
/* keep serif headings; kids text just reads warmer via interp */
}
.kids-q {
margin: 16px 0 0;
background: var(--gold-50);
border: 1px dashed rgba(169, 129, 64, 0.4);
border-radius: var(--r-md);
padding: 14px 16px;
font-size: 14.5px;
color: var(--ink);
}
.kids-q strong {
display: block;
font-family: var(--serif);
font-weight: 700;
font-size: 1.05rem;
color: var(--gold-d);
margin-bottom: 4px;
}
/* badges row */
.tags {
display: flex;
flex-wrap: wrap;
gap: 7px;
margin: 16px 0 0;
}
.tag {
font-size: 11px;
letter-spacing: 0.04em;
color: var(--ink-2);
background: var(--paper);
border: 1px solid var(--line);
border-radius: 999px;
padding: 4px 11px;
}
.tag.on-view {
color: var(--ok);
border-color: rgba(63, 125, 86, 0.3);
background: rgba(63, 125, 86, 0.08);
}
.tag.fragile {
color: var(--warn);
border-color: rgba(184, 132, 44, 0.3);
background: rgba(184, 132, 44, 0.08);
}
/* actions */
.actions {
display: flex;
gap: 8px;
margin: 18px 0 0;
padding-top: 16px;
border-top: 1px dashed var(--line);
}
.act {
appearance: none;
flex: 1;
border: 1px solid var(--line-2);
background: var(--wall);
border-radius: var(--r-sm);
color: var(--ink);
font-family: var(--sans);
font-size: 12.5px;
font-weight: 500;
padding: 9px 10px;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 7px;
transition: border-color 0.16s ease, background 0.16s ease, color 0.16s ease;
}
.act:hover {
border-color: var(--gold);
color: var(--gold-d);
background: var(--gold-50);
}
.act svg {
width: 14px;
height: 14px;
}
/* focus visibility */
:where(button, input, a):focus-visible {
outline: 2px solid var(--gold-d);
outline-offset: 2px;
border-radius: var(--r-sm);
}
/* ---------- colophon ---------- */
.colophon {
display: flex;
align-items: center;
gap: 10px;
margin-top: 48px;
padding-top: 22px;
border-top: 1px solid var(--line);
font-size: 12.5px;
color: var(--muted);
}
.colophon .dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--gold);
flex: none;
}
.colophon strong {
color: var(--ink-2);
font-weight: 600;
}
/* ---------- toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 28px;
transform: translate(-50%, 16px);
background: var(--charcoal);
color: #fff;
font-size: 13.5px;
font-weight: 500;
padding: 11px 18px;
border-radius: 999px;
box-shadow: var(--shadow-2);
opacity: 0;
pointer-events: none;
transition: opacity 0.22s ease, transform 0.22s ease;
z-index: 50;
}
.toast.show {
opacity: 1;
transform: translate(-50%, 0);
}
/* ---------- responsive ---------- */
@media (max-width: 760px) {
.wall {
grid-template-columns: 1fr;
}
}
@media (max-width: 520px) {
.frame {
padding: 36px 16px 56px;
}
.controls {
align-items: flex-start;
flex-direction: column;
}
.switcher {
width: 100%;
}
.seg {
flex: 1;
padding: 9px 8px;
text-align: center;
}
.control-aside {
width: 100%;
justify-content: space-between;
}
.piece {
padding: 16px;
}
.art {
padding: 14px;
}
.label .artist {
font-size: 1.22rem;
}
}
/* ---------- print ---------- */
@media print {
body {
background: #fff;
}
.controls,
.colophon,
.actions,
.masthead .lede,
.toast,
.medium-tag {
display: none !important;
}
.frame {
padding: 0;
}
.wall {
grid-template-columns: 1fr;
gap: 0;
}
.piece {
box-shadow: none;
border: none;
page-break-inside: avoid;
transform: none;
padding: 0 0 24px;
}
.piece.print-hide {
display: none !important;
}
}/* Object Label / Wall Plaque — demo data + interactions (vanilla JS) */
(function () {
"use strict";
/* ---------------- demo collection ---------------- */
var WORKS = [
{
id: "MC.1971.214",
artist: "Esme Caldarone",
life: "Italian, 1889–1974",
title: "The Tidewater Letters",
year: "1937",
medium: "Oil and gold leaf on linen",
dims: "146 × 112 cm (57 1/2 × 44 1/8 in.)",
credit: "Gift of the Lindqvist Family Foundation, 1971",
kind: "Painting",
grad: "linear-gradient(150deg,#c9a14a 0%,#9d6b3f 48%,#3b2f2a 100%)",
shape: "circle",
tags: ["On view", "Gallery 14"],
onView: true,
interp:
"Caldarone painted this estuary scene from memory after fleeing the coast of her childhood. The flecks of gold leaf — applied last, against the artist's usual practice — catch raking gallery light, so the water appears to shift as visitors move past.",
kidsTitle: "Can you find the shiny water?",
kids:
"This painting glows because the artist pressed tiny pieces of real gold onto it. Walk side to side and watch the river sparkle. What sounds do you think this place would make?"
},
{
id: "MC.1989.007",
artist: "Joren Vasco",
life: "Brazilian, b. 1952",
title: "Counterweight (No. 3)",
year: "1988",
medium: "Welded steel and patinated bronze",
dims: "204 × 90 × 90 cm (80 5/16 × 35 7/16 × 35 7/16 in.)",
credit: "Museum purchase with funds from the Acquisitions Circle, 1989",
kind: "Sculpture",
grad: "linear-gradient(135deg,#6f7479 0%,#3c4044 55%,#1c1b19 100%)",
shape: "bars",
tags: ["On view", "Fragile"],
onView: true,
fragile: true,
interp:
"Three cantilevered arms hold one another in tension; remove any single member and the whole composition would collapse. Vasco, trained as a bridge engineer, described the piece as 'a structure arguing with itself.'",
kidsTitle: "How does it stand up?",
kids:
"Each metal arm is leaning on the others — like friends holding hands in a circle so nobody falls. The artist used to build real bridges! Which arm do you think is working hardest?"
},
{
id: "MC.2004.118",
artist: "Hana Okuýama",
life: "Japanese, b. 1968",
title: "Field Notes, Winter",
year: "2002",
medium: "Sumi ink and mineral pigment on kozo paper",
dims: "Each sheet 38 × 27 cm; installation variable",
credit: "Promised gift of the artist in honor of Dr. Imelda Roan",
kind: "Works on Paper",
grad: "linear-gradient(160deg,#eef0f2 0%,#cdd2d6 50%,#8c9398 100%)",
shape: "grid",
tags: ["On view", "Light sensitive"],
onView: true,
fragile: true,
interp:
"Okuýama records a single hillside across forty winter mornings. Because the pigments fade under prolonged exposure, the museum rotates which sheets are shown — no visitor sees the same field twice.",
kidsTitle: "Forty cold mornings",
kids:
"The artist drew the same hill again and again on snowy days. We can only show a few drawings at a time so the colors stay bright. If you drew outside your window every morning, what would change?"
},
{
id: "MC.1958.402",
artist: "Unknown",
life: "Workshop of the Lower Vey, active c. 1610–1650",
title: "Ewer with Heron Frieze",
year: "c. 1630",
medium: "Tin-glazed earthenware (faience)",
dims: "H. 34.3 cm (13 1/2 in.)",
credit: "Bequest of Cornelia P. Marsh, 1958",
kind: "Decorative Arts",
grad: "linear-gradient(145deg,#e7e2d4 0%,#b9bcd0 50%,#5b6c86 100%)",
shape: "vessel",
tags: ["In storage"],
onView: false,
interp:
"The herons circling this ewer's shoulder were a workshop signature, repeated across surviving pieces with slight variation. Conservators recently identified a hidden potter's mark beneath the foot, suggesting an apprentice's hand.",
kidsTitle: "Count the birds",
kids:
"This jug is almost 400 years old! Tall birds called herons march around the top. Long ago a young helper may have painted them. How many birds can you count going all the way around?"
}
];
/* ---------------- placeholder artwork (inline SVG) ---------------- */
function artSvg(w) {
var s = '<svg viewBox="0 0 240 180" role="img" aria-label="' +
esc(w.title) + ' by ' + esc(w.artist) + '" preserveAspectRatio="xMidYMid slice">';
s += '<defs><linearGradient id="g-' + w.id.replace(/\W/g, "") +
'" x1="0" y1="0" x2="1" y2="1">';
s += '<stop offset="0" stop-color="' + gradStop(w.grad, 0) + '"/>';
s += '<stop offset="1" stop-color="' + gradStop(w.grad, 1) + '"/>';
s += "</linearGradient></defs>";
s += '<rect width="240" height="180" fill="url(#g-' + w.id.replace(/\W/g, "") + ')"/>';
if (w.shape === "circle") {
s += '<circle cx="120" cy="92" r="52" fill="rgba(255,255,255,0.16)"/>';
s += '<path d="M30 140 Q120 110 210 140" stroke="rgba(255,255,255,0.5)" stroke-width="3" fill="none"/>';
} else if (w.shape === "bars") {
s += '<rect x="96" y="30" width="14" height="120" fill="rgba(255,255,255,0.28)"/>';
s += '<rect x="118" y="56" width="14" height="94" fill="rgba(255,255,255,0.16)"/>';
s += '<rect x="74" y="70" width="14" height="80" fill="rgba(0,0,0,0.18)"/>';
} else if (w.shape === "grid") {
for (var gy = 0; gy < 3; gy++)
for (var gx = 0; gx < 4; gx++)
s += '<rect x="' + (28 + gx * 48) + '" y="' + (24 + gy * 48) +
'" width="36" height="36" rx="3" fill="rgba(28,27,25,' +
(0.06 + ((gx + gy) % 3) * 0.07).toFixed(2) + ')"/>';
} else if (w.shape === "vessel") {
s += '<path d="M120 36 q-26 18 -22 60 q4 40 22 48 q18 -8 22 -48 q4 -42 -22 -60 z" fill="rgba(255,255,255,0.2)"/>';
s += '<circle cx="102" cy="78" r="5" fill="rgba(28,27,25,0.4)"/>';
s += '<circle cx="138" cy="86" r="5" fill="rgba(28,27,25,0.4)"/>';
}
s += "</svg>";
return s;
}
function gradStop(g, i) {
var m = g.match(/#[0-9a-f]{6}/gi) || ["#999999", "#333333"];
return i === 0 ? m[0] : m[m.length - 1];
}
/* ---------------- render ---------------- */
var wall = document.getElementById("wall");
var currentStyle = "standard";
var showMat = true;
function esc(str) {
return String(str).replace(/[&<>"']/g, function (c) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
});
}
function tombstone(w) {
return (
'<p class="work"><em>' + esc(w.title) + "</em>, " +
'<span class="year">' + esc(w.year) + "</span></p>" +
'<p class="specs"><span class="medium">' + esc(w.medium) + "</span><br>" +
esc(w.dims) + "</p>" +
'<p class="credit">' + esc(w.credit) + "</p>" +
'<span class="accession">' + esc(w.id) + "</span>"
);
}
function tagHtml(w) {
var html = '<div class="tags">';
(w.tags || []).forEach(function (t) {
var cls = "tag";
if (t === "On view") cls += " on-view";
if (t === "Fragile" || t === "Light sensitive") cls += " fragile";
html += '<span class="' + cls + '">' + esc(t) + "</span>";
});
html += "</div>";
return html;
}
function labelBody(w, style) {
var head =
'<p class="artist">' + esc(w.artist) + "</p>" +
'<p class="life">' + esc(w.life) + "</p>";
if (style === "kids") {
return (
head +
'<p class="work"><em>' + esc(w.title) + "</em></p>" +
'<div class="kids-q"><strong>' + esc(w.kidsTitle) + "</strong>" +
esc(w.kids) + "</div>" +
tagHtml(w)
);
}
if (style === "extended") {
return (
head +
tombstone(w) +
'<p class="interp">' + esc(w.interp) + "</p>" +
tagHtml(w)
);
}
// standard
return head + tombstone(w) + tagHtml(w);
}
function actions() {
var copyIcon =
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>';
var printIcon =
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9V3h12v6"/><rect x="6" y="14" width="12" height="7"/><path d="M6 17H3v-5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v5h-3"/></svg>';
return (
'<div class="actions">' +
'<button class="act" type="button" data-action="copy">' + copyIcon + "Copy label</button>" +
'<button class="act" type="button" data-action="print">' + printIcon + "Print label</button>" +
"</div>"
);
}
function render() {
wall.innerHTML = "";
WORKS.forEach(function (w) {
var card = document.createElement("article");
card.className = "piece" + (currentStyle === "kids" ? " is-kids" : "");
card.setAttribute("data-id", w.id);
card.innerHTML =
'<div class="art' + (showMat ? "" : " no-mat") + '">' +
'<span class="medium-tag">' + esc(w.kind) + "</span>" +
'<div class="art-canvas" style="background:' + w.grad + '">' + artSvg(w) + "</div>" +
"</div>" +
'<div class="label">' + labelBody(w, currentStyle) + "</div>" +
actions();
wall.appendChild(card);
});
}
/* ---------------- plain-text label for clipboard ---------------- */
function plainLabel(w) {
var lines = [
w.artist,
w.life,
"",
w.title + ", " + w.year,
w.medium,
w.dims,
"",
w.credit,
w.id
];
if (currentStyle === "extended") lines.push("", w.interp);
if (currentStyle === "kids") lines = [w.artist, w.title, "", w.kidsTitle, w.kids];
return lines.join("\n");
}
/* ---------------- toast ---------------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2200);
}
function copyText(text, okMsg) {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(
function () { toast(okMsg); },
function () { fallbackCopy(text, okMsg); }
);
} else {
fallbackCopy(text, okMsg);
}
}
function fallbackCopy(text, okMsg) {
var ta = document.createElement("textarea");
ta.value = text;
ta.style.position = "fixed";
ta.style.opacity = "0";
document.body.appendChild(ta);
ta.select();
try {
document.execCommand("copy");
toast(okMsg);
} catch (e) {
toast("Copy not supported");
}
document.body.removeChild(ta);
}
/* ---------------- single-label print ---------------- */
function printOnly(id) {
var cards = wall.querySelectorAll(".piece");
cards.forEach(function (c) {
if (c.getAttribute("data-id") !== id) c.classList.add("print-hide");
});
var clear = function () {
cards.forEach(function (c) { c.classList.remove("print-hide"); });
window.removeEventListener("afterprint", clear);
};
window.addEventListener("afterprint", clear);
window.print();
// safety net for browsers that don't fire afterprint
setTimeout(clear, 1500);
}
/* ---------------- events ---------------- */
// style switcher
var tabs = document.querySelectorAll(".seg");
tabs.forEach(function (tab) {
tab.addEventListener("click", function () {
tabs.forEach(function (t) {
t.classList.remove("is-active");
t.setAttribute("aria-selected", "false");
});
tab.classList.add("is-active");
tab.setAttribute("aria-selected", "true");
currentStyle = tab.getAttribute("data-style");
render();
toast(
currentStyle === "kids"
? "Kids labels — written for ages 6–10"
: currentStyle === "extended"
? "Extended interpretive labels"
: "Standard tombstone labels"
);
});
// arrow-key navigation between tabs
tab.addEventListener("keydown", function (e) {
var list = Array.prototype.slice.call(tabs);
var i = list.indexOf(tab);
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
e.preventDefault();
list[(i + 1) % list.length].focus();
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
e.preventDefault();
list[(i - 1 + list.length) % list.length].focus();
}
});
});
// mat toggle
document.getElementById("mat-toggle").addEventListener("change", function (e) {
showMat = e.target.checked;
wall.querySelectorAll(".art").forEach(function (a) {
a.classList.toggle("no-mat", !showMat);
});
});
// print all visible
document.getElementById("print-all").addEventListener("click", function () {
window.print();
});
// delegated card actions
wall.addEventListener("click", function (e) {
var btn = e.target.closest(".act");
if (!btn) return;
var card = btn.closest(".piece");
var id = card.getAttribute("data-id");
var w = WORKS.filter(function (x) { return x.id === id; })[0];
if (!w) return;
var action = btn.getAttribute("data-action");
if (action === "copy") {
copyText(plainLabel(w), "Label text copied · " + w.id);
} else if (action === "print") {
printOnly(id);
}
});
render();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Object Label / Wall Plaque</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&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="frame">
<header class="masthead">
<p class="eyebrow">The Meridian Collection · West Wing, Gallery 14</p>
<h1>Object Labels & Wall Plaques</h1>
<p class="lede">
Curatorial labels in three registers — the standard tombstone, an extended
interpretive panel, and a kids-friendly version. Switch styles, copy the
catalog text, or send a label to print.
</p>
</header>
<div class="controls" role="region" aria-label="Label controls">
<div class="switcher" role="tablist" aria-label="Label style">
<button class="seg is-active" role="tab" aria-selected="true" data-style="standard" id="tab-standard">Standard</button>
<button class="seg" role="tab" aria-selected="false" data-style="extended" id="tab-extended">Extended</button>
<button class="seg" role="tab" aria-selected="false" data-style="kids" id="tab-kids">Kids</button>
</div>
<div class="control-aside">
<label class="toggle">
<input type="checkbox" id="mat-toggle" checked />
<span>Show mat</span>
</label>
<button class="btn-ghost" id="print-all" type="button">Print visible labels</button>
</div>
</div>
<main class="wall" id="wall" aria-live="polite">
<!-- cards injected by script.js -->
</main>
<footer class="colophon">
<span class="dot" aria-hidden="true"></span>
Type set in Cormorant Garamond & Inter · Accession prefix <strong>MC</strong> ·
Labels conform to house style 7th ed.
</footer>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Object Label / Wall Plaque
A wall of four catalogued works, each paired with the kind of plaque a real institution would hang beside it. The label follows house tombstone order — artist and life dates, the work title set in italic serif, the date, medium, dimensions, credit line, and accession number — with status badges like “On view” or “Light sensitive” beneath. Artworks are rendered as matted gradient panels with inline SVG motifs, so the component is fully self-contained with no external assets.
A pill switcher at the top toggles every label between three voices: the standard tombstone, an extended version that adds an interpretive paragraph, and a kids register that trades specs for a friendly prompt. A “Show mat” checkbox frames or unframes each piece, and each card carries copy-to-clipboard and “Print label” actions. Copying emits a toast and lifts the correct plain-text label for the current style; printing isolates a single plaque using a print stylesheet, so what comes out of the printer is just the label, not the chrome.
Everything is vanilla — the demo collection lives as a small data array, labels are templated in JS, and the tab switcher is keyboard-navigable with arrow keys and visible focus rings.
Illustrative UI only — demo data; not a real museum system.