Files
upstream-zulip/web/styles/popovers.css
upstream-mirror 64898b2c79
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
2026-09-15 15:05:30 +05:00

1480 lines
38 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
Our Tippy popovers use the strangely named "light-border" Tippy
theme, so this block defines the common styling for all of our Tippy
popovers. (Tippy tooltips are defined in tooltips.css).
*/
.tippy-box[data-theme="light-border"] {
background-color: var(--color-background-popover);
/* Basic Tippy popovers scale with the base font-size. */
font-size: var(--base-font-size-px);
.tippy-content {
/* We set the font-size here to override the
default value in the upstream tippy.css */
/* 14px at 14px/1em */
font-size: 1em;
}
/* TODO: Clean this logic up after drop Bootstrap styling */
& hr {
/* Override bootstrap defaults */
margin: 5px 0;
}
&[data-placement^="top"] {
> .tippy-arrow {
&::before {
border-top-color: var(--color-background-popover);
}
}
}
&[data-placement^="bottom"] {
> .tippy-arrow {
&::before {
border-bottom-color: var(--color-background-popover);
}
}
}
&[data-placement^="left"] {
> .tippy-arrow {
&::before {
border-left-color: var(--color-background-popover);
}
}
}
&[data-placement^="right"] {
> .tippy-arrow {
&::before {
border-right-color: var(--color-background-popover);
}
}
}
}
.tippy-box[data-theme="dropdown-widget"] {
border-radius: 6px;
background-color: var(--color-background-dropdown-widget);
border: 1px solid var(--color-border-dropdown-widget);
box-shadow:
0 7px 13px light-dark(hsl(0deg 0% 0% / 15%), hsl(0deg 0% 0% / 35%)),
0 5px 8px light-dark(hsl(0deg 0% 0% / 12%), hsl(0deg 0% 0% / 32%)),
0 2px 4px light-dark(hsl(0deg 0% 0% / 10%), hsl(0deg 0% 0% / 20%));
/* Tippy dropdown widgets scale with the base font-size. */
font-size: var(--base-font-size-px);
.tippy-content {
/* We set the font-size here to override the
default value in the upstream tippy.css */
/* 14px at 14px/1em */
font-size: 1em;
color: hsl(0deg 0% 75%);
padding: 0;
}
> .tippy-arrow {
color: var(--color-background-dropdown-widget);
}
}
.tippy-box[data-theme="popover-menu"] {
background-color: var(--color-background-popover-menu);
border: 1px solid var(--color-border-popover-menu);
border-radius: 6px;
box-shadow: var(--box-shadow-popover-menu);
font-size: 1.0714em; /* 15px at 14px em */
> .tippy-content {
padding: 0;
/* We set the font-size here to override the
default value in the upstream tippy.css */
/* 15 at 15px/1em */
font-size: 1em;
}
> .tippy-arrow {
color: var(--color-background-popover-menu);
}
&[data-placement^="top"] > .tippy-arrow::before {
bottom: var(--popover-tippy-arrow-before-offset);
}
&[data-placement^="bottom"] > .tippy-arrow::before {
top: var(--popover-tippy-arrow-before-offset);
}
&[data-placement^="left"] > .tippy-arrow::before {
right: var(--popover-tippy-arrow-before-offset);
}
&[data-placement^="right"] > .tippy-arrow::before {
left: var(--popover-tippy-arrow-before-offset);
}
}
.giphy-popover .tippy-box .tippy-arrow {
/* Since the GIPHY banner at the popover is black,
match the arrow color with the banner. */
color: hsl(0deg 0% 0%);
}
.tippy-box[data-theme="popover-menu"]:has(#gear-menu-dropdown) {
--box-shadow-popover-menu: var(--box-shadow-gear-menu);
}
.user_full_name {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.user-card-popover-actions {
--color-text-item: var(--color-text-user-card-secondary);
.user-card-popover-bot-owner-field {
&.text-item {
align-items: center;
white-space: nowrap;
}
.pill-container {
border: none !important;
}
.pill {
border: none;
text-decoration: none;
color: var(--color-text-popover-menu);
background-color: var(--color-background-text-direct-mention);
&:hover {
color: var(--color-text-popover-menu);
background-color: var(
--color-background-text-hover-direct-mention
);
text-decoration: none;
}
}
}
.pill-container {
padding: 0;
}
.custom-profile-field-value {
display: flex;
align-items: center;
gap: 5px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.custom-profile-field-value.rendered_markdown p {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
/* Overriding CSS from rendered_markdown.css */
margin: 0;
}
.custom-profile-field-link {
color: var(--color-text-item);
&:hover {
text-decoration: none;
}
&:focus-visible {
color: var(--color-text-url-hover);
outline: 1px solid var(--color-outline-focus) !important;
outline-offset: 2px;
border-radius: 2px;
}
.custom-profile-field-text {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
&:hover {
text-decoration: underline;
}
}
}
}
.custom-user-url-field,
.external-account-text-field {
display: flex;
align-items: center;
/* Maintain space between URL and copy icon. */
gap: 3px;
overflow: hidden;
.custom-profile-fields-link {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.copy-custom-field-url,
.copy-external-account-field {
height: 1em;
}
}
.external-account-link-field {
display: inline-flex;
align-items: center;
/* Maintain space between icon and text. */
gap: 3px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.hidden-remove-button {
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.hidden-remove-button:has(.button-loading-indicator) {
cursor: default;
opacity: 1;
}
.hidden-remove-button-row:hover
.hidden-remove-button:not(:has(.button-loading-indicator)),
.hidden-remove-button-row:focus-within
.hidden-remove-button:not(:has(.button-loading-indicator)) {
opacity: 1;
pointer-events: auto;
}
.hidden-remove-button:focus-visible {
opacity: 1;
/* TODO: We need to consolidate icon-button outline to this
outline color and separately define outline colors to specific
elements if needed. We should remove this after that. */
outline: 1px solid var(--color-outline-focus) !important;
outline-offset: -2px;
}
#stream-actions-menu-popover,
#stream-card-popover {
.popover-stream-name {
font-weight: 600;
color: var(--color-text-popover-menu);
line-height: 1.1;
}
.popover-stream-name,
.stream-privacy.filter-icon {
margin-top: 4px;
}
.zulip-icon-lock {
/* Override the margin-top set on the stream lock icon
at the top-level, since we don't need to pull up this
icon for the stream actions popover header. */
margin: 0 !important;
}
.popover-stream-info-menu-description {
color: var(--color-text-popover-menu);
}
}
#topic-actions-menu-popover {
.popover-topic-name {
font-weight: 600;
color: var(--color-text-popover-menu);
line-height: 1.1;
margin-top: 4px;
white-space: pre-wrap;
min-width: 12.5em; /* 200px at 16px/1em */
}
}
.popover-header-name {
font-weight: 600;
color: var(--color-text-popover-menu);
line-height: 1.1;
margin-top: 4px;
width: max-content;
}
.popover-group-menu-info {
display: flex;
flex-direction: column;
gap: 5px;
padding: 3px var(--user-group-popover-horizontal-padding);
}
.popover-group-menu-name-container {
display: flex;
align-items: flex-start;
gap: 5px;
/* 18px at 15px/1em */
font-size: 1.2em;
font-weight: 600;
/* 20px at 18px/1em */
line-height: 1.1111em;
color: var(--color-text-full-name);
overflow-wrap: anywhere;
}
.popover-group-menu-description {
/* 15px at 15px/1em */
font-size: 1em;
/* 16px at 15px/1em */
line-height: 1.0667em;
}
ul.popover-group-menu-member-list {
max-height: 300px;
display: flex;
flex-direction: column;
.simplebar-content {
display: grid;
grid-template-areas: "group-member-icon gap group-member-name";
grid-template-columns:
max-content var(--user-group-popover-icon-text-gap)
minmax(0, 1fr);
width: unset;
}
.popover-group-menu-member {
display: grid;
grid-template-columns: subgrid;
grid-column: 1 / -1;
align-items: center;
padding: 0 var(--user-group-popover-horizontal-padding);
}
.popover-group-member-icon {
justify-self: center;
grid-area: group-member-icon;
}
.popover-group-menu-member-name {
grid-area: group-member-name;
}
}
.popover-group-menu-placeholder {
padding: 0 var(--user-group-popover-horizontal-padding);
}
.popover-group-menu-member {
.zulip-icon-user-group {
color: var(--color-icon-purple);
}
}
.popover-group-menu-member-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.popover-group-menu-description,
.popover-group-menu-member-name,
.popover-group-menu-placeholder {
color: var(--color-text-popover-menu);
}
.user-status-icon-wrapper {
display: flex;
}
.popover-group-menu-user-presence {
/* 11px at 16px/1em */
font-size: 0.6875em;
}
.user_profile_presence {
/* Remove font-size to allow this to scale
with the menu header text. Declaring font-size
here maintains the legacy design of keeping
the user-circle smaller, despite the larger
surrounding text and icons. */
font-size: calc(var(--base-font-size-px) * 0.6666);
line-height: 1;
}
.popover-avatar {
height: 240px;
width: 240px;
background-size: cover;
background-position: center;
position: relative;
&.guest-avatar::after {
outline: 10px solid hsl(0deg 0% 100%);
}
.popover-inner {
width: 240px;
}
}
@media (width < $md_min) {
.popover-flex {
position: absolute;
top: 0 !important;
left: 0 !important;
width: 100vw;
height: 100vh;
display: flex !important;
justify-content: center;
align-items: center;
background-color: hsl(0deg 0% 0% / 70%);
/* Needs to be higher than the 105 for div.overlay so that the
emoji picker can render on top of the user status picker. */
z-index: 106;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
&.fade.in {
opacity: 1;
pointer-events: all;
}
}
.emoji-picker-popover {
position: static;
margin-right: 0;
}
}
.popover.top .arrow::after {
left: -1px;
}
.gif-picker-popover,
.emoji-popover-root {
.tippy-content {
/* We remove the default padding from this container
as it is not necessary for the Giphy and Tenor popovers. */
padding: 0;
/* By resetting to the default color from the `body`,
we can ignore the colors applied from `tippy-box`. */
color: var(--color-text-default);
}
}
.emoji-popover-root {
/* The emoji popover has a different background color for the
header and footer, so we customize the arrow to match this color. */
.tippy-box[data-placement="top"] .tippy-arrow::before {
border-top-color: var(--color-border-emoji-picker-tippy-arrow);
}
.tippy-box[data-placement="bottom"] .tippy-arrow::before {
border-bottom-color: var(--color-border-emoji-picker-tippy-arrow);
}
.tippy-box[data-placement="left"] .tippy-arrow::before {
border-left-color: var(--color-border-emoji-picker-tippy-arrow);
}
}
.modal__overlay #set-user-status-modal + .emoji-popover-root {
/* Micromodal prevents pointer events to elements outside the content.
We need to re-enable pointer events for the emoji popover to work. */
pointer-events: auto;
}
.gif-grid-in-popover {
/* Anchor resize handles to this element's padding box so they
stay inside the popover. */
position: relative;
/* So width / min-width / max-width refer to the total visible
box, including the handle-size padding added below; the viewport
safe-margin caps then compare apples-to-apples. */
box-sizing: border-box;
/* Initial width: four columns. On narrow viewports, `max-width`
caps this at what fits. Users can drag between one and five
columns. */
width: calc(
4 * var(--gif-picker-gif-column-min-width) + 3 *
var(--gif-picker-gif-column-gap) +
var(--gif-picker-grid-horizontal-chrome)
);
height: 70dvh;
min-width: var(--gif-picker-grid-min-width);
min-height: var(--gif-picker-grid-min-height);
max-width: var(--gif-picker-grid-max-width);
max-height: var(--gif-picker-grid-max-height);
/* On mobile devices (userAgent-based, see gif_picker_ui.ts), fill
the viewport and drop the handle-size padding since resize is
disabled. Gating on device class rather than viewport width
lets a desktop user on a narrow window keep the resizable
picker. */
&.is-mobile-device {
width: calc(100vw - 2 * var(--gif-picker-viewport-safe-margin));
height: calc(100dvh - 2 * var(--gif-picker-viewport-safe-margin));
min-width: 0;
min-height: 0;
max-width: none;
max-height: none;
padding: 0;
}
border: 0;
/* Reserve a strip equal to the resize handle size on every side
so the handles don't overlap clickable GIFs, the search input,
or the inner scrollbar. */
padding: var(--resizable-box-handle-size);
.gif-search-container {
margin: 4px 4px 2px;
}
.no-results {
font-style: italic;
color: var(--color-text-default);
grid-column: 1 / -1;
text-align: center;
}
.gif-picker-content {
display: grid;
/* Reflow to more columns as the picker enlarges, using the
same min column width as the container resize bounds. */
grid-template-columns: repeat(
auto-fit,
minmax(var(--gif-picker-gif-column-min-width), 1fr)
);
grid-auto-rows: auto;
gap: var(--gif-picker-gif-column-gap);
@media (width < $md_min) {
/* Allow narrower columns on mobile so two can fit on a phone. */
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
/* Meant to prevent outline overflow when the GIF
is focused. */
padding: 0 2px;
}
.gif-picker-gif {
cursor: pointer;
width: 100%;
height: 100%;
border-radius: 10px;
object-fit: cover;
&:focus {
/* Blue outline for clear visibility
* of which image is in focus.
*/
outline: 2px solid var(--color-selected-gif-in-grid-picker);
}
&:hover {
outline: 2px solid var(--color-hovered-gif-in-grid-picker);
}
}
.popover-inner {
/* Fill .gif-grid-in-popover so the scrolling container takes
the space left over after the search input. */
height: 100%;
display: flex;
flex-direction: column;
.gif-scrolling-container {
flex: 1 1 auto;
/* `min-height: 0` lets this flex item shrink below its
content's intrinsic height, so the scroll area can
be shorter than the grid it contains. */
min-height: 0;
/* SimpleBar's `.simplebar-wrapper` uses `height: inherit`
to pick up its host's *computed* height; when the host
is `height: auto` (the default on a flex item),
SimpleBar falls back to an "auto height" mode that
disables its internal scroll. Setting `height: 100%`
here gives the wrapper a resolvable percentage instead,
so SimpleBar drives scrolling against the flex-computed
height. SimpleBar also reads this element's `overflow-y`
and suppresses its own scrollbar if it's `hidden`, so
we use `overflow: hidden auto` to allow Y scrolling while
still blocking any horizontal overflow. */
height: 100%;
overflow: hidden auto;
margin: 2px 3px;
padding: 5px 0;
}
}
.popover-footer {
/* We center the attribution image with flex so it doesn't
pick up a baseline descender gap, and set flex-shrink: 0 so
the flex layout on `.popover-inner` can't squeeze the
footer below the image's own height. */
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
background-color: hsl(0deg 0% 0%);
/* The border radius corresponds to the default radius value from `tippy-box`. */
border-radius: 0 0 4px 4px;
/* The GIPHY image is 200×42 natural, rendered at 120px wide
(so ~25px tall); 34px gives the image a little breathing
room and keeps the footer from collapsing before the image
has loaded. */
min-height: 34px;
& img {
width: 120px;
}
}
}
#message_report_modal,
#move_topic_modal {
/* Modals have a 16px/1em base font-size. */
& form {
margin: 0;
}
.modal_select {
width: auto;
max-width: 100%;
}
#report_type_options_widget_wrapper,
#move_topic_to_stream_widget_wrapper {
display: flex;
/* 230px at 16px/1em */
max-width: 14.375em;
.dropdown-widget-button {
outline: none;
/* 24px at 16px/1em */
line-height: 1.5em;
width: 100%;
}
.dropdown_widget_value {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--color-text-default);
}
.zulip-icon-chevron-down {
padding-left: 5px;
color: hsl(0deg 0% 58%);
font-weight: lighter;
}
}
#move-topic-new-topic-input-wrapper {
position: relative;
display: grid;
/* 30px at 16px/1em */
grid-template:
"move-topic-input clear-topic" auto / minmax(0, 1fr)
1.875em;
& input.move_messages_edit_topic {
grid-column: move-topic-input-start / clear-topic-end;
grid-row: move-topic-input;
/* 30px at 16px/1em */
padding-right: 1.875em;
margin-bottom: unset;
box-sizing: border-box;
width: 100%;
height: auto;
/* Unset max-width set using modal_text_input selector as box-sizing
is set to border-box here and we already set width to 100%. */
max-width: unset;
&.empty-topic-display::placeholder {
color: inherit;
}
&.empty-topic-only {
cursor: default;
}
&.invalid-topic-input {
border-color: var(--color-invalid-input-border);
box-shadow: var(--invalid-input-box-shadow);
}
}
}
.move-topic-new-topic-placeholder {
position: absolute;
left: 6px;
right: 6px;
top: 50%;
transform: translateY(-50%);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
pointer-events: none;
visibility: hidden;
}
.move-topic-new-topic-placeholder-visible {
visibility: visible;
}
#message_move_select_options {
width: 100%;
}
#move_messages_count {
/* Disabled pending fixes to the logic. */
display: none;
}
.topic_stream_edit_header {
#select_stream_id {
border-left: 0;
padding-left: 0;
border-radius: 3px;
margin: 0 5px 5px -10px;
text-indent: 10px;
}
.dropdown-menu {
position: fixed;
top: 125px;
left: 40px;
}
}
.topic_move_breadcrumb_messages {
margin: 0 5px 5px 0;
align-self: center;
width: 100%;
& label.checkbox {
/* Place the checkboxes on their own lines. */
display: block;
& input {
margin: 0;
vertical-align: baseline;
}
& + label.checkbox {
margin-top: 10px;
}
}
& label {
display: inline-block;
margin-right: 10px;
}
}
.new-topic-name-error {
color: hsl(0deg 100% 50%);
}
}
#language_selection_modal {
width: min(750px, 70vw);
}
.default_language_modal_table {
column-count: 3;
@media (width < $md_min) {
column-count: 2;
}
@media (width < $sm_min) {
column-count: 1;
}
}
#send_later_popover {
& hr {
margin: 5px 0;
}
}
.visibility-policy-popover {
.popover-menu-list {
padding: 2px;
}
}
.recipient-bar-topic-visibility-switcher {
.tab-option-content {
/* 15px at 16px/1em */
font-size: 0.9375em;
color: var(--color-text-popover-menu);
gap: 10px;
justify-content: flex-start;
padding: 2px 13px;
}
}
.popover-menu-user-header {
display: flex;
flex-flow: row nowrap;
gap: 7px;
text-align: left;
padding: 4px;
.popover-menu-user-avatar-container {
position: relative;
flex-shrink: 0;
width: var(--length-user-popover-menu-avatar);
height: var(--length-user-popover-menu-avatar);
}
.popover-menu-user-avatar {
width: var(--length-user-popover-menu-avatar);
height: var(--length-user-popover-menu-avatar);
border-radius: 4px;
background-size: cover;
background-position: center;
}
.popover-menu-user-presence {
position: absolute;
/* Presence dot does not scale, because
the avatar itself does not scale. */
font-size: var(--length-user-status-circle-popover-menu);
line-height: 1;
right: -1px;
bottom: -1px;
background-color: var(--color-background-popover-menu);
border: solid 1px var(--color-background-popover-menu);
border-radius: 50%;
&.deactivated-user-icon {
font-size: 0.8em;
background-color: var(--color-background-popover-menu);
padding: 1px;
}
}
.popover-menu-user-info {
width: max-content;
align-self: center;
overflow: hidden;
}
.popover-menu-user-full-name {
/* 18px at 15px/1em */
font-size: 1.2em;
font-weight: 600;
/* 20px at 18px/1em */
line-height: 1.1111em;
color: var(--color-text-full-name);
overflow-wrap: anywhere;
.zulip-icon.zulip-icon-bot {
vertical-align: middle;
}
}
.popover-menu-user-type {
/* 14px at 15px/1em */
font-size: 0.9333em;
font-weight: 400;
/* 16px at 14px/1em */
line-height: 1.1428em;
color: var(--color-text-item);
text-overflow: ellipsis;
white-space: nowrap;
}
}
.user-card-popover-email-field {
& .user_popover_email {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
#popover-menu-copy-email,
.copy-custom-profile-field-link {
display: flex;
margin-left: auto;
&.hide_copy_icon {
display: none;
}
&:focus-visible {
outline: 1px solid var(--color-outline-focus) !important;
}
}
.personal-menu-header {
display: flex;
flex-flow: row nowrap;
gap: 7px;
text-align: left;
padding: 4px;
.avatar {
position: relative;
width: 64px;
height: 64px;
flex-shrink: 0;
}
.avatar-image {
width: 64px;
height: 64px;
border-radius: 4px;
background-size: cover;
background-position: center;
}
.status-circle {
position: absolute;
top: unset;
left: unset;
font-size: var(--length-user-status-circle);
line-height: 1;
right: -1px;
bottom: -1px;
background-color: var(--color-background-popover-menu);
border: solid 1px var(--color-background-popover-menu);
border-radius: 50%;
}
.text-area {
flex-grow: 1;
padding-top: 4px;
& p {
margin: 0 0 4px;
}
}
.full-name {
/* 18px at 15px/1em */
font-size: 1.2em;
font-weight: 600;
/* 20px at 18px/1em */
line-height: 1.1111em;
color: var(--color-text-full-name) !important;
overflow-wrap: anywhere;
}
.user-type {
/* 14px at 15px/1em */
font-size: 0.9333em;
font-weight: 400;
/* 16px at 14px/1em */
line-height: 1.1429em;
color: var(--color-text-item) !important;
}
}
.popover-menu {
margin: 0;
max-height: 85vh;
overflow-x: hidden;
user-select: none;
border-radius: 6px;
.simplebar-content {
/* Set the popover menu width equal to the width of the
longest menu item, thus letting the menu items control
the width of the menu. */
width: min-content;
/* Set `max-width` to the minimum of `97vw` and the value defined by
the `--popover-menu-max-width` custom property, which should be defined
as a local custom property in the scope of a particular popover where
we want apply a `max-width` limit.
When we don't define this local custom property, the fallback value of
`97vw` is considered and the `max-width` is then set to `min(97vw, 97vw)`
which is simply equivalent to `97vw`.
IMPORTANT: Setting `--popover-menu-max-width` in the `:root` scope
instead of the local scope, eliminates the fallback behavior and thus
prevents us from setting the max-width on a case-to-case basis. */
max-width: min(var(--popover-menu-max-width, 97vw), 97vw);
}
.popover-menu-label {
/* Keep menu items on a single line, unless forced to wrap
by a max-width on the popover. */
width: max-content;
flex: 1 0 0;
}
.text-item,
.link-item .popover-menu-link {
box-sizing: border-box;
display: flex;
flex-flow: row nowrap;
align-items: flex-start;
gap: 5px;
/* 3px at 15px/1em, 10px at 15px/1em */
padding: 0.2em 0.6666em;
/* 15px at 15px/1em */
font-size: 1em;
/* 16px at 15px/1em */
line-height: 1.0667em;
/* 26px at 16px/1em - this height was carried forward
despite the information density change in 15px > 16px,
so we calculate its height to the 16px em in use. */
min-height: 1.625em;
.popover-menu-icon {
/* 16px at 15px/1em */
font-size: 1.0667em;
/* 16px at 16px/1em */
width: 1em;
height: 1em;
text-align: center;
}
}
.text-item {
color: var(--color-text-item);
width: auto;
user-select: text;
}
.link-item {
outline: none;
.popover-menu-label,
.popover-menu-icon {
margin-top: 2px;
}
.popover-menu-icon {
color: var(--color-icon-purple);
}
.popover-menu-link {
color: var(--color-text-popover-menu) !important;
text-decoration: none;
flex-grow: 1;
&:hover {
background: var(--color-background-hover-popover-menu);
outline: none;
}
&:focus-visible {
border-radius: 4px;
/* Use an inset box-shadow rather than
`outline` with a negative `outline-offset`,
which at fractional browser zoom levels can
render at subpixel positions outside the item
and get clipped by the menu's `overflow-x:
hidden`. */
outline: none;
box-shadow: inset 0 0 0 1px var(--color-outline-focus);
background: var(--color-background-hover-popover-menu);
}
&:focus:not(:focus-visible) {
outline: none;
}
&:active {
background: var(--color-background-active-popover-menu);
}
}
}
.tab-picker {
&.popover-menu-tab-group {
margin: 2px 10px;
}
.tab-option-content:focus-visible {
border-radius: 4px;
/* Override the default focus style */
outline: 1px solid var(--color-outline-focus) !important;
outline-offset: -1px;
}
}
.status_emoji {
align-self: flex-start;
flex-shrink: 0;
/* 16px at 15px/1em */
width: 1.0667em;
height: 1.0667em;
}
.popover-menu-icon {
position: relative;
top: -1px;
&.zulip-icon-id-card {
/* Override the top value for the id card icon,
since it looks more visually centered */
top: 0;
}
}
.info-density-controls {
display: flex;
padding: 0.125em 0.625em;
gap: 0.5em;
.zulip-icon {
width: 0.933em;
height: 0.933em;
}
}
}
#help-menu-dropdown,
#gear-menu-dropdown,
#personal-menu-dropdown {
.simplebar-content {
min-width: var(--navbar-popover-menu-min-width);
}
}
#message-actions-menu-dropdown {
/* 350px at 15px/1em */
--popover-menu-max-width: 23.3333em;
.simplebar-content {
min-width: var(--message-actions-popover-min-width);
}
}
#stream-actions-menu-popover,
#topic-actions-menu-popover {
.simplebar-content {
min-width: var(--topic-actions-popover-min-width);
}
}
#user_card_popover {
/* 250px at 14px/1em */
--popover-menu-max-width: 17.8571em;
.simplebar-content {
min-width: var(--user-card-popover-min-width);
}
}
.user-group-info-popover {
.simplebar-content {
min-width: var(--user-group-info-popover-min-width);
}
}
#stream-card-popover {
.simplebar-content {
min-width: var(--stream-card-popover-min-width);
}
}
.color-picker-popover {
--popover-menu-max-width: calc(
var(--padding-color-swatch-list) * 2 + var(--size-color-swatch) * 6 +
var(--grid-gap-color-swatch) * 5
);
}
.personal-menu-clear-status {
display: flex;
align-items: center;
margin-left: auto;
color: hsl(0deg 0% 40%) !important;
border-radius: 4px;
opacity: 0.5;
&:focus {
/* Override bootstrap defaults */
outline: 1px solid var(--color-outline-focus) !important;
outline-offset: 0;
}
&:hover,
&:focus {
opacity: 0.9;
text-decoration: none;
}
}
.personal-menu-clear-status .personal-menu-clear-status-icon {
top: 0;
}
.personal-menu-status-wrapper {
display: flex;
align-items: flex-start;
gap: 5px;
}
.personal-menu-status-text {
color: var(--color-text-personal-menu-some-status);
}
.personal-menu-no-status-text {
color: var(--color-text-personal-menu-no-status);
}
#gear-menu-dropdown {
.org-info-container {
padding: 9px 0 5px;
border-bottom: solid 1px var(--color-border-popover-menu-separator);
.org-info {
display: flex;
justify-content: flex-start;
font-style: normal;
font-weight: 400;
/* 16px at 15px/1em */
line-height: 1.0667em;
letter-spacing: 0.28px;
&:focus-within {
background: var(--color-background-hover-popover-menu);
}
.popover-menu-link {
padding: 2px 10px;
flex-grow: 1;
text-decoration: none;
&:hover {
background: var(--color-background-hover-popover-menu);
outline: none;
}
&:focus-visible {
border-radius: 4px;
/* Override the default focus style */
outline: 1px solid var(--color-outline-focus) !important;
outline-offset: -1px;
}
&:active {
background: var(--color-background-active-popover-menu);
}
}
}
.org-url {
margin-bottom: 7px;
padding: 0 10px;
}
.org-name,
.org-plan .popover-menu-link {
color: var(--color-text-popover-menu);
}
.org-name {
/* 17px at 15px/1em */
font-size: 1.1333em;
font-weight: 600;
/* 22px at 17px/1em */
line-height: 1.2941em;
padding: 0 10px;
}
.org-upgrade {
/* 14px at 15px/1em */
font-size: 0.9333em;
/* 16px at 14px/1em */
line-height: 1.1428em;
}
.org-upgrade,
.org-url {
color: var(--color-gear-menu-lighter-text);
}
.org-upgrade a,
.org-version a {
color: var(--color-gear-menu-blue-text);
}
}
.theme-switcher {
/* Left and right margins are set to match the alignment with
other items in the menu. Other elements have space of 0.6666em
on both sides, but they have font size set to 1em and theme
switcher has font size set to 1.0666em. So, we need space of
0.6666/1.0666 em on each side. */
margin: 0 0.625em;
}
.info-density-controls {
/* Left and right paddings are set to match the alignment with
other items in the menu. */
padding: 0.4em 0.6666em 0.25em;
}
}
ul.popover-menu-list {
list-style: none;
margin: 0;
padding: 4px 0;
}
.popover-menu-separator {
margin: 4px 0;
border-bottom: solid 1px var(--color-border-popover-menu-separator);
}
.popover-menu-hotkey-hints {
display: flex;
gap: 4px;
margin-left: auto;
padding-left: 5px;
> .popover-menu-hotkey-hint {
box-sizing: border-box;
color: var(--color-popover-hotkey-hint);
text-align: center;
/* 14px at 15px/1em */
font-size: 0.9333em;
font-style: normal;
font-weight: 500;
/* 14px at 14px/1em */
line-height: 1em;
/* 20px at 14px/1em */
min-width: 1.4285em;
padding: 2px 4px;
border-radius: 3px;
border: 1px solid var(--color-border-popover-hotkey-hint);
}
}
.condensed-views-popover-menu {
.popover-menu-link:has(.label-and-unread-wrapper) {
align-items: center;
.popover-menu-icon {
margin-top: 1px;
}
.label-and-unread-wrapper {
/* Occupy the maximum width of the
parent flex container. */
flex: 1 0 max-content;
display: flex;
gap: 5px;
align-items: baseline;
}
.popover-menu-label {
margin-top: 0;
}
.unread_count {
margin: 0 0 0 6px;
border-color: var(--color-border-unread-counter-popover-menu);
width: max-content;
height: auto;
line-height: 1.2445em;
align-self: baseline;
}
}
}
#groups-to-add {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
#user-group-to-add {
flex: 1;
min-width: 0;
}
#topic-links-menu-popover {
color: var(--color-text-popover-menu) !important;
.popover-topic-links-list {
/* 3px at 15px/1em; with the separator's margin, this matches
the vertical rhythm of other popover menus. The larger bottom
padding stacks with the next section title's top padding to
leave a bigger gap between the two link sections. */
padding: 0.2em 0.6666em 0.6666em;
}
.topic-links-menu-title {
display: flex;
align-items: center;
gap: 5px;
/* 3px bottom at 15px/1em, matching other popover menus. */
padding: 0.6666em 0.6666em 0.2em;
font-weight: 600;
margin: 0;
.help_link_widget {
/* Override bootstrap defaults */
&:focus {
outline: none;
}
&:focus-visible {
/* Undo a.help_link_widget's 0.7 opacity so the outline isn't dimmed. */
opacity: 1;
outline: 2px solid var(--color-outline-focus);
outline-offset: 2px;
}
}
}
.topic-links-menu-title,
.popover-topic-links-list a {
width: fit-content;
max-width: 85vw;
white-space: nowrap;
}
.popover-topic-links-list a {
display: block;
text-overflow: ellipsis;
overflow: hidden;
/* External monitors sometimes cut off the edge of the message icon,
so add some extra margin. */
margin-right: 3px;
}
.popover-topic-links-list li + li {
margin-top: 0.5em;
}
ul {
margin: 0;
list-style: none;
}
}