Canvas Design System
Main Site Tokens

Energy Arc Card

Summarises how a session's energy moved: a score, an interpretive badge, a sparkline, and four contributing metrics.

When to Use

Use when: You're showing the energy arc of a specific workshop — the top of the Coach retrospective, the Planner's inspector rail, a Facilitator debrief. It carries session-retrospective semantics, not generic scoring.
Don't use when: You need a generic number — use Stat. For a single proportion use Progress. Don't stretch it past ~400px; the chart and metric grid are tuned for that width.

Variants

Canonical (light)

The default. Four regions: eyebrow header, score row, sparkline with axis labels, and a 2×2 metric grid.

ENERGY ARC 8 OF 8H USED COMPLETE
82 / 100
Needs Work
9:00 10:30 1:00 5:00
PACING ~17m
VARIETY 3/7
RECOVERY 55m
ENGAGEMENT 63%
<?= ws_energy_arc_card([
    'eyebrow'    => 'Energy Arc',
    'timeUsed'   => '8 of 8h used',
    'status'     => ['text' => 'Complete', 'type' => 'success'],
    'score'      => 82,
    'scoreBadge' => ['text' => 'Needs Work', 'type' => 'warning'],
    'chartData'  => [['time' => '9:00', 'value' => 48], /* … */],
    'timeLabels' => ['9:00', '10:30', '1:00', '5:00'],
    'metrics'    => [
        ['label' => 'Pacing',     'value' => '~17m', 'fill' => 30],
        ['label' => 'Engagement', 'value' => '63%',  'fill' => 63],
    ],
]) ?>

Dark

For presentation mode and dark dashboards. Badges and bars switch to a tinted-on-dark treatment.

ENERGY ARC 6 OF 8H USED IN PROGRESS
71 / 100
On Track
9:00 11:00 1:00 3:00
PACING ~12m
VARIETY 4/7
RECOVERY 40m
ENGAGEMENT 71%
<?= ws_energy_arc_card([/* … */ 'theme' => 'dark']) ?>

Score tiers

The badge does the interpreting. Drive its type from the score so colour reinforces the number: 85+ success, 70+ info, 50+ warning, below 50 danger.

ENERGY ARC 8 OF 8H USED COMPLETE
94 / 100
Excellent
9:00 12:00 3:00
PACING ~10m
VARIETY 6/7
RECOVERY 40m
ENGAGEMENT 91%
ENERGY ARC 4 OF 8H USED AT RISK
42 / 100
At Risk
9:00 11:00 1:00
PACING ~32m
VARIETY 1/7
RECOVERY 15m
ENGAGEMENT 38%

States

StateBehavior
DefaultStatic. The card reports; nothing in it is interactive.
Score clampedValues below 0 become 0, above scoreMax become scoreMax. A bad score can't overflow the row.
Header hiddenshowHeader => false drops the eyebrow row so a container can supply its own title. This is what Planner Inspector Rail sets automatically.
Badge variantscoreBadge.variant is pill by default; note gives the smaller mono tag the inspector rail uses.
Too few chart pointsFewer than four points renders a near-flat line that reads as no data. Pass four to eight; beyond ten the arc loses definition at this width.
No chart dataThe chart region renders empty. Guard on the array and show Empty State instead.

Real-World Usage

The Coach retrospective header. The badge tier is derived from the score rather than hand-set, so the colour can never contradict the number.

<?php
$score = $energyScorer->score($planId);
$tier  = match (true) {
    $score >= 85 => ['Excellent',  'success'],
    $score >= 70 => ['On Track',   'info'],
    $score >= 50 => ['Needs Work', 'warning'],
    default      => ['At Risk',    'danger'],
};
?>
<?= ws_energy_arc_card([
    'eyebrow'    => 'Energy Arc',
    'timeUsed'   => formatDuration($used) . ' of ' . formatDuration($planned) . ' used',
    'status'     => ['text' => $session['status_label'], 'type' => $session['status_type']],
    'score'      => $score,
    'scoreBadge' => ['text' => $tier[0], 'type' => $tier[1]],
    'chartData'  => $energyScorer->series($planId),      // 4–8 points
    'timeLabels' => $energyScorer->axisLabels($planId),
    'metrics'    => $energyScorer->dimensions($planId),  // up to 4
]) ?>

Options

OptionTypeDefaultPurpose
scoreint0Effectively required. Clamped to 0–scoreMax.
scoreMaxint100Denominator shown beside the score
scoreBadgearraynull['text' => …, 'type' => …, 'variant' => …]. Types: success | warning | danger | info | neutral. variant is pill (default) or note.
eyebrowstring'Energy Arc'Top-left label, rendered uppercase
timeUsedstring''Muted progress text in the header
statusarraynull['text' => …, 'type' => …], same types as the badge
showHeaderbooltrueRender the eyebrow row. Undocumented in the helper's docblock, but supported — the inspector rail relies on it.
chartDataarray[][['time' => …, 'value' => 0..100]]. Values are clamped.
timeLabelsarray[]X-axis tick strings, spaced evenly. Independent of chartData — they don't have to match point-for-point.
metricsarray[]Up to 4: ['label', 'value', 'fill' => 0..100, 'barColor'?]. Keep values to 3–5 characters.
themestring'light'light | dark. Corrected: this page previously documented the default as dark; the template defaults to light.
accentstringtheme defaultOverrides the accent as an inline CSS variable. Pass a token reference, not a literal hex.
id / class / attrsstring / string / arrayStandard passthrough

Accessibility

ConcernBehavior
ChartThe sparkline carries role="img" with aria-label="Energy arc over time", so it's announced as one graphic rather than a pile of SVG nodes. Good — but the label is generic and conveys no shape or trend.
Decorative partsGrid lines and the axis carry aria-hidden="true".
ScoreScore and denominator are adjacent text, so "82 out of 100" is announced in order without extra wiring.
MetricsLabel and value are text; the bar is presentational. The number carries the meaning, so the fill is safe reinforcement.
KeyboardNothing is focusable, which is correct for a read-only summary.
Colour independenceThe badge text names the tier — "At Risk", not just red. Keep it that way; the tier must never live in colour alone.
Data alternativeWorth improving: the trend itself is only available visually. Consider extending the chart's aria-label to describe the shape — "rises to a peak mid-morning, dips after lunch, recovers by close" — or offering the series as a table.
ContrastLight and dark themes each pair tested foreground and background. A custom accent bypasses that — verify it against both themes if the card appears in each.

Tokens

The card resolves a theme-scoped accent and surface set on its root, so the light and dark treatments share one set of internal rules. The accent is overridable through the accent option, which writes an inline CSS variable.

Token groupUsed for
AccentChart line, metric bar fills, and score emphasis. Theme-derived unless overridden.
Surface and borderCard background and edge, swapped per theme
Ink scaleScore, labels, metric values, and the muted header text
Status coloursThe five badge and status types — success, warning, danger, info, neutral
Type scaleDisplay score, mono eyebrow, caption-size metric labels

See the .ws-energy-arc rules in components.css for the exact declarations, and Token Reference for current values.

CSS Classes

ClassPurpose
.ws-energy-arcRoot container
.ws-energy-arc--darkDark theme. The light theme's modifier is emitted but has no rule — light is the base styling.
.ws-energy-arc__cardInner card surface
.ws-energy-arc__header / __eyebrowTop row, suppressed by showHeader: false
.ws-energy-arc__status (+ --success / --warning / --danger / --info)Header status chip
.ws-energy-arc__score-row / __score / __score-value / __score-maxScore display
.ws-energy-arc__badge (+ type modifiers, plus --note)Interpretive badge and its two variants
.ws-energy-arc__chart / __axisSparkline and its tick labels
.ws-energy-arc__metrics / __metricThe 2×2 grid and its cells
.ws-energy-arc__metric-label / -value / -bar / -bar-fillMetric internals

Files

FilePurpose
includes/components/helpers.phpws_energy_arc_card() helper function
includes/components/energy-arc-card.phpTemplate — clamping, theme resolution, chart and metric markup
includes/components/components.cssStyles (.ws-energy-arc rules)
includes/components/planner-inspector-rail.phpWraps this card with showHeader: false