Usage meters
Budget, seats and credit as three meters, with the forecast hatched past what is used and alert thresholds marked on the bar.
Oct 1 to Oct 14, 2026
Before the $1,000.00 included credit. GPU use is up 18% on September.
It is live: hover, focus and its own controls respond. Actions that would change data (approve, send, delete) are for your app to wire. The width is a real 390 px, 768 px or 1280 px box, shrunk to fit your screen.
<style>
.odl-donut-breakdown { box-sizing: border-box; inline-size: 100%; max-inline-size: 720px; container-type: inline-size; text-wrap: pretty; }
.odl-donut-breakdown *, .odl-donut-breakdown *::before { box-sizing: border-box; }
.odl-donut-breakdown .odl-card { display: grid; gap: var(--ds-space-stack-lg); padding: var(--ds-space-inset-lg); background: var(--ds-color-surface-raised); color: var(--ds-color-text-primary);
border: var(--ds-border-width-default) solid var(--ds-color-border-subtle); border-radius: var(--ds-radius-container); box-shadow: var(--ds-elevation-raised); font: var(--ds-text-body-md); }
.odl-donut-breakdown .odl-head { display: grid; justify-items: start; gap: var(--ds-space-2); }
.odl-donut-breakdown h3 { margin: 0; font: var(--ds-text-title-sm); }
.odl-donut-breakdown .odl-sub { margin: 0; color: var(--ds-color-text-secondary); font: var(--ds-text-body-sm); font-variant-numeric: tabular-nums; }
.odl-donut-breakdown .odl-body { display: grid; gap: var(--ds-space-stack-lg); justify-items: center; }
.odl-donut-breakdown figure { position: relative; display: grid; place-items: center; inline-size: 100%; max-inline-size: 12.5rem; margin: 0; aspect-ratio: 1; }
.odl-donut-breakdown svg { grid-area: 1 / 1; inline-size: 100%; block-size: 100%; overflow: visible; }
.odl-donut-breakdown circle { fill: none; stroke-width: 15; transition: stroke-width var(--ds-motion-duration-short) var(--ds-motion-easing-standard), opacity var(--ds-motion-duration-short) var(--ds-motion-easing-standard); }
.odl-donut-breakdown .odl-s1 { stroke: var(--ds-color-bg-accent-bold); }
.odl-donut-breakdown .odl-s2 { stroke: var(--ds-color-bg-info-bold); }
.odl-donut-breakdown .odl-s3 { stroke: var(--ds-color-bg-warning-bold); }
.odl-donut-breakdown .odl-s4 { stroke: var(--ds-color-border-strong); }
.odl-donut-breakdown .odl-total { grid-area: 1 / 1; display: grid; justify-items: center; gap: var(--ds-space-2); text-align: center; }
.odl-donut-breakdown .odl-total b { font: var(--ds-text-numeric-lg); font-variant-numeric: tabular-nums; }
.odl-donut-breakdown .odl-total span { color: var(--ds-color-text-secondary); font: var(--ds-text-label-md); }
.odl-donut-breakdown ul { inline-size: 100%; margin: 0; padding: 0; list-style: none; display: grid; font-variant-numeric: tabular-nums; }
.odl-donut-breakdown li { display: grid; grid-template-columns: var(--ds-space-12) minmax(0, 1fr) auto 5ch; align-items: center; column-gap: var(--ds-space-inline-sm);
min-block-size: max(var(--ds-size-row-md), var(--ds-size-target-min)); padding-inline: var(--ds-space-8);
transition: background-color var(--ds-motion-duration-short) var(--ds-motion-easing-standard); }
.odl-donut-breakdown li + li { border-block-start: var(--ds-border-width-default) solid var(--ds-color-border-subtle); }
.odl-donut-breakdown li:hover { background: var(--ds-color-bg-neutral-subtle); }
.odl-donut-breakdown .odl-sw { inline-size: var(--ds-space-12); block-size: var(--ds-space-12); border-radius: var(--ds-radius-detail); }
.odl-donut-breakdown .odl-k1 { background: var(--ds-color-bg-accent-bold); }
.odl-donut-breakdown .odl-k2 { background: var(--ds-color-bg-info-bold); }
.odl-donut-breakdown .odl-k3 { background: var(--ds-color-bg-warning-bold); }
.odl-donut-breakdown .odl-k4 { background: var(--ds-color-border-strong); }
.odl-donut-breakdown .odl-name { display: grid; min-inline-size: 0; padding-block: var(--ds-space-4); }
.odl-donut-breakdown .odl-name small { color: var(--ds-color-text-tertiary); font: var(--ds-text-body-sm); }
.odl-donut-breakdown .odl-amt { text-align: end; }
.odl-donut-breakdown .odl-pct { color: var(--ds-color-text-secondary); font: var(--ds-text-body-sm); text-align: end; }
.odl-donut-breakdown:has(li:hover) circle { opacity: 0.3; }
.odl-donut-breakdown:has(.odl-r1:hover) .odl-s1, .odl-donut-breakdown:has(.odl-r2:hover) .odl-s2,
.odl-donut-breakdown:has(.odl-r3:hover) .odl-s3, .odl-donut-breakdown:has(.odl-r4:hover) .odl-s4 { opacity: 1; stroke-width: 19; }
.odl-donut-breakdown .odl-foot { margin: 0; color: var(--ds-color-text-secondary); font: var(--ds-text-body-sm); }
@container (min-width: 30rem) {
.odl-donut-breakdown .odl-body { grid-template-columns: 11rem minmax(0, 1fr); align-items: center; gap: var(--ds-space-inset-xl); }
}
@container (max-width: 22rem) {
.odl-donut-breakdown .odl-card { padding: var(--ds-space-inset-md); }
.odl-donut-breakdown figure { max-inline-size: 10.5rem; }
.odl-donut-breakdown li { padding-inline: var(--ds-space-4); }
}
@media (prefers-reduced-motion: reduce) { .odl-donut-breakdown, .odl-donut-breakdown *, .odl-donut-breakdown *::before { transition: none !important; animation: none !important; } }
</style>
<section class="odl-donut-breakdown" aria-label="Usage by category">
<div class="odl-card">
<div class="odl-head">
<h3>Usage by category</h3>
<p class="odl-sub">Oct 1 to Oct 14, 2026</p>
</div>
<div class="odl-body">
<figure aria-hidden="true">
<svg viewBox="0 0 120 120">
<g transform="rotate(-90 60 60)">
<circle class="odl-s1" cx="60" cy="60" r="48" pathLength="100" stroke-dasharray="55 45" stroke-dashoffset="0"/>
<circle class="odl-s2" cx="60" cy="60" r="48" pathLength="100" stroke-dasharray="26.4 73.6" stroke-dashoffset="-55.8"/>
<circle class="odl-s3" cx="60" cy="60" r="48" pathLength="100" stroke-dasharray="9.8 90.2" stroke-dashoffset="-83"/>
<circle class="odl-s4" cx="60" cy="60" r="48" pathLength="100" stroke-dasharray="5.6 94.4" stroke-dashoffset="-93.6"/>
</g>
</svg>
<div class="odl-total"><b>$6,932</b><span>usage to date</span></div>
</figure>
<ul aria-label="Usage to date, $6,932.38, by category">
<li class="odl-r1"><span class="odl-sw odl-k1" aria-hidden="true"></span><span class="odl-name">GPU instances<small>1,842.5 GPU-h</small></span><span class="odl-amt">$3,869.25</span><span class="odl-pct">55.8%</span></li>
<li class="odl-r2"><span class="odl-sw odl-k2" aria-hidden="true"></span><span class="odl-name">CPU and batch<small>21,406 vCPU-h</small></span><span class="odl-amt">$1,882.37</span><span class="odl-pct">27.2%</span></li>
<li class="odl-r3"><span class="odl-sw odl-k3" aria-hidden="true"></span><span class="odl-name">Storage<small>48.2 TB-month</small></span><span class="odl-amt">$734.90</span><span class="odl-pct">10.6%</span></li>
<li class="odl-r4"><span class="odl-sw odl-k4" aria-hidden="true"></span><span class="odl-name">Networking<small>5.1 TB out</small></span><span class="odl-amt">$445.86</span><span class="odl-pct">6.4%</span></li>
</ul>
</div>
<p class="odl-foot">Before the $1,000.00 included credit. GPU use is up 18% on September.</p>
</div>
</section>
Budget, seats and credit as three meters, with the forecast hatched past what is used and alert thresholds marked on the bar.
Six months of spend as bars, with the current month's forecast hatched on top, a dashed budget line and a tooltip on the bar you point at.
One service metric over a day against its objective, with yesterday for comparison, a deploy marker, a data gap and the moment it went wrong in the warning colour.