markup for a named icon.
*
* The inner paths/rects/circles are copied exactly from the mockup HTML so the
* glyphs match 1:1. Stroke width follows the mockup for that glyph (most are
* 1.7/1.8; the step check is 2.4, the arrow is 2). An unknown name returns an
* empty string so a typo degrades to no icon rather than a fatal.
*
* @param string $name Icon key (see the switch below for the full set).
* @return string Inline SVG markup, or '' for an unknown name.
*/
function aafm_icon( string $name ): string {
$icons = array(
// Tab icons (dashboard-a.html lines 44-49).
'dashboard' => array( 'svg' => '' ),
'connection' => array( 'svg' => '' ),
'abilities' => array( 'svg' => '' ),
'playbooks' => array( 'svg' => '' ),
'integrations' => array( 'svg' => '' ),
// Deliberately NOT the plug: 'integrations' owns that glyph, and this tab used to carry a
// byte-identical copy of it, so the two nav items were indistinguishable. An arrow landing
// in a tray reads as abilities arriving from somewhere else, which is what this tab is.
'bridge' => array( 'svg' => '' ),
'settings' => array( 'svg' => '' ),
'activity' => array( 'svg' => '' ),
'help' => array( 'svg' => '' ),
// Right-aligned nav links (review + support).
'star' => array( 'svg' => '' ),
'lifebuoy' => array( 'svg' => '' ),
'play' => array( 'svg' => '' ),
// Dashboard card / inline icons.
'endpoint' => array( 'svg' => '' ),
'clock' => array( 'svg' => '' ),
'copy' => array( 'svg' => '' ),
// Stat icons (dashboard-a.html lines 107-134).
'bolt' => array( 'svg' => '' ),
'recent' => array( 'svg' => '' ),
'audit' => array( 'svg' => '' ),
// Registered apps: a grid of equal tiles, so it never reads as the settings shield.
'groups' => array( 'svg' => '' ),
// Card-head icons, one per card so no two cards on a tab share a glyph.
'pause' => array( 'svg' => '' ),
'bell' => array( 'svg' => '' ),
'key' => array( 'svg' => '' ),
'terminal' => array( 'svg' => '' ),
'file' => array( 'svg' => '' ),
'tag' => array( 'svg' => '' ),
// Client icons (connection.html lines 91-98).
'client-chatgpt' => array( 'svg' => '' ),
'client-claude' => array( 'svg' => '' ),
'client-claude-code' => array( 'svg' => '' ),
'client-cursor' => array( 'svg' => '' ),
'client-vscode' => array( 'svg' => '' ),
'client-windsurf' => array( 'svg' => '' ),
'client-gemini-cli' => array( 'svg' => '' ),
'client-manus' => array( 'svg' => '' ),
'client-generic' => array( 'svg' => '' ),
// Settings card-head / notice icons (settings.html lines 42-66).
'shield' => array( 'svg' => '' ),
// Per-glyph stroke width: most icons use the 1.7 default; info/warning/success/error need
// a slightly heavier 1.8 stroke to balance their smaller glyphs against the rest of the set.
'warning' => array(
'svg' => '',
'width' => '1.8',
),
'info' => array(
'svg' => '',
'width' => '1.8',
),
'success' => array(
'svg' => '',
'width' => '1.8',
),
'error' => array(
'svg' => '',
'width' => '1.8',
),
// Locked high-risk ability row (Abilities tab), drawn in the shackle-closed
// style the settings shield already uses for its stroke weight.
'lock' => array( 'svg' => '' ),
// The step-done check (dashboard-a.html line 61) and the navigation arrow (line 85) are
// stroke-weight variants that need a heavier stroke than the 1.7 default.
'check' => array(
'svg' => '',
'width' => '2.4',
),
'arrow-right' => array(
'svg' => '',
'width' => '2',
),
);
$icon = $icons[ $name ] ?? null;
if ( null === $icon ) {
return '';
}
return sprintf(
'',
$icon['width'] ?? '1.7',
$icon['svg']
);
}