/* * 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 no global * `button` rule, such as `button { color: inherit }`, can 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; font-weight: 500; 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; } } /* Sparkle glow, disabled: a solid readable face, no glow, no sparks, no fade. */ .btn-spark:disabled { opacity: 1; cursor: not-allowed; background: var(--tile-3); color: var(--ink-2); box-shadow: inset 0 0 0 1px var(--line-2); transform: none; } .btn-spark:disabled .btn-spark-inner, .btn-spark:disabled .btn-spark-hex { color: var(--ink-2); } .btn-spark:disabled .btn-spark-hex { stroke: var(--ink-2); animation: none; } .btn-spark:disabled::before, .btn-spark:disabled::after, .btn-spark:disabled .btn-spark-fold, .btn-spark:disabled .btn-spark-pts { display: none; }