@layer components { /* Container /* ------------------------------------------------------------------------ */ .tray { --tray-duration: 350ms; --tray-margin: 0.5rem; --tray-radius: 0.25rem; --tray-timing-function: cubic-bezier(0.25, 1.25, 0.5, 1); align-items: end; block-size: var(--footer-height); display: grid; inset-block: auto 0; inline-size: var(--tray-size); position: fixed; z-index: var(--z-tray); /* Make the dialog, expander, and actions inhabit the same space */ > * { grid-column-start: 1; grid-row-start: 1; } @media (max-width: 799px) { &:has(.tray__dialog[open]) { background-color: var(--color-terminal-bg); inline-size: calc(100% - var(--tray-margin) * 2); inset-inline-start: var(--tray-margin); z-index: calc(var(--z-tray) + 2); } } } /* Dialog /* ------------------------------------------------------------------------ */ .tray__dialog { background-color: transparent; display: flex; flex-direction: column-reverse; inline-size: auto; inset: auto 0 0 0; position: absolute; transition: var(--tray-duration) var(--tray-timing-function); transition-property: background-color, box-shadow, inset-block-end; &[open] { border-radius: var(--tray-radius); box-shadow: 0 0 0 1px var(--color-ink-lighter), 0 0 16px oklch(var(--lch-black) / 33%); inset-block-end: var(--footer-height); } &:not([open]) { block-size: var(--footer-height); pointer-events: none; } } /* Expander /* ------------------------------------------------------------------------ */ .tray__expander { --hover-size: 0; --outline-size: 0; align-self: stretch; background: transparent; border: 0; display: grid; margin-block: calc(var(--block-space) * -1) var(--block-space-half); place-content: center; z-index: calc(var(--z-tray) + 1); .icon { color: var(--color-white); display: none; } .tray__dialog[open] ~ & { display: none; } /* On mobile, add an icon to the expander button */ @media (max-width: 799px) { inline-size: var(--footer-height); margin: 0; .icon { display: block; } /* Show a red dot if there are items to show */ .tray__dialog:has(.tray__item:not(.tray__item--overflow)) ~ &:after { background: oklch(var(--lch-red-medium)); block-size: 1ch; border-radius: 50%; content: ""; inline-size: 1ch; inset: 25% 25% auto auto; position: absolute; } } /* On desktop, hide if there aren't any items to show */ @media (min-width: 800px) { .tray__dialog:not(:has(.tray__item:not(.tray__item--overflow))) ~ & { display: none } } } /* Actions /* ------------------------------------------------------------------------ */ .tray__actions { --hover-size: 0; align-self: center; align-items: stretch; border: 1px dashed oklch(var(--lch-white) / 50%); border-radius: 0.5em; color: var(--color-ink-inverted); display: flex; gap: var(--inline-space-half); opacity: 0; transition: translate var(--tray-duration) var(--tray-timing-function); translate: 0 var(--footer-height); /* Get the circle buttons to be full-height without magic numbers */ form { aspect-ratio: 1; .btn { block-size: 100%; inline-size: 100%; } } .btn { opacity: 0.66; &:hover, &:focus-visible { opacity: 1; } } .tray__dialog[open] ~ & { opacity: 1; translate: 0 0; } /* On desktop, show actions when there aren't items */ @media (min-width: 800px) { .tray__dialog:not(:has(.tray__item:not(.tray__item--overflow))) ~ & { opacity: 1; translate: 0 0; } } @media (prefers-color-scheme: dark) { .btn--reversed { color: var(--color-ink); } } } /* Item /* ------------------------------------------------------------------------ */ .tray__item { --tray-item-delay: calc((var(--tray-item-index) - 1) * 20ms); --tray-item-height: 76px; /* FIXME: Magic number */ --tray-item-index: 1; --tray-item-margin: calc(-1 * var(--tray-item-height) + var(--tray-item-offset)); --tray-item-offset: var(--block-space-half); /* The amount they overlap */ --tray-item-scale: calc(1 - (var(--tray-item-index) - 1) / 30); --tray-item-z: calc(6 - var(--tray-item-index)); position: relative; .tray__dialog & { font-size: 10px; margin-block-end: var(--tray-item-margin); transition: var(--tray-duration) var(--tray-timing-function); transition-delay: var(--tray-item-delay); transition-property: margin, scale; z-index: var(--tray-item-z); &:first-child { --tray-item-margin: var(--tray-margin); } &:not(:first-child) { scale: var(--tray-item-scale); } &:nth-child(1) { --tray-item-index: 1; } &:nth-child(2) { --tray-item-index: 2; } &:nth-child(3) { --tray-item-index: 3; } &:nth-child(4) { --tray-item-index: 4; } &:nth-child(5) { --tray-item-index: 5; } &:nth-child(6) { --tray-item-index: 6; } &:nth-child(7) { --tray-item-index: 7; } &:nth-child(8) { --tray-item-index: 8; } &:nth-child(9) { --tray-item-index: 9; } &:nth-child(10) { --tray-item-index: 10; } } .tray__dialog[open] & { --tray-item-margin: 0; --tray-item-scale: 1; } .tray__dialog:not([open]) & { @media (max-width: 799px) { opacity: 0; } } .bubble { display: none; } } .tray__item--overflow { --tray-item-index: 7 !important; --tray-item-z: 1; display: none; opacity: 0; .card { align-items: center; background-color: var(--color-canvas); font-size: var(--text-small); font-weight: bold; justify-content: center; } /* Only show when there are 7+ items */ .tray__dialog:has(.tray__item:nth-child(7)) & { display: flex; } .tray__dialog[open] & { --tray-item-scale: 1; opacity: 1; } } /* Tray cards /* ------------------------------------------------------------------------ */ .tray { .card { --card-padding-block: 1.5ch; --card-padding-inline: 1.5ch; --text-xx-large: 2em; block-size: var(--tray-item-height); view-transition-name: unset !important; [open] & { box-shadow: 0 0 0 1px var(--color-ink-lighter); border: 0; border-radius: 0; } @media (prefers-color-scheme: dark) { box-shadow: 0 0 0 1px var(--color-ink-lighter); } } .card__background { display: none; } .card__body { margin-block-start: -0.3em; padding-block-end: 0; } .card__collection { padding-block: 0.25ch; } .card__title { --lines: 1; font-size: var(--text-small); font-weight: bold; min-block-size: 0; } } /* Pin-specific styles /* ------------------------------------------------------------------------ */ .tray--pins { inset-inline: var(--tray-margin) auto; .tray__item { --tray-item-z: calc(10 - var(--tray-item-index)); &:nth-child(1n + 11) { display: none; } } .avatar, .card__tags, .card__meta .btn, .card__meta-item:not(.card__meta-item--updated), .card__stages, .card__closed { display: none; } .card__body { display: block; margin: 0; } .card__footer { margin-block: -0.2em 2em; } .card__header { margin-block-start: calc(var(--card-padding-block) * -1.1); margin-inline: calc(-1 * var(--card-padding-inline)); max-inline-size: unset; } .card__meta-grid { margin-inline-start: 0; } .card__link { z-index: 1; } .card__meta-item--updated { border: 0; font-size: var(--text-x-small); opacity: 0.66; padding: 0; text-transform: none; .local-time-value { font-weight: normal; } } .workflow-stage--current { --btn-padding: 0.1em 0.5em; background: none !important; border: 1px solid currentColor; color: var(--color-ink); display: inline-flex; flex: 0 1 auto; inline-size: fit-content; margin: 0 0 0 auto; } .card__bubble { display: none; } /* On mobile… */ @media (max-width: 799px) { /* …add a border */ .tray__expander { border-inline-end: 1px dashed oklch(var(--lch-white) / 50%); translate: calc(-1 * var(--tray-margin)) 0; } /* …and disable the expander if there aren't items to show */ .tray__dialog:not(:has(.tray__item:not(.tray__item--overflow))) ~ .tray__expander { pointer-events: none; .icon { opacity: 0.5; } } } /* On desktop, don't expand if there's only one pin */ @media (min-width: 800px) { .tray__dialog:has(.tray__item:only-child) { pointer-events: unset; ~ .tray__expander { display: none; } } } } /* Notification-specific styles /* ------------------------------------------------------------------------ */ .tray--notifications { inset-inline: auto var(--tray-margin); .tray__item:nth-child(1n + 7) { display: none; } &:not(:has(.card--notification)) { .tray__notification-read-action { visibility: hidden; } } .card__notification-unread-indicator { --btn-icon-size: 1.25em; --btn-size: 2em; } /* On mobile… */ @media (max-width: 799px) { /* …add a border */ .tray__expander { border-inline-start: 1px dashed oklch(var(--lch-white) / 50%); translate: var(--tray-margin) 0; } /* …and hide the dialog if there aren't items to show */ .tray__dialog:not(:has(.tray__item:not(.tray__item--overflow))) { display: none; } } } }