/* =========================
Buttons
Figma: Buttons / Button — Large 64, Medium 48, Small 40,
Xsmall 32, XXsmall 24.
========================= */
@use "sass:color";
@use "../kit-deps" as *;
@keyframes vmk-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.btn {
// Variant tokens
--btn-bg: transparent;
--btn-border: transparent;
--btn-text: #{$neutral-900};
--btn-hover-bg: var(--btn-bg);
--btn-hover-border: var(--btn-border);
--btn-hover-text: var(--btn-text);
--btn-focus-bg: var(--btn-hover-bg);
--btn-focus-border: var(--btn-hover-border);
--btn-focus-text: var(--btn-hover-text);
--btn-disabled-bg: var(--btn-bg);
--btn-disabled-border: var(--btn-border);
--btn-disabled-text: var(--btn-text);
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
gap: $space-2;
font-family: $font-family-base;
font-weight: $font-weight-semibold;
line-height: 1;
text-align: center;
text-decoration: none;
text-transform: none;
white-space: nowrap;
vertical-align: middle;
border-width: $border-width-base;
border-style: $border-style-base;
border-color: var(--btn-border);
border-radius: $radius-full;
background-color: var(--btn-bg);
color: var(--btn-text);
cursor: pointer;
transition:
background-color $motion-base $motion-ease,
border-color $motion-base $motion-ease,
color $motion-base $motion-ease,
box-shadow $motion-base $motion-ease;
&:focus-visible {
@include focus_ring;
}
&:hover:not(:disabled):not(.is-disabled):not(.is-loading),
&.is-hover:not(:disabled):not(.is-disabled):not(.is-loading) {
background-color: var(--btn-hover-bg);
border-color: var(--btn-hover-border);
color: var(--btn-hover-text);
}
&:active:not(:disabled):not(.is-disabled):not(.is-loading),
&.is-active:not(:disabled):not(.is-disabled):not(.is-loading) {
background-color: var(--btn-focus-bg);
border-color: var(--btn-focus-border);
color: var(--btn-focus-text);
}
&:disabled,
&.is-disabled {
background-color: var(--btn-disabled-bg) !important;
border-color: var(--btn-disabled-border) !important;
color: var(--btn-disabled-text) !important;
cursor: not-allowed;
opacity: 1;
}
&.is-loading {
cursor: wait;
.vmk-icon {
animation: vmk-spin 1s linear infinite;
}
}
.vmk-icon {
color: currentColor;
flex-shrink: 0;
}
}
// Sizes
// Reference API: sm (40), md (48), lg (64). Figma adds xs (32) and xxs (24).
.btn-lg {
min-height: 64px;
padding: $space-4 $space-6;
font-size: 16px;
}
.btn-md {
min-height: 48px;
padding: $space-3 $space-5;
font-size: 15px;
}
.btn-sm {
min-height: 40px;
padding: $space-2 $space-4;
font-size: 13px;
}
.btn-xs {
min-height: 32px;
padding: $space-1 $space-3;
font-size: 12px;
}
.btn-xxs {
min-height: 24px;
padding: $space-0 $space-2;
font-size: 13px;
}
// Block button
.btn-block {
display: flex;
width: 100%;
}
// Icon-only: keep a perfect circle and equal padding.
.btn-icon-only {
aspect-ratio: 1 / 1;
padding: 0;
&.btn-lg { width: 64px; }
&.btn-md { width: 48px; }
&.btn-sm { width: 40px; }
&.btn-xs { width: 32px; }
&.btn-xxs { width: 24px; }
}
// Variants aligned with Figma Button.png
// Primary — filled yellow CTA
.btn-primary {
--btn-bg: #{$yellow-300};
--btn-border: #{$yellow-300};
--btn-text: #{$neutral-900};
--btn-hover-bg: #{$yellow-400};
--btn-hover-border: #{$yellow-400};
--btn-focus-bg: #{$yellow-500};
--btn-focus-border: #{$yellow-500};
--btn-disabled-bg: #{$neutral-200};
--btn-disabled-border: #{$neutral-200};
--btn-disabled-text: #{$neutral-500};
}
// Accent — yellow alias, kept for API compatibility.
.btn-accent {
--btn-bg: #{$yellow-300};
--btn-border: #{$yellow-300};
--btn-text: #{$neutral-900};
--btn-hover-bg: #{$yellow-400};
--btn-hover-border: #{$yellow-400};
--btn-focus-bg: #{$yellow-500};
--btn-focus-border: #{$yellow-500};
--btn-disabled-bg: #{$neutral-200};
--btn-disabled-border: #{$neutral-200};
--btn-disabled-text: #{$neutral-500};
}
// Secondary — mint outline (Figma secondary row)
.btn-secondary {
--btn-bg: transparent;
--btn-border: #{$mint-600};
--btn-text: #{$mint-800};
--btn-hover-bg: #{$mint-100};
--btn-hover-border: #{$mint-600};
--btn-focus-bg: #{$mint-200};
--btn-focus-border: #{$mint-600};
--btn-disabled-bg: transparent;
--btn-disabled-border: #{$mint-200};
--btn-disabled-text: #{$mint-500};
}
// Tertiary — ghost dark text (Figma tertiary row)
.btn-tertiary {
--btn-bg: transparent;
--btn-border: transparent;
--btn-text: #{$neutral-900};
--btn-hover-bg: #{$neutral-100};
--btn-hover-border: transparent;
--btn-focus-bg: #{$neutral-200};
--btn-focus-border: transparent;
--btn-disabled-bg: transparent;
--btn-disabled-border: transparent;
--btn-disabled-text: #{$neutral-400};
&.btn-icon-only {
border-radius: $radius-md;
}
}
// Semantic variants
.btn-success {
--btn-bg: #{$success-bg};
--btn-border: #{$success-text};
--btn-text: #{$success-text};
--btn-hover-bg: #{color.mix($success-text, $success-bg, 12%)};
--btn-hover-border: #{$success-text};
--btn-focus-bg: #{color.mix($success-text, $success-bg, 24%)};
--btn-disabled-bg: #{$success-bg};
--btn-disabled-border: #{rgba($success-text, 0.4)};
--btn-disabled-text: #{rgba($success-text, 0.5)};
}
.btn-warning {
--btn-bg: #{$warning-bg};
--btn-border: #{$warning-text};
--btn-text: #{$warning-text};
--btn-hover-bg: #{color.mix($warning-text, $warning-bg, 12%)};
--btn-hover-border: #{$warning-text};
--btn-focus-bg: #{color.mix($warning-text, $warning-bg, 24%)};
--btn-disabled-bg: #{$warning-bg};
--btn-disabled-border: #{rgba($warning-text, 0.4)};
--btn-disabled-text: #{rgba($warning-text, 0.5)};
}
.btn-info {
--btn-bg: #{$info-bg};
--btn-border: #{$info-text};
--btn-text: #{$info-text};
--btn-hover-bg: #{color.mix($info-text, $info-bg, 12%)};
--btn-hover-border: #{$info-text};
--btn-focus-bg: #{color.mix($info-text, $info-bg, 24%)};
--btn-disabled-bg: #{$info-bg};
--btn-disabled-border: #{rgba($info-text, 0.4)};
--btn-disabled-text: #{rgba($info-text, 0.5)};
}
// Danger / Error — destructive red fill
.btn-danger,
.btn-error {
--btn-bg: #{$danger-text};
--btn-border: #{$danger-text};
--btn-text: #{$neutral-0};
--btn-hover-bg: #{color.adjust($danger-text, $lightness: -8%)};
--btn-hover-border: #{color.adjust($danger-text, $lightness: -8%)};
--btn-focus-bg: #{color.adjust($danger-text, $lightness: -12%)};
--btn-focus-border: #{color.adjust($danger-text, $lightness: -12%)};
--btn-disabled-bg: #{$danger-bg};
--btn-disabled-border: #{$danger-bg};
--btn-disabled-text: #{rgba($danger-text, 0.5)};
}
// Destructive secondary — light red outline
.btn-danger-secondary,
.btn-error-secondary {
--btn-bg: #{$danger-bg};
--btn-border: #{$danger-text};
--btn-text: #{$danger-text};
--btn-hover-bg: #{color.adjust($danger-bg, $lightness: -4%)};
--btn-hover-border: #{$danger-text};
--btn-focus-bg: #{color.adjust($danger-bg, $lightness: -8%)};
--btn-focus-border: #{$danger-text};
--btn-disabled-bg: #{$danger-bg};
--btn-disabled-border: #{rgba($danger-text, 0.3)};
--btn-disabled-text: #{rgba($danger-text, 0.5)};
}
// Destructive tertiary — red ghost
.btn-danger-tertiary,
.btn-error-tertiary {
--btn-bg: transparent;
--btn-border: transparent;
--btn-text: #{$danger-text};
--btn-hover-bg: #{$danger-bg};
--btn-hover-border: transparent;
--btn-focus-bg: #{color.adjust($danger-bg, $lightness: -4%)};
--btn-focus-border: transparent;
--btn-disabled-bg: transparent;
--btn-disabled-border: transparent;
--btn-disabled-text: #{rgba($danger-text, 0.5)};
}