/* Matte buttons. Scoped styles and editable color and motion tokens. */ @font-face { font-family: 'Instrument Sans'; src: url('./instrument-sans-variable.woff2') format('woff2'); font-weight: 400 700; font-style: normal; font-display: swap; } .button-kit { --unit: 1px; --ink: #222222; --secondary: #e4e3e0; --save-feedback: #3f3f3f; --primary-hover: #2e2e2e; --primary-foreground: #fafafa; --secondary-hover: #dcdcdc; --secondary-feedback: #cdcdcd; --secondary-foreground: var(--ink); --focus-ring: #5a5a5a; --motion-duration-short-2: 100ms; --motion-duration-short-3: 150ms; --motion-duration-short-4: 200ms; --motion-duration-medium-1: 250ms; --motion-duration-medium-2: 300ms; --motion-duration-medium-3: 350ms; --motion-easing-standard: cubic-bezier(0.2,0,0,1); --motion-easing-emphasized-decelerate: cubic-bezier(0.05,0.7,0.1,1); --motion-easing-ease-in-out-gentle: cubic-bezier(0.4,0,0.2,1); font-family: 'Instrument Sans', sans-serif; font-synthesis: none; -webkit-font-smoothing: antialiased; display: flex; flex-direction: column; align-items: center; gap: calc(20 * var(--unit)); } .button-kit *, .button-kit *::before, .button-kit *::after { box-sizing: border-box; } .bk-button { appearance: none; -webkit-tap-highlight-color: transparent; position: relative; display: block; border: 0; padding: 0; background: transparent; font: inherit; font-weight: 550; letter-spacing: -0.02em; cursor: pointer; touch-action: manipulation; user-select: none; border-radius: calc(13 * var(--unit)); outline-offset: 6px; } .bk-button:focus-visible { outline: 2px solid var(--focus-ring); } .bk-button--save { width: calc(220 * var(--unit)); height: calc(52 * var(--unit)); font-size: calc(19 * var(--unit)); color: var(--primary-foreground); } .bk-button--cancel { width: calc(140 * var(--unit)); height: calc(46 * var(--unit)); font-size: calc(16 * var(--unit)); color: var(--secondary-foreground); } .bk-surface { position: absolute; inset: 0; overflow: hidden; isolation: isolate; display: grid; place-items: center; border-radius: inherit; transition: transform var(--motion-duration-medium-3) var(--motion-easing-emphasized-decelerate), background-color var(--motion-duration-short-4) var(--motion-easing-standard), box-shadow var(--motion-duration-medium-2) var(--motion-easing-standard); } .bk-button--save .bk-surface { background-color: var(--secondary-foreground); background-image: linear-gradient(155deg, rgb(255 255 255 / 2.5%), transparent 68%); box-shadow: inset 0 1px 0 rgb(255 255 255 / 7%), 0 1px 2px rgb(0 0 0 / 5%); } .bk-button--cancel .bk-surface { background-color: var(--secondary); box-shadow: inset 0 1px 0 rgb(255 255 255 / 18%); } @media (hover: hover) { .bk-button:not([aria-disabled="true"]):hover .bk-surface { transform: translateY(-2px); } .bk-button--save:not([aria-disabled="true"]):hover .bk-surface { background-color: var(--primary-hover); box-shadow: inset 0 1px 0 rgb(255 255 255 / 9%), 0 6px 12px -8px rgb(0 0 0 / 28%); } .bk-button--cancel:hover .bk-surface { background-color: var(--secondary-hover); } } .bk-button:not([aria-disabled="true"]):active .bk-surface, .bk-button.is-pressed .bk-surface { transform: translateY(1px) scale(0.98); transition-duration: var(--motion-duration-short-2); transition-timing-function: var(--motion-easing-standard); } .bk-button[aria-disabled="true"] { cursor: default; } .bk-label { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 0.3em; line-height: 1.1; white-space: nowrap; opacity: 0; transition: opacity var(--motion-duration-short-3) var(--motion-easing-standard); } [data-state="idle"] .bk-label-idle, [data-state="saving"] .bk-label-saving, [data-state="saved"] .bk-label-saved, [data-state="cancelled"] .bk-label-cancelled { opacity: 1; } /* M3 fade-through: finish the outgoing label before revealing its replacement. */ .bk-button[data-state="idle"] .bk-label-idle, .bk-button[data-state="saving"] .bk-label-saving, .bk-button[data-state="saved"] .bk-label-saved, .bk-button[data-state="cancelled"] .bk-label-cancelled { transition-duration: var(--motion-duration-short-4); transition-delay: var(--motion-duration-short-3); } /* A gentler, 600ms return after success; other state changes keep their timing. */ .bk-button--save[data-transition="return"] .bk-label-saved { transition-duration: var(--motion-duration-medium-1); transition-timing-function: var(--motion-easing-ease-in-out-gentle); } .bk-button--save[data-transition="return"] .bk-label-idle { transition-duration: var(--motion-duration-medium-3); transition-delay: var(--motion-duration-medium-1); transition-timing-function: var(--motion-easing-ease-in-out-gentle); } .bk-ellipsis { margin-left: -0.3em; } .bk-progress { position: absolute; inset: 0; background: var(--save-feedback); transform: scaleX(0); transform-origin: left center; } .bk-wash { position: absolute; inset: 0; background: var(--secondary-feedback); opacity: 0; } .bk-label-saved { display: grid; grid-template-columns: 1fr auto 1fr; gap: 0.24em; } .bk-label-saved .bk-check { justify-self: end; } .bk-saved-text { grid-column: 2; } .bk-check { width: 1em; height: 1em; flex: 0 0 auto; overflow: visible; } .bk-check path { stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 0; } [data-state="saved"] .bk-check path { animation: bk-check-draw var(--motion-duration-medium-3) var(--motion-easing-standard) var(--motion-duration-short-2) backwards; } @keyframes bk-check-draw { from { stroke-dashoffset: 1; opacity: 0; } 15% { opacity: 1; } to { stroke-dashoffset: 0; opacity: 1; } } .bk-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; } @media (prefers-reduced-motion: reduce) { .bk-button .bk-surface, .bk-button .bk-label, .bk-check path { transition: none; } .bk-button[data-state] .bk-label { transition: none; } [data-state="saved"] .bk-check path { animation: none; } .bk-button .bk-surface, .bk-button:hover .bk-surface, .bk-button:active .bk-surface, .bk-button.is-pressed .bk-surface, .bk-button .bk-label { transform: none; } .bk-button:active .bk-surface { opacity: 0.88; } .bk-progress { display: none; } } @media (forced-colors: active) { .bk-surface { border: 1px solid ButtonText; } .bk-progress, .bk-wash { display: none; } }