Contents Purpose Anatomy Variants States Tokens Used Accessibility Behavior Platform Notes Component: skeleton Purpose Indicate loading state with a placeholder that approximates content shape. Anatomy Single element — shape determined by class Variants Class Visual Usage skeleton Base — surface-tertiary bg, pulse animation Generic block placeholder skeleton-text Height matches text-base line, narrow width Text line placeholder skeleton-heading Height matches text-lg line, wider Heading placeholder skeleton-circle Square with border-radius 50% Avatar/icon placeholder States Always animating (pulse). Respects prefers-reduced-motion — static at reduced opacity, no animation. Tokens Used --text-base, --text-lg --leading-normal, --leading-tight --space-2 --color-surface-tertiary Accessibility Use aria-hidden="true" on skeleton elements — they are decorative placeholders The loading state should be communicated via aria-busy="true" on the parent container Screen readers should not announce individual skeleton elements Behavior Pulse animation: opacity oscillates between 1.0 and 0.4, 1.5s linear infinite prefers-reduced-motion: reduce: static at opacity 0.6, no animation skeleton-text default: height: calc(var(--text-base) * var(--leading-normal)), width: 80% skeleton-heading default: height: calc(var(--text-lg) * var(--leading-tight)), width: 60% skeleton-circle is the one exception to border-radius: 0 — avatars/icons need it No color — always neutral. Never accent or functional colors. Stacking: multiple .skeleton-text in a column with space-2 gap approximates a paragraph Default skeleton-circle size: 32px (matches icon-md + padding) Platform Notes Web: CSS in @layer components. One file: skeleton.css. Pure CSS animation — no JS needed. macOS: Map to a shimmer NSView or SwiftUI .redacted(reason: .placeholder).