styles
tcmts.examples.userinput.styles · #doan53mk · css file
/* userinput: feedback boards, in the manner of Apple's apps. Large type, space to breathe, squircles (continuous
corners, where the browser draws them), and few colours: greys, one blue, and a tint for each status. */
:root {
color-scheme: light dark;
--font: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Helvetica Neue", "Inter", system-ui, sans-serif;
--mono: ui-monospace, "SF Mono", Menlo, monospace;
--bg: #f5f5f7;
--surface: #ffffff;
--fill: rgba(120, 120, 128, 0.12);
--fill-strong: rgba(120, 120, 128, 0.2);
--text: #1d1d1f;
--secondary: #6e6e73;
--tertiary: #aeaeb2;
--separator: rgba(60, 60, 67, 0.12);
--accent: #0071e3;
--accent-text: #ffffff;
--danger: #e30000;
--shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.06);
--bar: rgba(245, 245, 247, 0.72);
--open: #6e6e73;
--review: #5e5ce6;
--planned: #0071e3;
--progress: #f56300;
--implemented: #1d9b45;
--declined: #e30000;
--closed: #8e8e93;
--r-sm: 12px;
--r: 22px;
--r-lg: 32px;
--space: 8px;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #000000;
--surface: #1c1c1e;
--fill: rgba(120, 120, 128, 0.24);
--fill-strong: rgba(120, 120, 128, 0.36);
--text: #f5f5f7;
--secondary: #a1a1a6;
--tertiary: #636366;
--separator: rgba(84, 84, 88, 0.6);
--accent: #2997ff;
--shadow: none;
--bar: rgba(22, 22, 23, 0.72);
--open: #a1a1a6;
--review: #7d7aff;
--planned: #2997ff;
--progress: #ff9f0a;
--implemented: #30d158;
--declined: #ff453a;
}
}
* {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
background: var(--bg);
color: var(--text);
font: 17px/1.47 var(--font);
letter-spacing: -0.022em;
-webkit-font-smoothing: antialiased;
}
a {
color: inherit;
text-decoration: none;
}
button,
input,
textarea,
select {
font: inherit;
color: inherit;
letter-spacing: inherit;
}
/* continuous corners: a squircle where the browser can draw one, a rounded rectangle where it can't */
.sq {
border-radius: var(--r);
corner-shape: squircle;
}
@supports (corner-shape: squircle) {
.sq {
border-radius: calc(var(--r) * 1.6);
}
}
/* ---- the frame ------------------------------------------------------------------------------------------------- */
.bar {
position: sticky;
top: 0;
z-index: 10;
background: var(--bar);
backdrop-filter: saturate(180%) blur(20px);
-webkit-backdrop-filter: saturate(180%) blur(20px);
border-bottom: 1px solid var(--separator);
}
.bar-inner {
max-width: 1080px;
margin: 0 auto;
height: 56px;
padding: 0 24px;
display: flex;
align-items: center;
gap: 16px;
}
.brand {
font-weight: 600;
font-size: 19px;
letter-spacing: -0.02em;
display: flex;
align-items: center;
gap: 10px;
}
.brand-mark {
width: 28px;
height: 28px;
--r: 8px;
background: linear-gradient(135deg, #0a84ff, #5e5ce6);
display: grid;
place-items: center;
color: white;
font-size: 15px;
}
.bar-spacer {
flex: 1;
}
.page {
max-width: 1080px;
margin: 0 auto;
padding: 48px 24px 120px;
}
.page.narrow {
max-width: 760px;
}
.large-title {
font-size: 40px;
line-height: 1.1;
font-weight: 700;
letter-spacing: -0.03em;
margin: 0 0 8px;
}
.title {
font-size: 28px;
line-height: 1.15;
font-weight: 700;
letter-spacing: -0.025em;
margin: 0;
}
.headline {
font-size: 21px;
line-height: 1.24;
font-weight: 600;
letter-spacing: -0.02em;
margin: 0;
}
.subhead {
font-size: 21px;
line-height: 1.38;
color: var(--secondary);
margin: 0;
}
.caption {
font-size: 14px;
color: var(--secondary);
letter-spacing: -0.01em;
}
.section {
margin-top: 56px;
}
.section-head {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 20px;
}
/* ---- controls -------------------------------------------------------------------------------------------------- */
.btn {
--r: 14px;
appearance: none;
border: 0;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
height: 44px;
padding: 0 20px;
font-size: 17px;
font-weight: 500;
white-space: nowrap;
transition: transform 0.12s ease, background 0.2s ease, opacity 0.2s ease;
}
.btn[data-pressed] {
transform: scale(0.97);
}
.btn[data-disabled] {
opacity: 0.4;
cursor: default;
transform: none;
}
/* the keyboard's focus, shown when it's the keyboard that moved it */
[data-focus-visible],
a:focus-visible {
outline: 3px solid color-mix(in srgb, var(--accent) 55%, transparent);
outline-offset: 2px;
}
.btn.primary {
background: var(--accent);
color: var(--accent-text);
}
.btn.secondary {
background: var(--fill);
}
.btn.plain {
background: transparent;
color: var(--accent);
padding: 0 8px;
}
.btn.danger {
background: transparent;
color: var(--danger);
}
.btn.small {
height: 34px;
padding: 0 14px;
font-size: 15px;
--r: 11px;
}
.btn.large {
height: 54px;
padding: 0 28px;
font-size: 19px;
--r: 17px;
}
.icon-btn {
--r: 12px;
width: 40px;
height: 40px;
padding: 0;
background: transparent;
color: var(--secondary);
}
.icon-btn[data-hovered] {
background: var(--fill);
color: var(--text);
}
/* a menu button showing a picture: round, like the picture */
.icon-btn.face {
border-radius: 50%;
}
.icon {
width: 20px;
height: 20px;
flex: none;
}
.field {
display: grid;
gap: 8px;
margin-bottom: 20px;
}
.field-label {
font-size: 15px;
font-weight: 500;
color: var(--secondary);
}
.input,
.textarea {
--r: 14px;
width: 100%;
border: 0;
outline: 0;
background: var(--fill);
padding: 13px 16px;
font-size: 17px;
transition: box-shadow 0.15s ease;
}
.input[data-focused],
.textarea[data-focused] {
box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent);
}
.textarea {
min-height: 140px;
resize: vertical;
line-height: 1.5;
}
.input.big {
font-size: 21px;
padding: 16px 20px;
}
.hint {
font-size: 14px;
color: var(--secondary);
}
.error-text {
color: var(--danger);
font-size: 15px;
}
.segmented {
--r: 11px;
display: inline-flex;
padding: 3px;
background: var(--fill);
gap: 2px;
}
.segment {
--r: 9px;
border: 0;
background: transparent;
height: 32px;
/* (centred whatever the element: a tab is a div, which doesn't centre its text as a button does) */
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 16px;
font-size: 15px;
font-weight: 500;
cursor: pointer;
color: var(--secondary);
}
.segment[data-selected] {
background: var(--surface);
color: var(--text);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}
.chips {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.chip {
border-radius: 999px;
border: 0;
outline: none;
height: 32px;
padding: 0 14px;
font-size: 15px;
background: var(--fill);
color: var(--text);
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
}
.chip[data-selected],
.chip.removable {
background: var(--text);
color: var(--bg);
}
.chip-remove {
border: 0;
background: transparent;
color: inherit;
width: 20px;
height: 20px;
padding: 0;
margin-right: -6px;
display: grid;
place-items: center;
border-radius: 50%;
cursor: pointer;
}
.chip-remove[data-hovered] {
background: rgba(127, 127, 127, 0.3);
}
.tag {
font-size: 13px;
font-weight: 500;
color: var(--secondary);
background: var(--fill);
padding: 3px 10px;
border-radius: 999px;
}
.pill {
font-size: 13px;
font-weight: 600;
padding: 4px 11px;
border-radius: 999px;
color: var(--tone);
background: color-mix(in srgb, var(--tone) 13%, transparent);
white-space: nowrap;
}
/* ---- surfaces -------------------------------------------------------------------------------------------------- */
.card {
background: var(--surface);
box-shadow: var(--shadow);
padding: 28px;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.space-card {
display: grid;
gap: 16px;
transition: transform 0.2s ease;
}
.space-card:hover {
transform: translateY(-2px);
}
.space-icon {
--r: 14px;
width: 56px;
height: 56px;
background: var(--fill);
display: grid;
place-items: center;
font-size: 24px;
font-weight: 600;
overflow: hidden;
flex: none;
}
.space-icon img {
width: 100%;
height: 100%;
object-fit: cover;
}
.space-icon.large {
--r: 22px;
width: 88px;
height: 88px;
font-size: 38px;
}
.list {
background: var(--surface);
box-shadow: var(--shadow);
overflow: hidden;
}
.row {
display: flex;
gap: 20px;
padding: 22px 24px;
align-items: flex-start;
}
.row + .row {
border-top: 1px solid var(--separator);
}
.row-main {
flex: 1;
min-width: 0;
display: grid;
gap: 6px;
}
.row-title {
font-size: 19px;
font-weight: 600;
letter-spacing: -0.02em;
}
.row-excerpt {
color: var(--secondary);
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
font-size: 14px;
color: var(--secondary);
}
.votes {
--r: 14px;
display: grid;
justify-items: center;
min-width: 52px;
padding: 6px 0;
background: var(--fill);
}
.votes.horizontal {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 0 6px;
min-width: 0;
height: 40px;
}
.vote {
border: 0;
background: transparent;
width: 32px;
height: 28px;
display: grid;
place-items: center;
cursor: pointer;
color: var(--secondary);
border-radius: 8px;
}
.vote[data-hovered] {
color: var(--text);
}
.vote.up[data-selected] {
color: var(--accent);
}
.vote.down[data-selected] {
color: var(--declined);
}
.score {
font-weight: 700;
font-size: 17px;
font-variant-numeric: tabular-nums;
}
.avatar {
border-radius: 50%;
background: var(--fill);
object-fit: cover;
flex: none;
display: grid;
place-items: center;
font-weight: 600;
color: var(--secondary);
overflow: hidden;
}
.person {
display: inline-flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.person-name {
font-weight: 600;
color: var(--text);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ---- a discussion ---------------------------------------------------------------------------------------------- */
.body {
font-size: 19px;
line-height: 1.6;
overflow-wrap: anywhere;
}
.body > :last-child,
.reply-body > :last-child {
margin-bottom: 0;
}
.body ul,
.body ol,
.reply-body ul,
.reply-body ol {
margin: 0 0 1em;
padding-left: 1.4em;
}
.body li + li,
.reply-body li + li {
margin-top: 0.3em;
}
.body h3,
.body h4,
.body h5,
.body h6,
.reply-body h3,
.reply-body h4 {
font-size: 1.1em;
font-weight: 650;
margin: 1.4em 0 0.5em;
}
.body blockquote,
.reply-body blockquote {
margin: 0 0 1em;
padding: 2px 0 2px 18px;
border-left: 3px solid var(--separator);
color: var(--secondary);
}
.body pre,
.reply-body pre {
--r: 14px;
font-family: var(--mono);
font-size: 15px;
line-height: 1.5;
background: var(--fill);
border-radius: var(--r);
padding: 16px 18px;
overflow: auto;
margin: 0 0 1em;
}
.body pre code,
.reply-body pre code {
background: none;
padding: 0;
}
.body hr {
border: 0;
border-top: 1px solid var(--separator);
margin: 1.6em 0;
}
.body p {
margin: 0 0 1em;
}
.body code {
font-family: var(--mono);
font-size: 0.88em;
background: var(--fill);
padding: 1px 6px;
border-radius: 6px;
}
.body a {
color: var(--accent);
}
.images {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 12px;
margin-top: 20px;
}
.images img {
--r: 16px;
width: 100%;
aspect-ratio: 4 / 3;
object-fit: cover;
background: var(--fill);
display: block;
}
.image-button {
--r: 16px;
border: 0;
padding: 0;
background: none;
cursor: zoom-in;
}
.status-note {
--r: 18px;
border-left: 0;
background: color-mix(in srgb, var(--tone) 9%, transparent);
padding: 18px 22px;
display: grid;
gap: 6px;
}
.banner {
--r: 16px;
background: var(--fill);
padding: 14px 18px;
display: flex;
align-items: center;
gap: 12px;
color: var(--secondary);
}
.thread {
display: grid;
gap: 4px;
}
.reply {
display: grid;
gap: 8px;
padding: 18px 0;
}
.reply-children {
margin-left: 22px;
padding-left: 22px;
border-left: 2px solid var(--separator);
}
.reply-body {
font-size: 17px;
line-height: 1.55;
overflow-wrap: anywhere;
}
.reply-body p,
.reply-body code {
margin: 0 0 0.7em;
}
.reply-body code {
font-family: var(--mono);
font-size: 0.9em;
background: var(--fill);
padding: 1px 6px;
border-radius: 6px;
}
.reply-actions {
display: flex;
align-items: center;
gap: 4px;
}
.composer {
display: grid;
gap: 12px;
}
/* ---- overlays -------------------------------------------------------------------------------------------------- */
.scrim {
position: fixed;
inset: 0;
z-index: 50;
background: rgba(0, 0, 0, 0.32);
display: grid;
place-items: center;
padding: 24px;
animation: fade 0.2s ease;
}
.scrim[data-exiting] {
animation: fade 0.15s ease reverse;
}
.dialog {
outline: none;
}
.sheet {
--r: 28px;
background: var(--surface);
width: min(620px, 100%);
max-height: calc(100vh - 48px);
overflow: auto;
padding: 32px;
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.24);
animation: rise 0.28s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
.sheet-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
}
.sheet-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 28px;
}
.popover {
--r: 16px;
min-width: 240px;
background: var(--surface);
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.18);
padding: 6px;
outline: none;
}
.popover[data-entering] {
animation: fade 0.12s ease;
}
.popover[data-trigger="ComboBox"] {
width: var(--trigger-width);
}
.menu,
.listbox {
outline: none;
max-height: 320px;
overflow: auto;
}
.menu-item {
--r: 10px;
width: 100%;
border: 0;
background: transparent;
text-align: left;
display: flex;
align-items: center;
gap: 12px;
height: 42px;
padding: 0 12px;
font-size: 16px;
cursor: pointer;
}
.menu-item {
outline: none;
}
.menu-item[data-focused],
.menu-item[data-hovered] {
background: var(--fill);
}
.menu-item.danger {
color: var(--danger);
}
.lightbox {
position: fixed;
inset: 0;
z-index: 60;
background: rgba(0, 0, 0, 0.88);
display: grid;
place-items: center;
cursor: zoom-out;
}
.lightbox .dialog {
outline: none;
}
.lightbox img {
max-width: 92vw;
max-height: 88vh;
border-radius: 12px;
}
.toasts {
position: fixed;
left: 50%;
bottom: 32px;
transform: translateX(-50%);
z-index: 70;
display: grid;
gap: 8px;
}
.toast {
--r: 18px;
background: var(--text);
color: var(--bg);
padding: 14px 22px;
font-size: 16px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.24);
animation: rise 0.28s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
/* ---- states ---------------------------------------------------------------------------------------------------- */
.empty {
text-align: center;
padding: 72px 24px;
display: grid;
gap: 12px;
justify-items: center;
color: var(--secondary);
}
.empty .icon {
width: 44px;
height: 44px;
color: var(--tertiary);
}
.skeleton {
background: linear-gradient(90deg, var(--fill) 0%, var(--fill-strong) 50%, var(--fill) 100%);
background-size: 200% 100%;
animation: shimmer 1.4s ease infinite;
border-radius: 8px;
}
.spinner {
width: 22px;
height: 22px;
border-radius: 50%;
border: 2.5px solid var(--fill-strong);
border-top-color: var(--secondary);
animation: spin 0.8s linear infinite;
}
.badge {
min-width: 20px;
height: 20px;
border-radius: 10px;
background: var(--danger);
color: white;
font-size: 12px;
font-weight: 700;
display: grid;
place-items: center;
padding: 0 6px;
position: absolute;
top: 2px;
right: 2px;
}
.hero {
display: grid;
gap: 20px;
padding: 40px 0 8px;
}
.hero .large-title {
font-size: 56px;
}
.toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;
margin: 32px 0 20px;
}
.search {
--r: 12px;
flex: 1;
min-width: 200px;
display: flex;
align-items: center;
gap: 8px;
background: var(--fill);
padding: 0 14px;
height: 40px;
color: var(--secondary);
}
.search input {
border: 0;
outline: 0;
background: transparent;
flex: 1;
font-size: 16px;
}
.space-head {
display: flex;
gap: 24px;
align-items: center;
}
.stack {
display: grid;
gap: 16px;
}
.inline {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.muted {
color: var(--secondary);
}
@keyframes fade {
from {
opacity: 0;
}
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(16px) scale(0.98);
}
}
@keyframes shimmer {
to {
background-position: -200% 0;
}
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@media (max-width: 640px) {
.page {
padding: 28px 16px 96px;
}
.large-title,
.hero .large-title {
font-size: 34px;
}
.row {
padding: 18px 16px;
gap: 14px;
}
.sheet {
padding: 24px;
}
}
used by