Stages compress; adoption percentages explain. This bar shows the count of practices live versus the canonical set, so a team can see exactly what's missing from the next rung.
Acceptance Criteria
[ ] Bar fills proportional to adopted / total
[ ] Numeric readout in tabular-nums
[ ] Bar uses pillar token, hollow remainder
[ ] Negative: does NOT round 99% up to 100%
Constraints
Pure CSS
Theme-aware via tokens
// practice-adoption-bar.astro
---
import type { CompendiumMeta } from '../../../data/types';
export const meta: CompendiumMeta = {
id: 443,
slug: 'practice-adoption-bar',
name: 'Practice Adoption Bar',
category: 'maturity-process',
subcategory: 'indicators',
pillar: 'de',
description: 'Horizontal bar showing what fraction of DoCoDeGo practices the team has adopted — maturity by checklist.',
spec: `## Intent
Stages compress; adoption percentages explain. This bar shows the count of practices live versus the canonical set, so a team can see exactly what's missing from the next rung.
## Acceptance Criteria
- [ ] Bar fills proportional to adopted / total
- [ ] Numeric readout in tabular-nums
- [ ] Bar uses pillar token, hollow remainder
- [ ] Negative: does NOT round 99% up to 100%
## Constraints
- Pure CSS
- Theme-aware via tokens`,
tags: ['gauge', 'real-content', 'dark-mode-tested', 'responsive'],
status: 'stable',
health: { ics: 89, a11y: 'aa', themed: true, animated: false },
};
const adopted = 11;
const total = 16;
const pct = Math.floor((adopted / total) * 100);
---
<div data-this-component class="w-full bg-paper text-black border-4 border-black overflow-hidden">
<header class="flex items-baseline justify-between px-3 py-2 border-b-2 border-black">
<span class="font-mono text-[10px] uppercase tracking-widest opacity-60">// practices adopted</span>
<span class="font-mono text-[10px] uppercase tracking-widest tabular-nums">{adopted}/{total}</span>
</header>
<div class="p-3">
<div class="relative h-6 border-4 border-black bg-paper overflow-hidden">
<div class="h-full bg-de" style={`width: ${pct}%`} aria-hidden="true"></div>
<div class="absolute inset-0 flex items-center justify-end pe-2">
<span class="font-black text-[12px] tabular-nums">{pct}%</span>
</div>
</div>
<div class="mt-3 grid grid-cols-4 gap-1.5" aria-hidden="true">
{Array.from({ length: total }).map((_, i) => (
<span class:list={['h-1.5 border-2 border-black', i < adopted ? 'bg-de' : 'bg-paper']}></span>
))}
</div>
<div class="mt-3 pt-3 border-t-2 border-black flex items-baseline justify-between font-mono text-[9px] uppercase tracking-widest">
<span class="opacity-60">remaining</span>
<span class="font-black tabular-nums">{total - adopted} practices</span>
</div>
</div>
</div>
</content>
</invoke>