Menu
AkurAI-Build
publicLatest change 0cf28150faedd8c150474a4f16be4c9922c04f56 - feat: add Ponytail UI design system by Olafur Bui
{
"schemaVersion": 2,
"generatedAt": "2026-07-11T22:24:00Z",
"title": "Design System: Bunfork Ponytail UI",
"extensions": {
"colorMeta": {
"fork-accent-light": {
"role": "primary",
"displayName": "Fork Signal Light",
"canonical": "#176c3a",
"tonalRamp": ["#071f10", "#0b3a1e", "#0f572e", "#176c3a", "#55966d", "#8fc2a1", "#c4dfcc", "#e6f5eb"]
},
"fork-accent-dark": {
"role": "primary",
"displayName": "Fork Signal Dark",
"canonical": "#82efad",
"tonalRamp": ["#07120b", "#0d1b12", "#1f4730", "#2d6542", "#5cda8d", "#82efad", "#b9f8d0", "#e7fff0"]
},
"canvas-light": {
"role": "neutral",
"displayName": "Day Canvas",
"canonical": "#f6faf7",
"tonalRamp": ["#142119", "#34483a", "#52675a", "#718878", "#9daf9f", "#c9d8cd", "#e1ece4", "#f6faf7"]
},
"canvas-dark": {
"role": "neutral",
"displayName": "Night Canvas",
"canonical": "#090c0a",
"tonalRamp": ["#050806", "#090c0a", "#111713", "#18201b", "#202a23", "#303c33", "#5a6b5d", "#93a096"]
}
},
"typographyMeta": {
"display": {
"displayName": "Display",
"purpose": "Landing-page statements with a maximum of two lines."
},
"headline": {
"displayName": "Headline",
"purpose": "Page and major section titles."
},
"body": {
"displayName": "Body",
"purpose": "Readable prose capped near 70 characters per line."
},
"label": {
"displayName": "Label",
"purpose": "Field labels, navigation, and compact metadata."
}
},
"shadows": [
{
"name": "control-lift",
"value": "0 1px 2px rgb(0 0 0 / 12%)",
"purpose": "Selected items inside a bounded segmented control."
},
{
"name": "top-layer",
"value": "0 4px 8px rgb(0 0 0 / 16%)",
"purpose": "Popovers, dialogs, and transient messages only."
}
],
"motion": [
{
"name": "fast",
"value": "120ms cubic-bezier(.16, 1, .3, 1)",
"purpose": "Hover, press, and focus feedback."
},
{
"name": "medium",
"value": "200ms cubic-bezier(.16, 1, .3, 1)",
"purpose": "Open and close state changes."
}
],
"breakpoints": [
{
"name": "compact",
"value": "44rem"
},
{
"name": "content",
"value": "58rem"
},
{
"name": "wide",
"value": "70rem"
}
]
},
"components": [
{
"name": "Primary Button",
"kind": "button",
"refersTo": "button-primary",
"description": "The single highest-priority action in a region.",
"html": "<button class=\"ds-btn-primary\" type=\"button\">Save draft</button>",
"css": ".ds-btn-primary { min-height: 44px; padding: 11px 16px; border: 1px solid var(--pt-color-accent, #176c3a); border-radius: 8px; background: var(--pt-color-accent, #176c3a); color: var(--pt-color-on-accent, #ffffff); font: 760 1rem/1.2 ui-sans-serif, system-ui, sans-serif; cursor: pointer; transition: background-color 120ms cubic-bezier(.16,1,.3,1), transform 120ms cubic-bezier(.16,1,.3,1); } .ds-btn-primary:hover { background: var(--pt-color-accent-strong, #0f572e); } .ds-btn-primary:active { transform: translateY(1px); } .ds-btn-primary:focus-visible { outline: 3px solid var(--pt-color-accent, #176c3a); outline-offset: 3px; }"
},
{
"name": "Secondary Button",
"kind": "button",
"refersTo": "button-secondary",
"description": "A lower-priority action with a structural edge.",
"html": "<button class=\"ds-btn-secondary\" type=\"button\">Preview</button>",
"css": ".ds-btn-secondary { min-height: 44px; padding: 11px 16px; border: 1px solid var(--pt-color-border-strong, #718878); border-radius: 8px; background: var(--pt-color-surface, #ffffff); color: var(--pt-color-ink, #142119); font: 760 1rem/1.2 ui-sans-serif, system-ui, sans-serif; cursor: pointer; } .ds-btn-secondary:hover { border-color: var(--pt-color-accent, #176c3a); background: var(--pt-color-accent-surface, #e6f5eb); } .ds-btn-secondary:focus-visible { outline: 3px solid var(--pt-color-accent, #176c3a); outline-offset: 3px; }"
},
{
"name": "Text Field",
"kind": "input",
"refersTo": "input-default",
"description": "A visible label, persistent hint, and native input.",
"html": "<label class=\"ds-field\"><span>Project name</span><small id=\"ds-project-hint\">Use 3 to 40 characters.</small><input aria-describedby=\"ds-project-hint\" value=\"Bunfork native\"></label>",
"css": ".ds-field { display: grid; gap: 8px; color: var(--pt-color-ink, #142119); font: 720 .875rem/1.35 ui-sans-serif, system-ui, sans-serif; } .ds-field small { color: var(--pt-color-ink-muted, #3f5446); font-weight: 400; } .ds-field input { min-height: 44px; padding: 11px 13px; border: 1px solid var(--pt-color-border-strong, #718878); border-radius: 8px; background: var(--pt-color-surface, #ffffff); color: var(--pt-color-ink, #142119); font: 400 1rem/1.35 ui-sans-serif, system-ui, sans-serif; } .ds-field input:focus-visible { outline: 3px solid var(--pt-color-accent, #176c3a); outline-offset: 3px; }"
},
{
"name": "Status Alert",
"kind": "custom",
"description": "Static status with a plain-language heading and recovery text.",
"html": "<aside class=\"ds-alert\"><strong>Artifact verified</strong><p>Every byte matches the admitted manifest.</p></aside>",
"css": ".ds-alert { display: grid; gap: 8px; padding: 16px; border: 1px solid var(--pt-color-accent-border, #55966d); border-radius: 8px; background: var(--pt-color-accent-surface, #e6f5eb); color: var(--pt-color-ink, #142119); font: 400 1rem/1.5 ui-sans-serif, system-ui, sans-serif; } .ds-alert p { margin: 0; color: var(--pt-color-ink-muted, #3f5446); }"
},
{
"name": "Status Badge",
"kind": "chip",
"description": "Compact metadata whose meaning remains textual.",
"html": "<span class=\"ds-badge\">Ready</span>",
"css": ".ds-badge { display: inline-flex; min-height: 28px; align-items: center; padding: 0 9px; border: 1px solid var(--pt-color-accent-border, #55966d); border-radius: 999px; background: var(--pt-color-accent-surface, #e6f5eb); color: var(--pt-color-accent, #176c3a); font: 760 .75rem/1 ui-sans-serif, system-ui, sans-serif; }"
},
{
"name": "Bounded Panel",
"kind": "card",
"refersTo": "panel-default",
"description": "A visible edge for one genuinely bounded object.",
"html": "<section class=\"ds-panel\"><h3>Native starter</h3><p>One route tree, one asset directory, and no browser build step.</p></section>",
"css": ".ds-panel { display: grid; gap: 16px; padding: 24px; border: 1px solid var(--pt-color-border, #c9d8cd); border-radius: 12px; background: var(--pt-color-surface, #ffffff); color: var(--pt-color-ink, #142119); font: 400 1rem/1.5 ui-sans-serif, system-ui, sans-serif; } .ds-panel h3, .ds-panel p { margin: 0; } .ds-panel p { color: var(--pt-color-ink-muted, #3f5446); }"
},
{
"name": "Linked Tabs",
"kind": "nav",
"description": "URL-backed views with explicit current state.",
"html": "<nav class=\"ds-tabs\" aria-label=\"Release views\"><a href=\"#\" aria-current=\"page\">Summary</a><a href=\"#\">Files</a><a href=\"#\">Checks</a></nav>",
"css": ".ds-tabs { display: flex; gap: 8px; border-bottom: 1px solid var(--pt-color-border, #c9d8cd); } .ds-tabs a { display: inline-flex; min-height: 44px; align-items: center; padding: 0 12px; border-bottom: 2px solid transparent; color: var(--pt-color-ink-muted, #3f5446); font: 700 .875rem/1.2 ui-sans-serif, system-ui, sans-serif; text-decoration: none; } .ds-tabs a[aria-current=\"page\"], .ds-tabs a:hover { border-color: var(--pt-color-accent, #176c3a); color: var(--pt-color-ink, #142119); } .ds-tabs a:focus-visible { outline: 3px solid var(--pt-color-accent, #176c3a); outline-offset: 3px; }"
},
{
"name": "Native Disclosure",
"kind": "custom",
"description": "An accordion row implemented by details and summary.",
"html": "<details class=\"ds-disclosure\" open><summary>What is admitted?</summary><p>A completed directory of ordinary browser files with a strict manifest.</p></details>",
"css": ".ds-disclosure { border-block: 1px solid var(--pt-color-border, #c9d8cd); color: var(--pt-color-ink, #142119); font: 400 1rem/1.5 ui-sans-serif, system-ui, sans-serif; } .ds-disclosure summary { display: flex; min-height: 44px; align-items: center; gap: 12px; padding: 13px 0; font-weight: 750; list-style: none; cursor: pointer; } .ds-disclosure summary::-webkit-details-marker { display: none; } .ds-disclosure summary::before { display: grid; width: 24px; height: 24px; place-items: center; border: 1px solid var(--pt-color-border-strong, #718878); border-radius: 6px; content: '+'; color: var(--pt-color-accent, #176c3a); } .ds-disclosure[open] summary { color: var(--pt-color-accent, #176c3a); } .ds-disclosure[open] summary::before { border-color: var(--pt-color-accent, #176c3a); background: var(--pt-color-accent, #176c3a); color: var(--pt-color-on-accent, #ffffff); content: '−'; } .ds-disclosure p { margin: 0 0 16px; color: var(--pt-color-ink-muted, #3f5446); } .ds-disclosure summary:focus-visible { outline: 3px solid var(--pt-color-accent, #176c3a); outline-offset: 3px; }"
},
{
"name": "Themed Checkbox",
"kind": "input",
"description": "Native checked and disabled state with no user-agent visual skin.",
"html": "<label class=\"ds-check\"><input type=\"checkbox\" checked><span>Verify before bind</span></label>",
"css": ".ds-check { display: flex; min-height: 44px; align-items: center; gap: 12px; color: var(--pt-color-ink, #142119); font: 400 1rem/1.4 ui-sans-serif, system-ui, sans-serif; cursor: pointer; } .ds-check input { display: grid; width: 22px; height: 22px; place-content: center; margin: 0; border: 1px solid var(--pt-color-border-strong, #718878); border-radius: 5px; appearance: none; background: var(--pt-color-control, #ffffff); color: var(--pt-color-on-accent, #ffffff); } .ds-check input::before { width: 12px; height: 12px; background: currentColor; clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0, 43% 62%); content: ''; transform: scale(0); } .ds-check input:checked { border-color: var(--pt-color-accent, #176c3a); background: var(--pt-color-accent, #176c3a); } .ds-check input:checked::before { transform: scale(1); } .ds-check input:focus-visible { outline: 3px solid var(--pt-color-accent, #176c3a); outline-offset: 3px; }"
},
{
"name": "Themed Range",
"kind": "input",
"description": "Native range semantics with a custom neutral track, thumb, focus, and disabled state.",
"html": "<label class=\"ds-range-field\"><span>Request budget</span><input type=\"range\" min=\"0\" max=\"100\" value=\"72\"></label>",
"css": ".ds-range-field { display: grid; gap: 8px; color: var(--pt-color-ink, #142119); font: 720 .875rem/1.35 ui-sans-serif, system-ui, sans-serif; } .ds-range-field input { width: 100%; height: 24px; margin: 0; appearance: none; background: transparent; } .ds-range-field input::-webkit-slider-runnable-track { height: 7px; border-radius: 999px; background: var(--pt-color-surface-3, #e1ece4); } .ds-range-field input::-webkit-slider-thumb { width: 20px; height: 20px; margin-top: -6px; border: 3px solid var(--pt-color-surface, #ffffff); border-radius: 50%; appearance: none; background: var(--pt-color-accent, #176c3a); box-shadow: 0 0 0 1px var(--pt-color-accent, #176c3a); } .ds-range-field input:focus-visible { outline: 3px solid var(--pt-color-accent, #176c3a); outline-offset: 3px; }"
}
],
"narrative": {
"northStar": "The Open Workbench",
"overview": "Bunfork should feel like a clear work surface with real tools already laid out. The visual voice is mechanical, grounded, and candid. Controls look operable, boundaries are honest, and the forkbird green signals action without turning every surface into branding. Production uses the .pt-* API; the ten .ds-* records here are self-contained shadow-DOM previews required by the design panel, not the 20-genre runtime inventory.",
"keyCharacteristics": [
"CSS-first and server-rendered",
"Light and dark hierarchy with the same semantic roles",
"Restrained green identity with optional scoped palettes",
"Comfortable documentation density",
"Native semantics with a complete token-driven visual skin",
"Explicit state and visible focus",
"No client build step and no implied Tailwind compatibility"
],
"rules": [
{
"name": "The One Palette Rule",
"body": "Pick one accent palette per page. Nested palette scopes are for documentation previews and embedded products, not decoration.",
"section": "colors"
},
{
"name": "The Mono Earns It Rule",
"body": "Use monospace for code, commands, keyboard keys, protocol values, and tabular figures. Technical subject matter alone is not a reason.",
"section": "typography"
},
{
"name": "The Top Layer Earns Depth Rule",
"body": "Static content remains flat. Shadows appear only where content actually rises above the document.",
"section": "elevation"
},
{
"name": "The No User-Agent Skin Rule",
"body": "Preserve native semantics and platform behavior, but replace every visible default browser treatment with semantic Ponytail UI tokens.",
"section": "components"
}
],
"dos": [
"Do consume semantic --pt-* tokens in every new component.",
"Do keep normal text at 4.5:1 contrast or better in every palette and mode.",
"Do use native controls and landmarks before adding script or an abstraction.",
"Do apply the complete Ponytail UI skin to every visible control and every state.",
"Do use documented data-gap and data-width variants under Bunfork's native-page CSP.",
"Do use spacing and headings before reaching for a card."
],
"donts": [
"Don't call Ponytail UI a Tailwind fork or compatibility layer.",
"Don't use generic indigo gradients, glass panels, neon glow, gradient text, or decorative grid backgrounds.",
"Don't expose default browser checkboxes, radio buttons, select arrows, range thumbs, file buttons, progress bars, disclosure markers, dialog chrome, or scrollbars.",
"Don't use inline style attributes; the native CSP rejects them.",
"Don't use color alone for status, hide focus, shrink controls below 44px, or rely on hover.",
"Don't copy upstream component code or brand assets without an exact file, pinned commit, and license review."
]
}
}