Delivery — Order Detail
A mobile-first food delivery order detail and receipt screen with a delivered status banner, four-step progress tracker, itemized list with quantities and prices, and an expandable payment summary covering subtotal, delivery and service fees, estimated tax, courier tip, and total. Includes delivery address with drop-off instructions, courier and payment rows, a five-star order rating control, and reorder and get-help actions wired to lightweight toast feedback.
MCP
Code
:root {
--brand: #ff5a2c;
--brand-d: #e0461d;
--ink: #16181d;
--ink-2: #3b3f4a;
--muted: #71757f;
--bg: #f4f5f7;
--surface: #ffffff;
--line: rgba(22, 24, 29, 0.1);
--ok: #1f9d62;
--warn: #e89422;
--danger: #d4493e;
--track: #5b8def;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--shadow-sm: 0 1px 3px rgba(22, 24, 29, 0.06), 0 1px 2px rgba(22, 24, 29, 0.04);
--shadow-md: 0 6px 20px rgba(22, 24, 29, 0.08);
--shadow-lg: 0 18px 50px rgba(22, 24, 29, 0.14);
}
* { box-sizing: border-box; }
html, body {
margin: 0;
padding: 0;
}
body {
font-family: "Inter", system-ui, -apple-system, sans-serif;
line-height: 1.5;
color: var(--ink);
background:
radial-gradient(900px 500px at 20% -10%, rgba(255, 90, 44, 0.1), transparent 60%),
radial-gradient(800px 500px at 110% 10%, rgba(91, 141, 239, 0.12), transparent 55%),
var(--bg);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-height: 100vh;
display: grid;
place-items: center;
padding: 24px 12px;
}
/* ---------- Phone shell ---------- */
.phone {
width: 100%;
max-width: 420px;
background: var(--bg);
border-radius: 28px;
box-shadow: var(--shadow-lg);
overflow: hidden;
display: flex;
flex-direction: column;
height: min(860px, calc(100vh - 48px));
border: 1px solid var(--line);
}
.topbar {
display: flex;
align-items: center;
gap: 10px;
padding: 16px 14px;
background: var(--surface);
border-bottom: 1px solid var(--line);
}
.topbar-title {
flex: 1;
display: flex;
flex-direction: column;
line-height: 1.2;
}
.topbar-title .kicker {
font-size: 11px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--muted);
}
.topbar-title strong { font-size: 16px; font-weight: 700; }
.icon-btn {
display: grid;
place-items: center;
width: 38px;
height: 38px;
border-radius: 50%;
border: 1px solid var(--line);
background: var(--surface);
color: var(--ink);
cursor: pointer;
transition: background 0.15s ease, transform 0.1s ease;
}
.icon-btn:hover { background: #f6f7f9; }
.icon-btn:active { transform: scale(0.94); }
.icon-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
/* ---------- Scroll area ---------- */
.scroll {
flex: 1;
overflow-y: auto;
padding: 14px;
display: flex;
flex-direction: column;
gap: 14px;
}
.card {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 16px;
box-shadow: var(--shadow-sm);
}
.card-title {
font-size: 15px;
font-weight: 700;
margin: 0 0 12px;
}
/* ---------- Status card ---------- */
.status-card {
background:
radial-gradient(420px 220px at 100% 0%, rgba(31, 157, 98, 0.12), transparent 60%),
var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 18px 16px;
box-shadow: var(--shadow-md);
}
.status-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.status-time { font-size: 12px; color: var(--muted); font-weight: 500; }
.status-headline { font-size: 22px; font-weight: 800; margin: 0; letter-spacing: -0.01em; }
.status-sub { margin: 4px 0 16px; color: var(--ink-2); font-size: 14px; }
.pill {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
font-weight: 700;
padding: 5px 11px;
border-radius: 999px;
letter-spacing: 0.01em;
}
.pill .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.pill-ok { color: var(--ok); background: rgba(31, 157, 98, 0.12); }
.pill-warn { color: var(--warn); background: rgba(232, 148, 34, 0.14); }
.pill-danger { color: var(--danger); background: rgba(212, 73, 62, 0.12); }
/* ---------- Tracker ---------- */
.tracker {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0;
position: relative;
}
.tracker .step {
font-size: 10.5px;
font-weight: 600;
color: var(--muted);
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
position: relative;
}
.tracker .step .tick {
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--line);
display: grid;
place-items: center;
position: relative;
z-index: 2;
}
.tracker .step::before {
content: "";
position: absolute;
top: 9px;
left: -50%;
width: 100%;
height: 3px;
background: var(--line);
z-index: 1;
}
.tracker .step:first-child::before { display: none; }
.tracker .step.done { color: var(--ok); }
.tracker .step.done .tick { background: var(--ok); }
.tracker .step.done .tick::after {
content: "";
width: 6px;
height: 9px;
border: solid #fff;
border-width: 0 2px 2px 0;
transform: translateY(-1px) rotate(45deg);
}
.tracker .step.done::before { background: var(--ok); }
/* ---------- Merchant ---------- */
.merchant {
display: flex;
align-items: center;
gap: 12px;
padding-bottom: 14px;
margin-bottom: 14px;
border-bottom: 1px solid var(--line);
}
.merchant-logo {
width: 44px;
height: 44px;
border-radius: var(--r-md);
background: linear-gradient(135deg, var(--brand), var(--brand-d));
color: #fff;
font-weight: 800;
font-size: 13px;
display: grid;
place-items: center;
flex-shrink: 0;
}
.merchant-meta { display: flex; flex-direction: column; }
.merchant-meta strong { font-size: 15px; font-weight: 700; }
.merchant-meta span { font-size: 12.5px; color: var(--muted); }
/* ---------- Items ---------- */
.items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.item {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: start;
gap: 12px;
padding: 10px 0;
border-bottom: 1px dashed var(--line);
}
.item:last-child { border-bottom: none; }
.qty {
font-weight: 700;
font-size: 13px;
color: var(--brand-d);
background: rgba(255, 90, 44, 0.1);
border-radius: var(--r-sm);
padding: 3px 8px;
min-width: 30px;
text-align: center;
}
.item-body { display: flex; flex-direction: column; }
.item-body strong { font-size: 14px; font-weight: 600; }
.item-note { font-size: 12px; color: var(--muted); }
.item-price { font-weight: 700; font-size: 14px; white-space: nowrap; }
/* ---------- Totals ---------- */
.totals { margin: 0; }
.trow {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
font-size: 14px;
}
.trow dt { color: var(--ink-2); margin: 0; }
.trow dd { margin: 0; font-weight: 600; }
.trow-total {
border-top: 1px solid var(--line);
margin-top: 4px;
padding-top: 12px;
font-size: 16px;
}
.trow-total dt { color: var(--ink); font-weight: 700; }
.trow-total dd { font-weight: 800; color: var(--ink); }
.link-btn {
display: inline-flex;
align-items: center;
gap: 4px;
background: none;
border: none;
padding: 0;
font: inherit;
color: var(--track);
font-weight: 600;
cursor: pointer;
}
.link-btn:focus-visible { outline: 2px solid var(--track); outline-offset: 3px; border-radius: 4px; }
.link-btn .chev { transition: transform 0.2s ease; }
.link-btn[aria-expanded="true"] .chev { transform: rotate(180deg); }
.fees-panel {
background: #f6f7f9;
border-radius: var(--r-md);
padding: 4px 12px;
margin: 2px 0 6px;
}
.frow {
display: flex;
justify-content: space-between;
padding: 7px 0;
font-size: 13px;
color: var(--ink-2);
}
.frow + .frow { border-top: 1px solid var(--line); }
.paid-with {
display: flex;
align-items: center;
gap: 8px;
margin: 14px 0 0;
padding-top: 14px;
border-top: 1px solid var(--line);
font-size: 13px;
color: var(--ink-2);
font-weight: 500;
}
/* ---------- Delivery details ---------- */
.detail-row {
display: flex;
gap: 12px;
align-items: flex-start;
padding: 9px 0;
}
.detail-row + .detail-row { border-top: 1px solid var(--line); }
.detail-ico {
font-size: 17px;
line-height: 1.3;
width: 22px;
text-align: center;
flex-shrink: 0;
}
.detail-row strong { display: block; font-size: 14px; font-weight: 600; }
.detail-sub { font-size: 12.5px; color: var(--muted); }
/* ---------- Rate ---------- */
.rate-card { text-align: center; }
.rate-sub { font-size: 13px; color: var(--muted); margin: -6px 0 12px; }
.stars { display: flex; justify-content: center; gap: 6px; }
.star {
background: none;
border: none;
font-size: 34px;
line-height: 1;
color: var(--line);
cursor: pointer;
padding: 2px;
transition: transform 0.12s ease, color 0.12s ease;
}
.star:hover { transform: scale(1.15); }
.star:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 6px; }
.star.lit { color: var(--warn); }
.rate-result {
font-size: 13px;
font-weight: 600;
color: var(--ok);
margin: 10px 0 0;
min-height: 18px;
}
/* ---------- Footer actions ---------- */
.actions {
display: flex;
gap: 10px;
padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
background: var(--surface);
border-top: 1px solid var(--line);
}
.btn {
flex: 1;
border-radius: 999px;
border: 1px solid transparent;
padding: 13px 14px;
font: inherit;
font-weight: 700;
font-size: 14px;
cursor: pointer;
transition: transform 0.1s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.btn:active { transform: translateY(1px) scale(0.99); }
.btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.btn-ghost {
flex: 0 0 38%;
background: var(--surface);
border-color: var(--line);
color: var(--ink);
}
.btn-ghost:hover { background: #f6f7f9; }
.btn-primary {
background: linear-gradient(180deg, var(--brand), var(--brand-d));
color: #fff;
box-shadow: 0 6px 16px rgba(255, 90, 44, 0.32);
}
.btn-primary:hover { box-shadow: 0 8px 22px rgba(255, 90, 44, 0.42); }
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 28px;
transform: translate(-50%, 24px);
background: var(--ink);
color: #fff;
padding: 12px 18px;
border-radius: 999px;
font-size: 13.5px;
font-weight: 600;
box-shadow: var(--shadow-lg);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
z-index: 50;
max-width: 90vw;
text-align: center;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
@media (max-width: 520px) {
body { padding: 0; }
.phone {
max-width: none;
height: 100vh;
border-radius: 0;
border: none;
}
.status-headline { font-size: 20px; }
}
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; animation: none !important; }
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer = null;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2600);
}
/* ---------- Expandable fee breakdown ---------- */
var feesBtn = document.getElementById("feesBtn");
var feesPanel = document.getElementById("feesPanel");
if (feesBtn && feesPanel) {
feesBtn.addEventListener("click", function () {
var open = feesBtn.getAttribute("aria-expanded") === "true";
feesBtn.setAttribute("aria-expanded", String(!open));
feesPanel.hidden = open;
});
}
/* ---------- Rate order stars ---------- */
var starWrap = document.getElementById("stars");
var rateResult = document.getElementById("rateResult");
var rated = 0;
var labels = {
1: "Sorry it missed — we'll flag this order.",
2: "Thanks — we'll work on it.",
3: "Noted, thanks for the feedback.",
4: "Great! Glad it landed well.",
5: "Loved it! Marisol will be thrilled."
};
if (starWrap) {
var stars = Array.prototype.slice.call(starWrap.querySelectorAll(".star"));
function paint(n) {
stars.forEach(function (s) {
var v = Number(s.getAttribute("data-value"));
s.classList.toggle("lit", v <= n);
});
}
function commit(n) {
rated = n;
stars.forEach(function (s) {
var v = Number(s.getAttribute("data-value"));
s.setAttribute("aria-checked", String(v === n));
s.setAttribute("tabindex", v === n ? "0" : "-1");
});
paint(n);
if (rateResult) rateResult.textContent = labels[n] || "";
toast("Thanks — you rated this order " + n + "★");
}
stars.forEach(function (star) {
var v = Number(star.getAttribute("data-value"));
star.addEventListener("mouseenter", function () { paint(v); });
star.addEventListener("focus", function () { paint(v); });
star.addEventListener("click", function () { commit(v); });
star.addEventListener("keydown", function (e) {
if (e.key === "ArrowRight" || e.key === "ArrowUp") {
e.preventDefault();
commit(Math.min(5, (rated || v) + 1));
stars[Math.min(5, (rated || v) + 1) - 1].focus();
} else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
e.preventDefault();
var nv = Math.max(1, (rated || v) - 1);
commit(nv);
stars[nv - 1].focus();
} else if (e.key === " " || e.key === "Enter") {
e.preventDefault();
commit(v);
}
});
});
starWrap.addEventListener("mouseleave", function () { paint(rated); });
}
/* ---------- Reorder ---------- */
var reorderBtn = document.getElementById("reorderBtn");
if (reorderBtn) {
reorderBtn.addEventListener("click", function () {
var original = reorderBtn.textContent;
reorderBtn.disabled = true;
reorderBtn.textContent = "Adding…";
setTimeout(function () {
reorderBtn.disabled = false;
reorderBtn.textContent = original;
toast("3 items added to a new cart from Saffron & Salt");
}, 700);
});
}
/* ---------- Get help ---------- */
var helpBtn = document.getElementById("helpBtn");
if (helpBtn) {
helpBtn.addEventListener("click", function () {
toast("Connecting you to support for order #SS-48207…");
});
}
/* ---------- Topbar buttons (illustrative) ---------- */
var shareBtn = document.querySelector('[aria-label="Share receipt"]');
if (shareBtn) {
shareBtn.addEventListener("click", function () {
toast("Receipt link copied to clipboard");
});
}
var backBtn = document.querySelector('[aria-label="Back to orders"]');
if (backBtn) {
backBtn.addEventListener("click", function () {
toast("Returning to your orders");
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Order Detail — Saffron & Salt</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;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="phone" role="application" aria-label="Delivery order detail">
<header class="topbar">
<button class="icon-btn" aria-label="Back to orders" type="button">
<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true"><path d="M15 5l-7 7 7 7" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
<div class="topbar-title">
<span class="kicker">Order detail</span>
<strong>#SS-48207</strong>
</div>
<button class="icon-btn" aria-label="Share receipt" type="button">
<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true"><path d="M12 3v12M8 7l4-4 4 4M5 13v6h14v-6" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
</header>
<main class="scroll">
<!-- Status banner -->
<section class="status-card" aria-label="Order status">
<div class="status-row">
<span class="pill pill-ok" id="statusPill">
<span class="dot" aria-hidden="true"></span> Delivered
</span>
<span class="status-time">Today · 7:42 PM</span>
</div>
<h1 class="status-headline">Your order arrived</h1>
<p class="status-sub">Handed to you by <strong>Marisol R.</strong> in 28 min.</p>
<ol class="tracker" aria-label="Delivery progress">
<li class="step done"><span class="tick" aria-hidden="true"></span>Confirmed</li>
<li class="step done"><span class="tick" aria-hidden="true"></span>Preparing</li>
<li class="step done"><span class="tick" aria-hidden="true"></span>On the way</li>
<li class="step done"><span class="tick" aria-hidden="true"></span>Delivered</li>
</ol>
</section>
<!-- Restaurant + items -->
<section class="card" aria-labelledby="itemsHeading">
<div class="merchant">
<div class="merchant-logo" aria-hidden="true">S&S</div>
<div class="merchant-meta">
<strong>Saffron & Salt</strong>
<span>2 items · Modern Indian</span>
</div>
</div>
<h2 id="itemsHeading" class="card-title">Your items</h2>
<ul class="items">
<li class="item">
<span class="qty">1×</span>
<div class="item-body">
<strong>Butter Chicken Bowl</strong>
<span class="item-note">Extra naan · Mild spice</span>
</div>
<span class="item-price">$16.50</span>
</li>
<li class="item">
<span class="qty">2×</span>
<div class="item-body">
<strong>Mango Lassi</strong>
<span class="item-note">No added sugar</span>
</div>
<span class="item-price">$11.00</span>
</li>
<li class="item">
<span class="qty">1×</span>
<div class="item-body">
<strong>Garlic Naan (3pc)</strong>
<span class="item-note">Brushed with ghee</span>
</div>
<span class="item-price">$6.75</span>
</li>
</ul>
</section>
<!-- Totals -->
<section class="card" aria-labelledby="totalsHeading">
<h2 id="totalsHeading" class="card-title">Payment summary</h2>
<dl class="totals">
<div class="trow"><dt>Subtotal</dt><dd>$34.25</dd></div>
<div class="trow fees-toggle">
<dt>
<button id="feesBtn" class="link-btn" type="button" aria-expanded="false" aria-controls="feesPanel">
Fees & estimated tax
<svg class="chev" viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path d="M6 9l6 6 6-6" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
</dt>
<dd>$6.18</dd>
</div>
<div class="fees-panel" id="feesPanel" hidden>
<div class="frow"><span>Delivery fee</span><span>$2.99</span></div>
<div class="frow"><span>Service fee</span><span>$2.40</span></div>
<div class="frow"><span>Estimated tax</span><span>$0.79</span></div>
</div>
<div class="trow"><dt>Courier tip</dt><dd>$6.00</dd></div>
<div class="trow trow-total"><dt>Total</dt><dd id="totalAmount">$46.43</dd></div>
</dl>
<p class="paid-with">
<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><rect x="2" y="5" width="20" height="14" rx="2.5" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M2 9h20" stroke="currentColor" stroke-width="1.8"/></svg>
Visa ···· 4821 · Charged $46.43
</p>
</section>
<!-- Delivery details -->
<section class="card" aria-labelledby="deliveryHeading">
<h2 id="deliveryHeading" class="card-title">Delivery details</h2>
<div class="detail-row">
<span class="detail-ico" aria-hidden="true">📍</span>
<div>
<strong>414 Larkspur Ave, Apt 7C</strong>
<span class="detail-sub">Portland, OR 97214</span>
</div>
</div>
<div class="detail-row">
<span class="detail-ico" aria-hidden="true">📝</span>
<div>
<strong>Leave at door</strong>
<span class="detail-sub">Ring buzzer 7C, then text on arrival.</span>
</div>
</div>
<div class="detail-row">
<span class="detail-ico" aria-hidden="true">🚲</span>
<div>
<strong>Marisol R.</strong>
<span class="detail-sub">Your courier · 4.96★ rating</span>
</div>
</div>
</section>
<!-- Rate order -->
<section class="card rate-card" aria-labelledby="rateHeading">
<h2 id="rateHeading" class="card-title">How was your order?</h2>
<p class="rate-sub">Tap to rate your experience.</p>
<div class="stars" id="stars" role="radiogroup" aria-label="Rate this order from 1 to 5 stars">
<button class="star" type="button" role="radio" aria-checked="false" data-value="1" aria-label="1 star">★</button>
<button class="star" type="button" role="radio" aria-checked="false" data-value="2" aria-label="2 stars">★</button>
<button class="star" type="button" role="radio" aria-checked="false" data-value="3" aria-label="3 stars">★</button>
<button class="star" type="button" role="radio" aria-checked="false" data-value="4" aria-label="4 stars">★</button>
<button class="star" type="button" role="radio" aria-checked="false" data-value="5" aria-label="5 stars">★</button>
</div>
<p class="rate-result" id="rateResult" aria-live="polite"></p>
</section>
</main>
<footer class="actions">
<button class="btn btn-ghost" id="helpBtn" type="button">Get help</button>
<button class="btn btn-primary" id="reorderBtn" type="button">Reorder · $34.25</button>
</footer>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Order Detail
A self-contained delivery order detail screen built as a mobile-first phone shell. The top card shows a delivered status pill, the courier name, and a four-step progress tracker (Confirmed → Preparing → On the way → Delivered) rendered purely with CSS. Below it, an itemized receipt lists each dish with its quantity, modifiers, and price, followed by a payment summary that breaks down subtotal, fees, tip, and total.
The interactions are vanilla JavaScript with no dependencies. The “Fees & estimated tax” row expands to reveal the delivery fee, service fee, and tax via an accessible aria-expanded toggle. The rating control is a keyboard-navigable star radiogroup that lights up on hover and focus and confirms your score with a contextual message. The footer “Reorder” and “Get help” buttons, plus the share and back actions, all surface short-lived toast notifications.
Everything is keyboard-usable with visible focus rings, semantic landmarks, and WCAG AA contrast, and the layout collapses to a full-bleed mobile screen at narrow widths.
Illustrative UI only — fictional brand, not a real delivery service.