// Button Component - Material Design 3 // ===================================== // Implements M3 button specifications using official M3 tokens // https://m3.material.io/components/buttons/specs @use '../tokens' as m3; // Base button styles .button { // Layout position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 8px; border: none; border-radius: m3.$corner-full; cursor: pointer; text-decoration: none; overflow: hidden; user-select: none; vertical-align: middle; -webkit-appearance: none; // Typography (M3 label-large) @include m3.typography(label-large); // Transitions transition: background-color m3.$motion-duration-short4 m3.$motion-easing-standard, box-shadow m3.$motion-duration-short4 m3.$motion-easing-standard, border-color m3.$motion-duration-short4 m3.$motion-easing-standard; // Touch target (48px minimum) &::after { content: ''; position: absolute; inset: 50% auto auto 50%; transform: translate(-50%, -50%); width: 48px; height: 48px; } // Focus ring &:focus-visible { outline: 2px solid m3.$primary; outline-offset: 2px; } // Disabled base state &:disabled { @include m3.disabled; } // Icon sizing .icon { display: inline-flex; font-size: 1.125rem; width: 1.125rem; height: 1.125rem; } // ============================================ // Size Variants // ============================================ &--small { height: 32px; padding: 0 16px; font-size: 0.75rem; .icon { font-size: 1rem; width: 1rem; height: 1rem; } } &--medium { height: 40px; padding: 0 24px; } &--large { height: 48px; padding: 0 32px; font-size: 1rem; .icon { font-size: 1.25rem; width: 1.25rem; height: 1.25rem; } } // ============================================ // Filled Button (High Emphasis) // ============================================ &--filled { background: m3.$primary; color: m3.$on-primary; &:hover:not(:disabled) { // M3: state layer with on-primary color at hover opacity background: color-mix( in srgb, m3.$primary calc(100% - 8%), m3.$on-primary ); } &:focus-visible:not(:disabled) { background: color-mix( in srgb, m3.$primary calc(100% - 12%), m3.$on-primary ); } &:active:not(:disabled) { background: color-mix( in srgb, m3.$primary calc(100% - 12%), m3.$on-primary ); } &:disabled { background: color-mix( in srgb, m3.$on-surface #{m3.$disabled-container-opacity * 100%}, transparent ); color: color-mix( in srgb, m3.$on-surface #{m3.$disabled-content-opacity * 100%}, transparent ); } } // ============================================ // Outlined Button (Medium Emphasis) // ============================================ &--outlined { background: transparent; color: m3.$primary; border: 1px solid m3.$outline; &:hover:not(:disabled) { background: color-mix( in srgb, m3.$primary 8%, transparent ); } &:focus-visible:not(:disabled) { background: color-mix( in srgb, m3.$primary 12%, transparent ); border-color: m3.$primary; } &:active:not(:disabled) { background: color-mix( in srgb, m3.$primary 12%, transparent ); } &:disabled { color: color-mix( in srgb, m3.$on-surface #{m3.$disabled-content-opacity * 100%}, transparent ); border-color: color-mix( in srgb, m3.$on-surface #{m3.$disabled-container-opacity * 100%}, transparent ); } } // ============================================ // Text Button (Low Emphasis) // ============================================ &--text { background: transparent; color: m3.$primary; padding: 0 12px; &:hover:not(:disabled) { background: color-mix( in srgb, m3.$primary 8%, transparent ); } &:focus-visible:not(:disabled) { background: color-mix( in srgb, m3.$primary 12%, transparent ); } &:active:not(:disabled) { background: color-mix( in srgb, m3.$primary 12%, transparent ); } &:disabled { color: color-mix( in srgb, m3.$on-surface #{m3.$disabled-content-opacity * 100%}, transparent ); } } // ============================================ // Tonal Button (Secondary Container) // ============================================ &--tonal { background: m3.$secondary-container; color: m3.$on-secondary-container; &:hover:not(:disabled) { background: color-mix( in srgb, m3.$secondary-container calc(100% - 8%), m3.$on-secondary-container ); } &:focus-visible:not(:disabled) { background: color-mix( in srgb, m3.$secondary-container calc(100% - 12%), m3.$on-secondary-container ); } &:active:not(:disabled) { background: color-mix( in srgb, m3.$secondary-container calc(100% - 12%), m3.$on-secondary-container ); } &:disabled { background: color-mix( in srgb, m3.$on-surface #{m3.$disabled-container-opacity * 100%}, transparent ); color: color-mix( in srgb, m3.$on-surface #{m3.$disabled-content-opacity * 100%}, transparent ); } } // ============================================ // Elevated Button (With Shadow) // ============================================ &--elevated { background: m3.$surface-container-low; color: m3.$primary; box-shadow: m3.$elevation-level1; &:hover:not(:disabled) { background: color-mix( in srgb, m3.$surface-container-low calc(100% - 8%), m3.$primary ); box-shadow: m3.$elevation-level2; } &:focus-visible:not(:disabled) { background: color-mix( in srgb, m3.$surface-container-low calc(100% - 12%), m3.$primary ); box-shadow: m3.$elevation-level1; } &:active:not(:disabled) { background: color-mix( in srgb, m3.$surface-container-low calc(100% - 12%), m3.$primary ); box-shadow: m3.$elevation-level1; } &:disabled { background: color-mix( in srgb, m3.$on-surface #{m3.$disabled-container-opacity * 100%}, transparent ); color: color-mix( in srgb, m3.$on-surface #{m3.$disabled-content-opacity * 100%}, transparent ); box-shadow: m3.$elevation-level0; } } }