jhxk68cdy: Add the five approved button styles, the glossy icon button and a dev story page
This commit is contained in:
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Button system (spec "Buttons", ADR 0001 sections 6 to 8).
|
||||
* Five styles plus the glossy crimson icon button, ported from the mockup's
|
||||
* recolored rules. Tokens only; white and black appear only on crimson faces.
|
||||
* Every class sets margin, padding, font and color itself so the legacy
|
||||
* `button` rules and any `button { color: inherit }` never leak in.
|
||||
*/
|
||||
|
||||
/* Shared base for every style. */
|
||||
.btn-flip,
|
||||
.btn-grow,
|
||||
.btn-sweep,
|
||||
.btn-depth,
|
||||
.btn-spark,
|
||||
.btn-gloss {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
isolation: isolate;
|
||||
opacity: 1;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.btn-flip svg,
|
||||
.btn-grow svg,
|
||||
.btn-depth svg,
|
||||
.btn-spark svg,
|
||||
.btn-gloss svg { flex: none; }
|
||||
|
||||
/* 1. Flip reveal: Post. Ready, disabled ("write first") and busy ("posting"). */
|
||||
.btn-flip {
|
||||
height: 42px;
|
||||
min-width: 118px;
|
||||
padding: 0 22px;
|
||||
border-radius: var(--r-ctl);
|
||||
background: var(--ink);
|
||||
color: var(--bg);
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
letter-spacing: .14em;
|
||||
text-transform: uppercase;
|
||||
box-shadow: var(--shadow-btn);
|
||||
transition: transform .3s cubic-bezier(.23,1,.32,1);
|
||||
}
|
||||
.btn-flip .btn-flip-front {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
height: 100%;
|
||||
color: var(--bg);
|
||||
transition: transform .6s cubic-bezier(.23,1,.32,1);
|
||||
}
|
||||
.btn-flip .btn-flip-back {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
color: var(--on-accent);
|
||||
background: linear-gradient(135deg, var(--accent-deep), var(--accent));
|
||||
transform: translateY(100%);
|
||||
transition: transform .6s cubic-bezier(.23,1,.32,1);
|
||||
}
|
||||
.btn-flip svg { width: 16px; height: 16px; }
|
||||
.btn-flip:hover .btn-flip-front,
|
||||
.btn-flip:focus-visible .btn-flip-front { transform: translateY(-200%); }
|
||||
.btn-flip:hover .btn-flip-back,
|
||||
.btn-flip:focus-visible .btn-flip-back { transform: none; }
|
||||
.btn-flip:active:not(:disabled) { transform: scale(.95); }
|
||||
|
||||
/* Disabled: solid graphite face, readable text, never faded. */
|
||||
.btn-flip:disabled {
|
||||
opacity: 1;
|
||||
cursor: not-allowed;
|
||||
background: var(--tile-3);
|
||||
color: var(--ink-2);
|
||||
box-shadow: inset 0 0 0 1px var(--line-2);
|
||||
}
|
||||
.btn-flip:disabled .btn-flip-front { color: var(--ink-2); }
|
||||
.btn-flip:disabled .btn-flip-back {
|
||||
background: var(--tile-3);
|
||||
color: var(--ink);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Busy (posting): keeps the ink face, shows "Posting", never flips. */
|
||||
.btn-flip.btn-flip-busy:disabled {
|
||||
cursor: progress;
|
||||
background: var(--ink);
|
||||
color: var(--bg);
|
||||
box-shadow: var(--shadow-btn);
|
||||
}
|
||||
.btn-flip.btn-flip-busy:disabled .btn-flip-front { color: var(--bg); transform: none; }
|
||||
.btn-flip.btn-flip-busy .btn-flip-back { transform: translateY(100%); }
|
||||
|
||||
/* 2. Circle expand: the new-posts pill. */
|
||||
.btn-grow {
|
||||
display: block;
|
||||
width: 178px;
|
||||
height: 42px;
|
||||
padding: 0;
|
||||
border-radius: 999px;
|
||||
background: var(--glass);
|
||||
color: var(--ink);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
backdrop-filter: blur(16px);
|
||||
box-shadow: inset 0 0 0 1px var(--line-2), var(--shadow-float);
|
||||
}
|
||||
.btn-grow .btn-grow-circle {
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 4px;
|
||||
bottom: 4px;
|
||||
width: 34px;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(180deg, var(--accent-hi), var(--accent) 55%, var(--accent-lo));
|
||||
transition: width .45s cubic-bezier(.65,0,.076,1);
|
||||
}
|
||||
.btn-grow .btn-grow-circle svg {
|
||||
position: absolute;
|
||||
left: 9px;
|
||||
top: 9px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--on-accent);
|
||||
transition: transform .45s cubic-bezier(.65,0,.076,1);
|
||||
}
|
||||
.btn-grow .btn-grow-text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: block;
|
||||
padding-left: 40px;
|
||||
line-height: 42px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 800;
|
||||
letter-spacing: .16em;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
color: var(--ink);
|
||||
transition: color .45s cubic-bezier(.65,0,.076,1);
|
||||
}
|
||||
.btn-grow:hover .btn-grow-circle,
|
||||
.btn-grow:focus-visible .btn-grow-circle { width: calc(100% - 8px); }
|
||||
.btn-grow:hover .btn-grow-circle svg,
|
||||
.btn-grow:focus-visible .btn-grow-circle svg { transform: translateY(-3px); }
|
||||
.btn-grow:hover .btn-grow-text,
|
||||
.btn-grow:focus-visible .btn-grow-text { color: var(--on-accent); }
|
||||
.btn-grow:active { transform: scale(.97); }
|
||||
|
||||
/* 3. Outline fill sweep: category chips and Cancel. Selected stays filled. */
|
||||
.btn-sweep {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 34px;
|
||||
padding: 0 15px;
|
||||
border-radius: 999px;
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
box-shadow: inset 0 0 0 1.5px var(--line-2);
|
||||
transition: color .3s, box-shadow .3s, transform .15s;
|
||||
}
|
||||
.btn-sweep::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
width: 170px;
|
||||
height: 170px;
|
||||
border-radius: 50%;
|
||||
background: var(--ink);
|
||||
top: 100%;
|
||||
left: 100%;
|
||||
transition: top .35s var(--ease), left .35s var(--ease);
|
||||
}
|
||||
.btn-sweep:hover,
|
||||
.btn-sweep:focus-visible,
|
||||
.btn-sweep.btn-sweep-on {
|
||||
color: var(--bg);
|
||||
box-shadow: inset 0 0 0 1.5px var(--ink);
|
||||
}
|
||||
.btn-sweep:hover::before,
|
||||
.btn-sweep:focus-visible::before,
|
||||
.btn-sweep.btn-sweep-on::before { top: -70px; left: -40px; }
|
||||
.btn-sweep:active { transform: scale(.95); }
|
||||
|
||||
/* 4. Soft depth, rising liquid: mobile More sheet rows and the theme switch. */
|
||||
.btn-depth {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
width: 100%;
|
||||
padding: 14px;
|
||||
border-radius: var(--r-card);
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
box-shadow: 6px 6px 14px var(--neu-d), -6px -6px 14px var(--neu-l);
|
||||
transition: color .3s, box-shadow .25s;
|
||||
}
|
||||
.btn-depth::before,
|
||||
.btn-depth::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 140%;
|
||||
height: 240%;
|
||||
border-radius: 50%;
|
||||
z-index: -1;
|
||||
transition: all .5s .05s cubic-bezier(.55,0,.1,1);
|
||||
}
|
||||
.btn-depth::before {
|
||||
left: 50%;
|
||||
top: 100%;
|
||||
transform: translateX(-50%) scaleX(1.25);
|
||||
background: color-mix(in srgb, var(--accent), transparent 82%);
|
||||
}
|
||||
.btn-depth::after {
|
||||
left: 55%;
|
||||
top: 180%;
|
||||
transform: translateX(-50%) scaleX(1.45);
|
||||
background: var(--accent);
|
||||
}
|
||||
.btn-depth .btn-depth-icon {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
flex: none;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: var(--r-ctl);
|
||||
background: var(--tile-2);
|
||||
color: var(--ink);
|
||||
transition: background-color .3s, color .3s;
|
||||
}
|
||||
.btn-depth .btn-depth-icon svg { width: 20px; height: 20px; }
|
||||
.btn-depth .btn-depth-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
|
||||
.btn-depth .btn-depth-label { font-size: 15px; font-weight: 700; color: inherit; }
|
||||
.btn-depth .btn-depth-sub { font-size: 12.5px; color: var(--ink-3); transition: color .3s; }
|
||||
.btn-depth:hover,
|
||||
.btn-depth:focus-visible { color: var(--on-accent); }
|
||||
.btn-depth:hover::before,
|
||||
.btn-depth:focus-visible::before {
|
||||
top: -35%;
|
||||
background: var(--accent);
|
||||
transform: translateX(-50%) scaleY(1.3) scaleX(.8);
|
||||
}
|
||||
.btn-depth:hover::after,
|
||||
.btn-depth:focus-visible::after { top: -45%; transform: translateX(-50%) scaleY(1.3) scaleX(.8); }
|
||||
.btn-depth:hover .btn-depth-sub,
|
||||
.btn-depth:focus-visible .btn-depth-sub { color: color-mix(in srgb, white 82%, transparent); }
|
||||
.btn-depth:hover .btn-depth-icon,
|
||||
.btn-depth:focus-visible .btn-depth-icon { background: color-mix(in srgb, white 16%, transparent); color: var(--on-accent); }
|
||||
.btn-depth:active { box-shadow: inset 4px 4px 12px var(--neu-d), inset -4px -4px 12px var(--neu-l); }
|
||||
|
||||
/* 5. Sparkle glow: Sign in (fold + hexagon) and the mobile new-post button (plus). */
|
||||
.btn-spark {
|
||||
--spark-round: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 180px;
|
||||
height: 50px;
|
||||
padding: 0 22px;
|
||||
border-radius: var(--spark-round);
|
||||
color: var(--on-accent);
|
||||
background:
|
||||
radial-gradient(65% 65% at 50% 100%, var(--accent-glow) 0%, var(--accent-glow-0) 100%),
|
||||
linear-gradient(0deg, var(--accent), var(--accent));
|
||||
box-shadow: 0 18px 36px -14px color-mix(in srgb, var(--accent), transparent 15%);
|
||||
transition: transform .25s;
|
||||
}
|
||||
.btn-spark::before,
|
||||
.btn-spark::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: var(--spark-inset);
|
||||
border-radius: calc(var(--spark-round) - var(--spark-inset));
|
||||
z-index: 0;
|
||||
transition: all .5s ease-in-out;
|
||||
}
|
||||
.btn-spark::before {
|
||||
--spark-inset: 1px;
|
||||
background: linear-gradient(178deg, color-mix(in srgb, white 24%, transparent) 0%, transparent 100%);
|
||||
}
|
||||
.btn-spark::after {
|
||||
--spark-inset: 2px;
|
||||
background:
|
||||
radial-gradient(65% 65% at 50% 100%, var(--accent-glow) 0%, var(--accent-glow-0) 100%),
|
||||
linear-gradient(0deg, var(--accent), var(--accent));
|
||||
}
|
||||
.btn-spark:active { transform: scale(.96); }
|
||||
|
||||
.btn-spark .btn-spark-fold {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
transition: all .5s ease-in-out;
|
||||
background: radial-gradient(100% 75% at 55%, var(--accent-glow) 0%, var(--accent-glow-0) 100%);
|
||||
box-shadow: 0 0 3px black;
|
||||
border-bottom-left-radius: .5rem;
|
||||
border-top-right-radius: var(--spark-round);
|
||||
}
|
||||
.btn-spark .btn-spark-fold::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 150%;
|
||||
height: 150%;
|
||||
transform: rotate(45deg) translateY(-18px);
|
||||
background: var(--bg);
|
||||
pointer-events: none;
|
||||
}
|
||||
.btn-spark:hover .btn-spark-fold,
|
||||
.btn-spark:focus-visible .btn-spark-fold { margin-top: -1rem; margin-right: -1rem; }
|
||||
|
||||
.btn-spark .btn-spark-pts { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 1; }
|
||||
.btn-spark .btn-spark-pts i {
|
||||
position: absolute;
|
||||
bottom: -10px;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
border-radius: 50%;
|
||||
background: var(--on-accent);
|
||||
animation: btn-spark-rise infinite ease-in-out;
|
||||
}
|
||||
@keyframes btn-spark-rise {
|
||||
0% { transform: translateY(0); }
|
||||
85% { opacity: 0; }
|
||||
100% { transform: translateY(-60px); opacity: 0; }
|
||||
}
|
||||
.btn-spark .btn-spark-pts i:nth-child(1) { left: 10%; animation-duration: 2.35s; animation-delay: .2s; }
|
||||
.btn-spark .btn-spark-pts i:nth-child(2) { left: 30%; opacity: .7; animation-duration: 2.5s; animation-delay: .5s; }
|
||||
.btn-spark .btn-spark-pts i:nth-child(3) { left: 25%; opacity: .8; animation-duration: 2.2s; animation-delay: .1s; }
|
||||
.btn-spark .btn-spark-pts i:nth-child(4) { left: 44%; opacity: .6; animation-duration: 2.05s; }
|
||||
.btn-spark .btn-spark-pts i:nth-child(5) { left: 50%; animation-duration: 1.9s; }
|
||||
.btn-spark .btn-spark-pts i:nth-child(6) { left: 75%; opacity: .5; animation-duration: 1.5s; animation-delay: 1.5s; }
|
||||
.btn-spark .btn-spark-pts i:nth-child(7) { left: 88%; opacity: .9; animation-duration: 2.2s; animation-delay: .2s; }
|
||||
.btn-spark .btn-spark-pts i:nth-child(8) { left: 58%; opacity: .8; animation-duration: 2.25s; animation-delay: .2s; }
|
||||
.btn-spark .btn-spark-pts i:nth-child(9) { left: 96%; opacity: .6; animation-duration: 2.6s; animation-delay: .1s; }
|
||||
.btn-spark .btn-spark-pts i:nth-child(10) { left: 65%; animation-duration: 2.5s; animation-delay: .2s; }
|
||||
|
||||
.btn-spark .btn-spark-inner {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: var(--on-accent);
|
||||
font-weight: 700;
|
||||
font-size: 15px;
|
||||
letter-spacing: .06em;
|
||||
}
|
||||
.btn-spark .btn-spark-hex {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
fill: transparent;
|
||||
stroke: var(--on-accent);
|
||||
stroke-width: 2.2;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.btn-spark:hover .btn-spark-hex,
|
||||
.btn-spark:focus-visible .btn-spark-hex {
|
||||
animation: btn-spark-dash 1s linear forwards, btn-spark-fill .1s linear forwards .95s;
|
||||
}
|
||||
@keyframes btn-spark-dash { from { stroke-dasharray: 0 0 0 0; } to { stroke-dasharray: 68 68 0 0; } }
|
||||
@keyframes btn-spark-fill { to { fill: var(--on-accent); } }
|
||||
|
||||
/* Mobile new-post variant: square, no fold, the plus turns 90 degrees. */
|
||||
.btn-spark.btn-spark-fab {
|
||||
--spark-round: 16px;
|
||||
min-width: 0;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
padding: 0;
|
||||
box-shadow: 0 12px 26px -10px color-mix(in srgb, var(--accent), transparent 15%);
|
||||
}
|
||||
.btn-spark.btn-spark-fab::after { display: none; }
|
||||
.btn-spark.btn-spark-fab:active { transform: scale(.94); }
|
||||
.btn-spark .btn-spark-plus {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: var(--on-accent);
|
||||
transition: transform .5s cubic-bezier(.2,.9,.3,1.4);
|
||||
}
|
||||
.btn-spark:hover .btn-spark-plus,
|
||||
.btn-spark:focus-visible .btn-spark-plus { transform: rotate(90deg); }
|
||||
|
||||
/* Glossy crimson icon button: send comment, delete confirm, play. */
|
||||
.btn-gloss {
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
padding: 0;
|
||||
border-radius: var(--r-ctl);
|
||||
color: var(--on-accent);
|
||||
background: linear-gradient(180deg, var(--accent-hi), var(--accent) 50%, var(--accent-lo));
|
||||
box-shadow:
|
||||
inset 0 1px 0 color-mix(in srgb, white 32%, transparent),
|
||||
inset 0 -1px 0 color-mix(in srgb, black 28%, transparent),
|
||||
0 0 0 1px var(--accent-lo),
|
||||
0 12px 26px -14px var(--accent);
|
||||
transition: transform .18s var(--ease), box-shadow .3s;
|
||||
}
|
||||
.btn-gloss.btn-gloss-round { border-radius: 50%; }
|
||||
.btn-gloss.btn-gloss-sm { width: 36px; height: 36px; }
|
||||
.btn-gloss svg { width: 18px; height: 18px; color: var(--on-accent); }
|
||||
.btn-gloss::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 50%;
|
||||
background: linear-gradient(180deg, color-mix(in srgb, white 20%, transparent), transparent);
|
||||
z-index: -1;
|
||||
}
|
||||
.btn-gloss::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -10%;
|
||||
bottom: -10%;
|
||||
width: 55%;
|
||||
left: -90%;
|
||||
background: linear-gradient(100deg, transparent, color-mix(in srgb, white 42%, transparent), transparent);
|
||||
transform: skewX(-20deg);
|
||||
transition: left .8s var(--ease);
|
||||
}
|
||||
.btn-gloss:hover::after,
|
||||
.btn-gloss:focus-visible::after { left: 140%; }
|
||||
.btn-gloss:active:not(:disabled) { transform: scale(.96); }
|
||||
/* Disabled keeps a solid face (no opacity) so the icon stays readable. */
|
||||
.btn-gloss:disabled {
|
||||
opacity: 1;
|
||||
cursor: not-allowed;
|
||||
background: var(--tile-3);
|
||||
color: var(--ink-2);
|
||||
box-shadow: inset 0 0 0 1px var(--line-2);
|
||||
}
|
||||
.btn-gloss:disabled svg { color: var(--ink-2); }
|
||||
.btn-gloss:disabled::before,
|
||||
.btn-gloss:disabled::after { display: none; }
|
||||
|
||||
/* Reduced motion: hover and press states still change color, but nothing moves. */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.btn-flip,
|
||||
.btn-flip *,
|
||||
.btn-grow,
|
||||
.btn-grow *,
|
||||
.btn-sweep,
|
||||
.btn-sweep::before,
|
||||
.btn-depth,
|
||||
.btn-depth *,
|
||||
.btn-depth::before,
|
||||
.btn-depth::after,
|
||||
.btn-spark,
|
||||
.btn-spark *,
|
||||
.btn-spark::before,
|
||||
.btn-spark::after,
|
||||
.btn-gloss,
|
||||
.btn-gloss::before,
|
||||
.btn-gloss::after {
|
||||
transition: none !important;
|
||||
animation: none !important;
|
||||
}
|
||||
.btn-flip:active,
|
||||
.btn-grow:active,
|
||||
.btn-sweep:active,
|
||||
.btn-spark:active,
|
||||
.btn-gloss:active { transform: none !important; }
|
||||
.btn-grow:hover .btn-grow-circle svg,
|
||||
.btn-grow:focus-visible .btn-grow-circle svg,
|
||||
.btn-spark:hover .btn-spark-plus,
|
||||
.btn-spark:focus-visible .btn-spark-plus { transform: none !important; }
|
||||
.btn-spark .btn-spark-pts { display: none; }
|
||||
.btn-spark:hover .btn-spark-hex,
|
||||
.btn-spark:focus-visible .btn-spark-hex { fill: var(--on-accent); }
|
||||
.btn-gloss::after { display: none; }
|
||||
}
|
||||
Reference in New Issue
Block a user