@layer components { /* Container /* ------------------------------------------------------------------------ */ .tray { --tray-duration: 350ms; --tray-margin: 0.5rem; --tray-radius: 0.25rem; --tray-item-height: 76px; /* FIXME: Magic number */ align-items: end; block-size: var(--footer-height); display: grid; inset-block: auto env(safe-area-inset-bottom); inline-size: var(--tray-size); position: fixed; transition: inset var(--tray-duration) var(--ease-out-overshoot-subtle); 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(--ease-out-overshoot-subtle); 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: calc(var(--footer-height) - 0.75ch); } &:not([open]) { block-size: var(--footer-height); pointer-events: none; /* On desktop, when there aren't items, tweak the hat so it doesn't look like it's coming from the bottom of the viewport */ @media (min-width: 800px) { &:not(:has(.tray__item--notification)) { .tray__item--hat { margin-block-end: 0; opacity: 0; } } } } } /* Expander /* ------------------------------------------------------------------------ */ .tray__toggle { align-self: stretch; background: none; border: 0; display: block; padding: 0; transition: opacity 100ms ease-out; .icon { color: var(--color-ink); display: none; } @media (max-width: 799px) { /* When collapsed on mobile, make it small */ .tray__dialog:not([open]) ~ & { inline-size: var(--footer-height); .tray__toggle-btn { border: 0; } .icon { display: block; } .tray__toggle-text { display: none; } } /* Show a red dot if there are items to show */ .tray__dialog:not([open]):has(.tray__item--notification) ~ &: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… */ @media (min-width: 800px) { /* Hide the UI when collapsed, but only if there are items */ .tray__dialog:not([open]):has(.tray__item--notification) ~ & { opacity: 0; } } } .tray__toggle-btn { --btn-background: transparent; --btn-border-size: 0; --btn-color: var(--color-ink); inline-size: 100%; opacity: 0.66; } /* Item /* ------------------------------------------------------------------------ */ .tray__item { --tray-item-delay: calc((var(--tray-item-index) - 1) * 20ms); --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(--ease-out-overshoot-subtle); transition-delay: var(--tray-item-delay); transition-property: margin, opacity, scale; &:not(.tray__item--hat) { z-index: var(--tray-item-z); } &:has(*:focus-visible) { z-index: calc(var(--tray-item-z) + 1); } &: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--hat { --tray-hat-bg: var(--color-canvas); --tray-item-scale: 1; background-color: var(--tray-hat-bg); border-block-end: 1px solid var(--color-ink-lighter); border-radius: var(--tray-radius) var(--tray-radius) 0 0; block-size: var(--tray-item-height); display: flex; opacity: 0; padding: 0.5ch; .btn { --btn-background: var(--tray-hat-bg); --btn-border-radius: 0.5ch; --btn-padding: 1.25ch 0.5ch 1ch; block-size: 100%; display: flex; flex-direction: column; font-weight: normal; gap: 0.25ch; inline-size: 100%; &:focus-visible { z-index: 1; } @media (max-width: 1060px) { > span:not(.icon) { font-size: 12px; } } .tray__dialog:not([open]) & { pointer-events: none; } } > *:is(:first-child, :last-child) { inline-size: 128px; } .tray__dialog[open] & { opacity: 1; } .tray__new-notifications { display: none; position: relative; } .tray__dialog:has(.tray__item:nth-child(1n + 7)) & { .tray__old-notifications { display: none; } .tray__new-notifications { display: flex; } .btn:has(.tray__new-notifications) { /* Red dot */ &:after { background-color: oklch(var(--lch-red-medium)); block-size: 1ch; border-radius: 50%; box-shadow: 0 0 0 1px var(--tray-hat-bg); content: ""; inline-size: 1ch; inset: 25% auto auto 50%; position: absolute; translate: 25% -75%; } } } } /* 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.2em; 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; #footer:has(.bar__placeholder[hidden]) & { inset-inline-start: -100%; } .tray__item { --tray-item-z: calc(10 - var(--tray-item-index)); position: relative; [open] &[aria-selected] { outline: 0; z-index: calc(var(--tray-item-z) + 2); .card__link { border-radius: 0.25ch; outline: var(--focus-ring-size) solid var(--focus-ring-color); outline-offset: var(--focus-ring-offset); z-index: 1; } } /* Show 6 max items on smallest devices */ @media (max-height: 578px) { &:nth-child(1n + 7) { display: none; } } /* 7 max */ @media (min-height: 578px) and (max-height: 656px) { &:nth-child(1n + 8) { display: none; } } /* 8 max */ @media (min-height: 656px) and (max-height: 734px) { &:nth-child(1n + 9) { display: none; } } /* 9 max */ @media (min-height: 734px) and (max-height: 812px) { &:nth-child(1n + 10) { display: none; } } /* 10 max on larger screens */ @media (min-height: 812px) { &:nth-child(1n + 11) { display: none; } } &:not([aria-selected]) .card__link:focus-visible, .tray__dialog:not([open]) & .card__link:focus-visible { --focus-ring-size: 0; } } .tray__remove-pin-btn { --btn-icon-size: 1.25em; --btn-size: 2em; background-color: var(--card-bg-color); inset: 0 0 auto auto; opacity: 0; pointer-events: none; position: absolute; z-index: 1; .tray__dialog[open] & { opacity: 0.66; pointer-events: unset; &:hover { opacity: 1; } } } .avatar, .card__tags, .card__meta .btn, .card__meta-text:not(.card__meta-text--updated), .card__stages, .card__steps, .card__closed { display: none; } .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__body { display: block; margin-block-start: 0.3em; } .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; transition: translate 150ms ease-out; [open] & { translate: -2em; } } .card__link { z-index: 1; } .card__footer { margin-block: -0.2em 2em; .icon { display: none; } } .card__meta { grid-template-areas: "text-updated"; grid-template-columns: 1fr; } .card__meta-text { line-height: 1.5; } .card__meta-text--updated { border: 0; font-size: var(--text-x-small); opacity: 0.66; padding: 0; text-transform: none; .local-time-value { font-weight: normal; } } .card__bubble { display: none; } /* Disable the expander if there aren't items to show */ .tray__dialog:not(:has(.tray__item)) ~ .tray__toggle { opacity: 0.5; &, .tray__toggle-btn { pointer-events: none; } } /* Add a border on mobile */ @media (max-width: 799px) { .tray__dialog:not([open]) ~ .tray__toggle { border-inline-end: 1px dashed var(--color-ink-light); translate: calc(-1 * var(--tray-margin)) 0; } } } /* Notification-specific styles /* ------------------------------------------------------------------------ */ .tray--notifications { inset-inline: auto var(--tray-margin); #footer:has(.bar__placeholder[hidden]) & { inset-inline-end: -100%; } .tray__item, [data-navigable-list-target~=item] { [open] &[aria-selected] { outline: 0; z-index: calc(var(--tray-item-z) + 2); .card, .tray__item--hat & .btn { border-radius: 0.25ch; outline: var(--focus-ring-size) solid var(--focus-ring-color); outline-offset: var(--focus-ring-offset); } } &:nth-child(1n + 7) { display: none; pointer-events: none; visibility: hidden; } &:not([aria-selected]) .card:focus-visible, .tray__dialog:not([open]) & .card:focus-visible { --focus-ring-size: 0; } .btn:focus-visible { outline: 0; } } &: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__dialog:not([open]) ~ .tray__toggle { border-inline-start: 1px dashed var(--color-ink-light); translate: var(--tray-margin) 0; } } } }