@layer components { /* Column container /* ------------------------------------------------------------------------ */ #main:has(.card-columns) { --main-padding: 0; } .card-columns { --bubble-size: 3.5rem; --cards-gap: min(1.2cqi, 1.7rem); --column-gap: 8px; --column-padding-expanded: calc(var(--column-gap) * 2); --column-transition-duration: 300ms; --column-width-collapsed: 40px; --column-width-expanded: 450px; --progress-increment: var(--progress-max-height) / var(--progress-max-cards); --progress-max-cards: 20; --progress-max-height: 50dvh; container-type: inline-size; display: grid; gap: var(--column-gap); grid-template-columns: 1fr var(--column-width-expanded) 1fr; margin-inline: auto; max-inline-size: var(--main-width); overflow-x: auto; overflow-y: hidden; padding-block-end: var(--column-width-collapsed); position: relative; /* When it has something expanded */ &:has(.card-columns__left .cards:not(.is-collapsed), .card-columns__right .cards:not(.is-collapsed)) { grid-template-columns: auto var(--column-width-expanded) auto; } &:has(.cards) { min-block-size: 20lh; } body:not(.public) & { @media (max-width: 519px) { display: none; } } } .card-columns__left, .card-columns__right { align-items: stretch; display: flex; gap: var(--column-gap); } .card-columns__left { justify-content: end; padding-inline-start: var(--column-gap); } .card-columns__right { justify-content: start; padding-inline-end: var(--column-gap); } /* Column /* ------------------------------------------------------------------------ */ .cards { --column-color: color-mix(in srgb, var(--card-color) 15%, var(--color-canvas)); inline-size: var(--column-width-expanded); outline: none; position: relative; scroll-snap-align: start; &.is-collapsed { inline-size: var(--column-width-collapsed); .pagination-link.pagination-link--active-when-observed, .card { display: none; } } &.drag-and-drop__hover-container { --dnd-bg-color: transparent; --dnd-border-color: transparent; &.is-off-screen { &:after { content: attr(data-column-name); font-size: var(--text-x-small); font-weight: 500; line-height: var(--column-width-collapsed); padding-inline: 1ch; position: fixed; text-transform: uppercase; top: 0; translate: -50%; } &.is-collapsed { &:after { writing-mode: vertical-rl; } } &:not(.is-collapsed) { &:after { background-color: var(--column-color); inline-size: calc(var(--column-width-expanded) - 4px); /* make room for the dnd border */ } } } } @media (any-hover: hover) { .card:has(.card__background img:not([src=""])):hover .card__background img:not([src=""]) { filter: blur(3px) brightness(1.2); opacity: 0.2; } } } .cards__transition-container { block-size: 100%; border-radius: calc(var(--column-width-collapsed) / 2); translate: 0; transition: translate var(--column-transition-duration) var(--ease-out-overshoot-subtle); .is-collapsed:not(.cards--considering) & { translate: 0 var(--column-width-collapsed); } .cards:not(.is-collapsed) & { padding-inline: var(--column-padding-expanded); } .drag-and-drop__hover-container & { --dnd-bg-color: var(--column-color); --dnd-border-color: var(--card-color); background-color: var(--dnd-bg-color); outline: 2px dashed var(--dnd-border-color); outline-offset: -2px; transition: background-color 200ms; z-index: 1; } .no-transitions & { transition: none; } } /* The wrapper around the cards used to clip overflow while transitioning. * Also, don't resize cards while transitioning to avoid reflow. */ .cards__list { align-items: flex-end; /* use flex-start to wipe from left */ display: flex; flex-direction: column; gap: var(--cards-gap); margin-block-start: -1ch; margin-inline: -1ch; overflow: hidden; .cards:not(.is-collapsed) & { padding: 1ch; } .card { inline-size: calc(var(--column-width-expanded) - var(--column-padding-expanded) * 2); } .cards--grid & { display: contents; } [aria-selected] & .card[aria-selected] { outline: var(--focus-ring-size) solid var(--color-selected-dark); outline-offset: var(--focus-ring-offset); @media (prefers-color-scheme: dark) { outline-color: oklch(var(--lch-blue-medium)); } } } .cards__new-column { margin-block-start: var(--column-width-collapsed); } /* Cards grid; used when filtering /* -------------------------------------------------------------------------- */ .cards--grid { --cards-gap: 1rem; --card-grid-columns: 1; container-type: inline-size; display: flex; flex-direction: row; flex-wrap: wrap; gap: var(--cards-gap); justify-content: center; margin-inline: auto; max-inline-size: var(--main-width); @media (min-width: 640px) { --card-grid-columns: 2; } @media (min-width: 960px) { --card-grid-columns: 3; } .card { inline-size: calc((100% - var(--cards-gap) * (var(--card-grid-columns) - 1) ) / var(--card-grid-columns)); } .card__header .card__column-name--current { --btn-padding: 0.1em 0.5em; background: none; border: 1px solid currentColor; color: var(--card-color); display: inline-flex; flex: 0 1 auto; inline-size: fit-content; margin: 0 0 0 auto; } } /* Column Elements /* ------------------------------------------------------------------------ */ .cards__header { .cards.is-collapsed & { block-size: 100%; } .cards:not(.is-collapsed) & { display: grid; grid-template-areas: "menu expander maximize"; grid-template-columns: var(--column-width-collapsed) 1fr var(--column-width-collapsed); margin-block-end: calc(0.5 * var(--cards-gap)); } } .cards__menu .btn--circle, .cards__maximize-button { --btn-background: transparent; block-size: var(--column-width-collapsed); inline-size: var(--column-width-collapsed); opacity: 0; outline-offset: -2px; .cards:hover &, &:focus-visible { opacity: 1; } .cards.is-collapsed & { display: none; } } .cards__menu { z-index: var(--z-popup); } .cards__maximize-button { grid-area: maximize; } .cards__expander { --gradient-direction: to bottom; align-items: center; border-radius: 99rem; cursor: pointer; display: flex; flex-direction: row-reverse; font-size: var(--text-x-small); font-weight: 600; gap: 0.5ch; grid-area: expander; outline-offset: -2px; position: relative; text-transform: uppercase; @media (any-hover: hover) { &:hover { filter: brightness(0.9); } } /* Progress */ &:after { background: linear-gradient(var(--gradient-direction), var(--card-color), var(--column-color) 80%); block-size: var(--column-width-collapsed); border-radius: 99rem; content: ""; inset: 0 0 auto; margin-inline: auto; max-block-size: var(--progress-max-height); min-block-size: var(--column-width-collapsed); opacity: 0; position: absolute; transition: block-size 500ms var(--ease-out-overshoot), inline-size var(--column-transition-duration) ease-out, opacity var(--column-transition-duration) ease-out; z-index: -1; } .no-transitions &:after { transition: none; } .cards.is-collapsed & { block-size: 100%; flex-direction: column; inline-size: var(--column-width-collapsed); justify-content: start; letter-spacing: 0.05em; /* Guitar string */ &:before { background-color: var(--column-color); block-size: 100%; content: ""; inline-size: 1px; inset: 0 auto; position: absolute; z-index: -2; } &:after { block-size: calc(var(--column-width-collapsed) + var(--card-count) * var(--progress-increment)); opacity: 1; inline-size: var(--column-width-collapsed); } } .cards:not(.is-collapsed) & { inline-size: 100%; justify-content: center; } .cards:is(.cards--considering) &:hover { cursor: unset; filter: none; } } .cards__expander-count { line-height: var(--column-width-collapsed); inline-size: var(--column-width-collapsed); .cards:not(.is-collapsed) & { display: none; } } .cards__expander-title { font-weight: inherit; font-size: inherit; line-height: var(--column-width-collapsed); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; .cards.is-collapsed & { max-inline-size: 50vh; writing-mode: vertical-rl; } .cards:not(.is-collapsed, .cards--considering) & { align-items: center; display: flex; gap: 0.25ch; max-inline-size: calc(100% - var(--column-width-collapsed) * 2); } .icon--collapse { --icon-size: 1.15em; opacity: 0; scale: 1.5; transition: 150ms ease-out; transition-property: opacity, scale; .cards.is-collapsed & { display: none; } .cards:not(.is-collapsed) .cards__expander:hover & { opacity: 0.66; scale: 1; } } } .blank-slate--card { box-shadow: none !important; color: color-mix(in srgb, var(--card-color) 70%, var(--color-canvas)); .cards--considering & { background-color: var(--card-bg-color) !important; } p { font-size: var(--text-small); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; &.blank-slate-for-grid { display: none; .cards--grid & { display: initial; } } } } /* TODO: I think this is legacy now? */ .cards__heading { display: flex; font-size: var(--text-medium); inset-block-start: 0; justify-content: center; margin-block-start: 1px; margin-inline: -8px; /* enough to cover card shadows, but avoid overlapping bubbles */ padding-block: var(--cards-gap) 0; position: sticky; z-index: 3; /* Cover bubbles and cards on small viewports */ @media (max-width: 639px) { margin-inline: calc(-1 * var(--cards-gap) - var(--main-padding)); } &, .cards__filter { font-weight: bold; text-transform: uppercase; } .cards__filter { --filter-block-padding: 0.5rem; background-color: var(--color-canvas); border-radius: 99rem; inline-size: auto; margin-block: calc(-1 * var(--filter-block-padding)); padding-block: var(--filter-block-padding); } dialog { font-weight: normal; text-transform: none; } } /* Override card styles within columns /* ------------------------------------------------------------------------ */ .cards { .card { --block-space: 1em; --block-space-half: 0.5em; --card-padding-inline: 1em; --text-xx-large: 1.6em; --text-x-small: 1em; /* Set lower limit for font size */ font-size: clamp(0.6rem, 0.85cqi, 100px); } .card__steps { display: flex; } .card__tags { gap: calc(var(--card-header-space) / 2); } .card__title { pointer-events: none; } .card__link { z-index: 1; } .card__stages, .card__hide-on-index { display: none; } .card__body { padding-block: calc(var(--card-padding-block) * 0.75) var(--card-padding-block); } .card__meta { font-weight: 600; strong, .local-time-value { font-weight: inherit; } } .card:has(.card__background img:not([src=""])) { .card__content, .card__meta, .card__column-name:not(.card__column-name--current) { opacity: 0; transition: opacity 0.2s ease-in-out; @media (any-hover: hover) { .card:hover & { opacity: 1; } } } } .bubble { inset-inline-start: 100%; translate: -90% -40%; } @media (any-hover: hover) { .card:has(.card__background img:not([src=""])):hover .card__background img:not([src=""]) { filter: blur(3px) brightness(1.2); opacity: 0.2; } } } /* Considering /* ------------------------------------------------------------------------ */ .cards--considering { --card-color: oklch(var(--lch-blue-medium)); position: relative; .card { --avatar-size: 2.75em; --text-small: 1.1em; background-color: var(--color-canvas); line-height: 1.2; z-index: 2; @media (min-width: 640px) { --text-xx-large: 1.6em; } } .card__board { background-color: transparent; color: var(--card-content-color); } .card__header { color: var(--color-ink); padding-block-start: calc(var(--card-padding-block) / 2); } .card__tags { color: inherit; } .card__body { padding-block: 0 var(--card-padding-block); } .card__people-label { display: none; } .card__title { min-block-size: 0; } } /* Board tools /* -------------------------------------------------------------------------- */ .board-tools.card { --border-color: var(--color-selected-dark); --border-size: 1px; --card-padding-block: var(--block-space); border: 1px solid var(--border-color); margin-block-end: var(--cards-gap); text-align: center; &:has(dialog[open]) { z-index: 5; } .separator--horizontal { margin-block: var(--block-space); } .btn--link { font-size: 1.2em; } .btn:not(.btn--link, .btn--circle) { border: 0; color: var(--color-link); } footer { font-size: var(--text-x-small); margin-block-end: calc(var(--block-space-half) * -1); } .overflow-count { font-size: 1.2em; font-weight: 500; padding: 0.5em 0.3em; } } .board-tools__watching { --btn-size: 32px; --gap: 0.5ch; display: flex; gap: var(--gap); inline-size: 100%; margin-block: var(--block-space-half); place-content: center; position: relative; } .board-tools__watching-dialog { --panel-padding: 2ch; --panel-size: 100%; display: flex; flex-wrap: wrap; gap: var(--gap); inset-block-start: 0; justify-content: center; position: absolute; z-index: 1; } /* On Deck (Not Now) /* ------------------------------------------------------------------------ */ .cards--closed, .cards--on-deck { --card-color: var(--color-ink-light) !important; .card { --card-color: var(--color-card-complete) !important; } .bubble { display: none !important; } } /* Closed (Done) /* ------------------------------------------------------------------------ */ .cards--closed { } /* Doing /* -------------------------------------------------------------------------- */ /* Surface a mini bubble if there are cards with bubbles inside */ .cards--considering:has(.bubble:not([hidden])), .cards--doing.is-collapsed:has(.bubble:not([hidden])) { .cards__transition-container { --bubble-color: var(--card-color, oklch(var(--lch-blue-medium))); --bubble-shape: 54% 46% 61% 39% / 57% 49% 51% 43%; &:before { background: radial-gradient( color-mix(in srgb, var(--bubble-color) 8%, var(--color-canvas)) 50%, color-mix(in srgb, var(--bubble-color) 48%, var(--color-canvas)) 100% ); block-size: 1em; border-radius: var(--bubble-shape); content: ""; inline-size: 1em; inset: 0 0 auto auto; position: absolute; translate: 20% -20%; z-index: 1; } .cards--considering &:before { inset: 0 auto auto 0; translate: 100% 75%; } } } .cards--considering:has(.bubble:not([hidden])) .cards__expander-title:before { translate: 120% 50%; } /* Card column indicators /* -------------------------------------------------------------------------- */ .card__column-name { --btn-background: transparent; --btn-padding: 0.2em 0.5em; --btn-border-size: 0; --btn-border-radius: 0.2em; color: inherit; inline-size: 100%; justify-content: flex-start; text-transform: uppercase; @media (hover: hover) { &:not(.card__column-name--current):hover { --btn-background: color(from var(--column-color) srgb r g b / 0.15); color: var(--column-color); } } } .card__column-name--current { --btn-background: var(--card-color); color: var(--color-ink-inverted); @media (hover: hover) { &:hover { --btn-background: var(--card-color); } } } /* Mobile columns /* -------------------------------------------------------------------------- */ .mobile-card-columns { --column-gap: 8px; --column-padding-expanded: calc(var(--column-gap) * 2); --column-width-collapsed: 40px; --progress-increment: var(--progress-max-width) / var(--progress-max-cards); --progress-max-cards: 20; --progress-max-width: 100%; padding-inline: 3vw; /* Hide on larger devices with cursors */ @media (min-width: 520px) { display: none; } .cards.is-collapsed { inline-size: auto; display: block; padding-block: 0.5ch; .cards__expander { --gradient-direction: to right; flex-direction: row; inline-size: auto; &:before { block-size: 1px; inline-size: 100%; inset: 50% 0 auto; translaate: 0 -50%; } &:after { block-size: var(--column-width-collapsed); inline-size: calc(var(--column-width-collapsed) + var(--card-count) * var(--progress-increment)); margin-inline-start: 0; max-inline-size: var(--progress-max-width); } } .cards__expander-title { writing-mode: revert; } } } }